aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/x11iraf/obm')
-rw-r--r--vendor/x11iraf/obm/Imakefile91
-rw-r--r--vendor/x11iraf/obm/OBM.revs350
-rw-r--r--vendor/x11iraf/obm/Obm.c1039
-rw-r--r--vendor/x11iraf/obm/Obm.h45
-rw-r--r--vendor/x11iraf/obm/ObmP.h508
-rw-r--r--vendor/x11iraf/obm/ObmW/Arrow.c465
-rw-r--r--vendor/x11iraf/obm/ObmW/Arrow.h70
-rw-r--r--vendor/x11iraf/obm/ObmW/Arrow.man680
-rw-r--r--vendor/x11iraf/obm/ObmW/ArrowP.h51
-rw-r--r--vendor/x11iraf/obm/ObmW/Board.c393
-rw-r--r--vendor/x11iraf/obm/ObmW/Board.h120
-rw-r--r--vendor/x11iraf/obm/ObmW/Board.man749
-rw-r--r--vendor/x11iraf/obm/ObmW/BoardP.h56
-rw-r--r--vendor/x11iraf/obm/ObmW/Button.c123
-rw-r--r--vendor/x11iraf/obm/ObmW/Button.h20
-rw-r--r--vendor/x11iraf/obm/ObmW/Button.man264
-rw-r--r--vendor/x11iraf/obm/ObmW/ButtonP.h41
-rw-r--r--vendor/x11iraf/obm/ObmW/CHANGES32
-rw-r--r--vendor/x11iraf/obm/ObmW/Common.c770
-rw-r--r--vendor/x11iraf/obm/ObmW/Common.c.ORIG852
-rw-r--r--vendor/x11iraf/obm/ObmW/Common.h108
-rw-r--r--vendor/x11iraf/obm/ObmW/Common.man1226
-rw-r--r--vendor/x11iraf/obm/ObmW/CommonP.h108
-rw-r--r--vendor/x11iraf/obm/ObmW/Container.c346
-rw-r--r--vendor/x11iraf/obm/ObmW/Container.h61
-rw-r--r--vendor/x11iraf/obm/ObmW/ContainerP.h71
-rw-r--r--vendor/x11iraf/obm/ObmW/Converters.h42
-rw-r--r--vendor/x11iraf/obm/ObmW/DrawIString.c45
-rw-r--r--vendor/x11iraf/obm/ObmW/DrawString.c45
-rw-r--r--vendor/x11iraf/obm/ObmW/DrawingArea.c193
-rw-r--r--vendor/x11iraf/obm/ObmW/DrawingArea.h35
-rw-r--r--vendor/x11iraf/obm/ObmW/DrawingAreaP.h45
-rwxr-xr-xvendor/x11iraf/obm/ObmW/FIXFWF6
-rw-r--r--vendor/x11iraf/obm/ObmW/FWFSED17
-rw-r--r--vendor/x11iraf/obm/ObmW/Frame.c654
-rw-r--r--vendor/x11iraf/obm/ObmW/Frame.h142
-rw-r--r--vendor/x11iraf/obm/ObmW/Frame.man1062
-rw-r--r--vendor/x11iraf/obm/ObmW/FrameP.h48
-rw-r--r--vendor/x11iraf/obm/ObmW/Gcs.c580
-rw-r--r--vendor/x11iraf/obm/ObmW/Gcs.h121
-rw-r--r--vendor/x11iraf/obm/ObmW/Group.c383
-rw-r--r--vendor/x11iraf/obm/ObmW/Group.h74
-rw-r--r--vendor/x11iraf/obm/ObmW/Group.man723
-rw-r--r--vendor/x11iraf/obm/ObmW/GroupP.h48
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c13283
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG11897
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h306
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h587
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.c1944
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.c.ORIG11897
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm.h306
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c12188
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG11897
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h247
-rw-r--r--vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h524
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermCmap.c765
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermCnv.c486
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermDebug.c23
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermGraphics.c1474
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermImaging.c3164
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermMapping.c2189
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermMarker.c4674
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermP.h598
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermUtil.c52
-rw-r--r--vendor/x11iraf/obm/ObmW/HTML-PSformat.c1544
-rw-r--r--vendor/x11iraf/obm/ObmW/HTML.c6177
-rw-r--r--vendor/x11iraf/obm/ObmW/HTML.h491
-rw-r--r--vendor/x11iraf/obm/ObmW/HTML.notes72
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLP.h246
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLamp.h141
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLformat.c6285
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLimages.c891
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLjot.c642
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLlists.c897
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLparse.c1373
-rw-r--r--vendor/x11iraf/obm/ObmW/HTMLwidgets.c4014
-rw-r--r--vendor/x11iraf/obm/ObmW/Icon.c224
-rw-r--r--vendor/x11iraf/obm/ObmW/Icon.h31
-rw-r--r--vendor/x11iraf/obm/ObmW/Icon.man392
-rw-r--r--vendor/x11iraf/obm/ObmW/IconP.h41
-rw-r--r--vendor/x11iraf/obm/ObmW/Imakefile241
-rw-r--r--vendor/x11iraf/obm/ObmW/Label.c345
-rw-r--r--vendor/x11iraf/obm/ObmW/Label.h130
-rw-r--r--vendor/x11iraf/obm/ObmW/Label.man732
-rw-r--r--vendor/x11iraf/obm/ObmW/LabelP.h89
-rw-r--r--vendor/x11iraf/obm/ObmW/Layout.c965
-rw-r--r--vendor/x11iraf/obm/ObmW/Layout.c.ORIG952
-rw-r--r--vendor/x11iraf/obm/ObmW/Layout.ex463
-rw-r--r--vendor/x11iraf/obm/ObmW/Layout.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/Layout.ps.gz.mipbin0 -> 17910 bytes
-rw-r--r--vendor/x11iraf/obm/ObmW/LayoutP.h213
-rw-r--r--vendor/x11iraf/obm/ObmW/ListTree.c2265
-rw-r--r--vendor/x11iraf/obm/ObmW/ListTree.h123
-rw-r--r--vendor/x11iraf/obm/ObmW/ListTreeP.h109
-rw-r--r--vendor/x11iraf/obm/ObmW/Makefile1192
-rw-r--r--vendor/x11iraf/obm/ObmW/MenuBar.c183
-rw-r--r--vendor/x11iraf/obm/ObmW/MenuBar.h15
-rw-r--r--vendor/x11iraf/obm/ObmW/MenuBar.man365
-rw-r--r--vendor/x11iraf/obm/ObmW/MenuBarP.h47
-rw-r--r--vendor/x11iraf/obm/ObmW/MultiList.c1793
-rw-r--r--vendor/x11iraf/obm/ObmW/MultiList.h279
-rw-r--r--vendor/x11iraf/obm/ObmW/MultiList.man207
-rw-r--r--vendor/x11iraf/obm/ObmW/MultiListP.h200
-rw-r--r--vendor/x11iraf/obm/ObmW/Notes191
-rw-r--r--vendor/x11iraf/obm/ObmW/README83
-rw-r--r--vendor/x11iraf/obm/ObmW/RadioGrp.c239
-rw-r--r--vendor/x11iraf/obm/ObmW/RadioGrp.h22
-rw-r--r--vendor/x11iraf/obm/ObmW/RadioGrp.man384
-rw-r--r--vendor/x11iraf/obm/ObmW/RadioGrpP.h43
-rw-r--r--vendor/x11iraf/obm/ObmW/RowCol.c346
-rw-r--r--vendor/x11iraf/obm/ObmW/RowCol.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/RowCol.man482
-rw-r--r--vendor/x11iraf/obm/ObmW/RowColP.h51
-rw-r--r--vendor/x11iraf/obm/ObmW/Scrollbar.c427
-rw-r--r--vendor/x11iraf/obm/ObmW/Scrollbar.h105
-rw-r--r--vendor/x11iraf/obm/ObmW/Scrollbar.man812
-rw-r--r--vendor/x11iraf/obm/ObmW/ScrollbarP.h58
-rw-r--r--vendor/x11iraf/obm/ObmW/Separator.c357
-rw-r--r--vendor/x11iraf/obm/ObmW/Separator.h98
-rw-r--r--vendor/x11iraf/obm/ObmW/SeparatorP.h62
-rw-r--r--vendor/x11iraf/obm/ObmW/Simple.c489
-rw-r--r--vendor/x11iraf/obm/ObmW/SimpleMenu.c1467
-rw-r--r--vendor/x11iraf/obm/ObmW/Slider2.c640
-rw-r--r--vendor/x11iraf/obm/ObmW/Slider2.h96
-rw-r--r--vendor/x11iraf/obm/ObmW/Slider2.man1068
-rw-r--r--vendor/x11iraf/obm/ObmW/Slider2P.h87
-rw-r--r--vendor/x11iraf/obm/ObmW/TabString.h26
-rw-r--r--vendor/x11iraf/obm/ObmW/Table.c4594
-rw-r--r--vendor/x11iraf/obm/ObmW/Table.h539
-rw-r--r--vendor/x11iraf/obm/ObmW/Table3d.c924
-rw-r--r--vendor/x11iraf/obm/ObmW/Table3d.h145
-rw-r--r--vendor/x11iraf/obm/ObmW/TableP.h166
-rw-r--r--vendor/x11iraf/obm/ObmW/TableUtil.c919
-rw-r--r--vendor/x11iraf/obm/ObmW/TableUtil.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/Tablist2Tabs.c35
-rw-r--r--vendor/x11iraf/obm/ObmW/Tabs.c2183
-rw-r--r--vendor/x11iraf/obm/ObmW/Tabs.h186
-rw-r--r--vendor/x11iraf/obm/ObmW/TabsP.h127
-rw-r--r--vendor/x11iraf/obm/ObmW/TextWidth.c39
-rw-r--r--vendor/x11iraf/obm/ObmW/Toggle.c290
-rw-r--r--vendor/x11iraf/obm/ObmW/Toggle.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/Toggle.man538
-rw-r--r--vendor/x11iraf/obm/ObmW/ToggleP.h50
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/3d.h145
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h33
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Arrow.h144
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h45
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h87
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h93
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h190
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h133
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h110
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h138
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Box.h74
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/BoxP.h90
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h35
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Clock.h87
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ClockP.h95
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Command.h104
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/CommandP.h121
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Container.h61
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h71
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Dialog.h82
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/DialogP.h76
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Form.h142
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/FormP.h126
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Frame.h163
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/FrameP.h95
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Grip.h83
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/GripP.h79
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Label.h98
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/LabelP.h111
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/List.h225
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ListP.h115
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Logo.h50
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/LogoP.h51
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h61
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h80
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h96
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h86
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Object.h37
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Paned.h229
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/PanedP.h172
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Panner.h104
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/PannerP.h100
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Porthole.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h63
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Repeater.h73
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h76
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Reports.h51
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h221
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h99
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h104
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h64
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Separator.h99
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Simple.h96
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h113
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h169
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h62
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Sme.h66
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h109
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h121
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h75
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h93
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/SmeP.h102
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h83
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/StripChart.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Table.h539
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Table3d.h145
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TableP.h166
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Template.h65
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h57
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Text.h314
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TextP.h224
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TextSink.h239
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h121
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h224
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h106
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Toggle.h170
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h108
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Tree.h120
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/TreeP.h112
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Viewport.h153
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h92
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/XawAll.h48
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/XawInit.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h95
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/color.h73
-rw-r--r--vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/_c90
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm8
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm16
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm41
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm48
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm42
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm36
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm46
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm38
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm39
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm26
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG26
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm26
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm26
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm27
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG27
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm27
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm27
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square0.pm24
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm24
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm24
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square1.pm24
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm25
-rw-r--r--vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm25
-rw-r--r--vendor/x11iraf/obm/ObmW/color.c309
-rw-r--r--vendor/x11iraf/obm/ObmW/cvtLong.c34
-rw-r--r--vendor/x11iraf/obm/ObmW/done.h16
-rw-r--r--vendor/x11iraf/obm/ObmW/iconutil.c297
-rw-r--r--vendor/x11iraf/obm/ObmW/iconutil.c.ORIG279
-rw-r--r--vendor/x11iraf/obm/ObmW/inkstore.h1844
-rw-r--r--vendor/x11iraf/obm/ObmW/laygram.y263
-rw-r--r--vendor/x11iraf/obm/ObmW/laylex.l126
-rw-r--r--vendor/x11iraf/obm/ObmW/laylex.l.ORIG96
-rw-r--r--vendor/x11iraf/obm/ObmW/scroll.c46
-rw-r--r--vendor/x11iraf/obm/ObmW/scroll.h96
-rw-r--r--vendor/x11iraf/obm/ObmW/stip4.bm4
-rw-r--r--vendor/x11iraf/obm/ObmW/strnchr.c17
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Separator.c357
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Separator.h99
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/SeparatorP.h60
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Simple.c489
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Simple.h96
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h113
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c1467
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h169
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/SimpleP.h62
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Table.c4529
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Table.h539
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Table3d.c924
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/Table3d.h145
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/TableP.h166
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/TableUtil.c918
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/TableUtil.h94
-rw-r--r--vendor/x11iraf/obm/ObmW/zz/XrawInit.h60
-rw-r--r--vendor/x11iraf/obm/README9
-rw-r--r--vendor/x11iraf/obm/Tcl/Imakefile224
-rw-r--r--vendor/x11iraf/obm/Tcl/Imakefile.ORIG163
-rw-r--r--vendor/x11iraf/obm/Tcl/Makefile1136
-rw-r--r--vendor/x11iraf/obm/Tcl/README346
-rw-r--r--vendor/x11iraf/obm/Tcl/README.OBM17
-rw-r--r--vendor/x11iraf/obm/Tcl/changes958
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/README6
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/dirent.h37
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/dirent2.h73
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/float.h30
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/getcwd.c63
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/limits.h34
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/opendir.c106
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/stdlib.h59
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/strerror.c484
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/string.h78
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/strstr.c84
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/strtod.c273
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/strtol.c99
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/strtoul.c199
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/tmpnam.c41
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/unistd.h83
-rw-r--r--vendor/x11iraf/obm/Tcl/compat/waitpid.c186
-rwxr-xr-xvendor/x11iraf/obm/Tcl/config.status64
-rwxr-xr-xvendor/x11iraf/obm/Tcl/configure1015
-rwxr-xr-xvendor/x11iraf/obm/Tcl/configure.in182
-rwxr-xr-xvendor/x11iraf/obm/Tcl/configure.info81
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/AddErrInfo.3143
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/AppInit.368
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Async.3172
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Backslash.358
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CallDel.382
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CmdCmplt.349
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Concat.364
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CrtCommand.3172
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CrtInterp.361
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CrtMathFnc.3114
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CrtPipelin.3114
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/CrtTrace.3125
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/DString.3141
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/DetachPids.379
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/EnterFile.398
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Eval.3119
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/ExprLong.3119
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/GetInt.394
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Hash.3222
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Interp.3132
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/LinkVar.3113
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/PrintDbl.358
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/RecordEval.360
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/RegExp.357
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/SetRecLmt.360
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/SetResult.3162
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/SetVar.3166
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/SplitList.3164
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/StrMatch.352
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/Tcl.n205
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/TildeSubst.385
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/TraceVar.3361
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/append.n45
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/array.n95
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/break.n41
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/case.n72
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/catch.n50
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/cd.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/close.n46
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/concat.n57
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/continue.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/eof.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/error.n71
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/eval.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/exec.n198
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/exit.n41
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/expr.n302
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/file.n146
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/flush.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/for.n57
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/foreach.n47
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/format.n233
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/gets.n61
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/glob.n92
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/global.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/history.n181
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/if.n58
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/incr.n44
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/info.n162
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/join.n42
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lappend.n48
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/library.n239
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lindex.n46
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/linsert.n45
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/list.n62
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/llength.n39
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lrange.n51
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lreplace.n55
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lsearch.n60
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/lsort.n72
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/man.macros182
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/open.n138
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/pid.n47
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/proc.n80
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/puts.n50
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/pwd.n38
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/read.n54
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/regexp.n160
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/regsub.n88
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/rename.n41
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/return.n104
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/scan.n149
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/seek.n64
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/set.n51
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/source.n47
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/split.n57
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/string.n131
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/switch.n122
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/tclsh.1103
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/tclvars.n156
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/tell.n43
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/time.n46
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/trace.n175
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/unknown.n55
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/unset.n47
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/uplevel.n79
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/upvar.n83
-rw-r--r--vendor/x11iraf/obm/Tcl/doc/while.n50
-rw-r--r--vendor/x11iraf/obm/Tcl/library/init.tcl259
-rw-r--r--vendor/x11iraf/obm/Tcl/library/parray.tcl43
-rw-r--r--vendor/x11iraf/obm/Tcl/library/tclIndex14
-rw-r--r--vendor/x11iraf/obm/Tcl/panic.c69
-rw-r--r--vendor/x11iraf/obm/Tcl/patchlevel.h11
-rw-r--r--vendor/x11iraf/obm/Tcl/porting.notes214
-rw-r--r--vendor/x11iraf/obm/Tcl/regexp.c1233
-rw-r--r--vendor/x11iraf/obm/Tcl/tcl.h649
-rw-r--r--vendor/x11iraf/obm/Tcl/tclAppInit.c95
-rw-r--r--vendor/x11iraf/obm/Tcl/tclAsync.c256
-rw-r--r--vendor/x11iraf/obm/Tcl/tclBasic.c1381
-rw-r--r--vendor/x11iraf/obm/Tcl/tclCkalloc.c607
-rw-r--r--vendor/x11iraf/obm/Tcl/tclCmdAH.c952
-rw-r--r--vendor/x11iraf/obm/Tcl/tclCmdIL.c1403
-rw-r--r--vendor/x11iraf/obm/Tcl/tclCmdMZ.c1730
-rw-r--r--vendor/x11iraf/obm/Tcl/tclEnv.c531
-rw-r--r--vendor/x11iraf/obm/Tcl/tclExpr.c2011
-rw-r--r--vendor/x11iraf/obm/Tcl/tclGet.c210
-rw-r--r--vendor/x11iraf/obm/Tcl/tclGlob.c455
-rw-r--r--vendor/x11iraf/obm/Tcl/tclHash.c937
-rw-r--r--vendor/x11iraf/obm/Tcl/tclHistory.c1109
-rw-r--r--vendor/x11iraf/obm/Tcl/tclInt.h947
-rw-r--r--vendor/x11iraf/obm/Tcl/tclLink.c361
-rw-r--r--vendor/x11iraf/obm/Tcl/tclMain.c296
-rw-r--r--vendor/x11iraf/obm/Tcl/tclMtherr.c89
-rw-r--r--vendor/x11iraf/obm/Tcl/tclParse.c1284
-rw-r--r--vendor/x11iraf/obm/Tcl/tclProc.c625
-rw-r--r--vendor/x11iraf/obm/Tcl/tclRegexp.h30
-rw-r--r--vendor/x11iraf/obm/Tcl/tclTest.c786
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUnix.h285
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUnixAZ.c1998
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUnixStr.c737
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUnixStr.c.OLD735
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUnixUtil.c1393
-rw-r--r--vendor/x11iraf/obm/Tcl/tclUtil.c1998
-rw-r--r--vendor/x11iraf/obm/Tcl/tclVar.c2363
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/README93
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/all10
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/append.test122
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/async.test145
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/case.test126
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/cd.test121
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/cmdinfo.test79
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/concat.test53
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/dcall.test54
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/defs94
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/dstring.test192
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/env.test122
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/error.test185
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/eval.test69
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/exec.test435
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/expr.test822
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/file.test326
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/for.test169
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/format.test379
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/glob.test153
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/history.test400
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/if.test162
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/incr.test86
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/info.test524
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/join.test52
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/lindex.test73
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/link.test148
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/linsert.test91
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/list.test87
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/llength.test49
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/lrange.test79
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/lreplace.test106
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/lsearch.test81
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/lsort.test136
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/misc.test84
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/open.test662
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/parse.test429
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/pid.test58
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/proc.test450
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/regexp.test324
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/rename.test78
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/scan.test276
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/set.test584
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/source.test95
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/split.test58
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/string.test333
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/switch.test184
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/trace.test914
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/unknown.test73
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/uplevel.test123
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/upvar.test303
-rw-r--r--vendor/x11iraf/obm/Tcl/tests/while.test113
-rw-r--r--vendor/x11iraf/obm/client.c253
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/TclQuickRef.html208
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/alphabetic.html39
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/athena.gifbin0 -> 1018 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/athena.html73
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/blueline.gifbin0 -> 75 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/book.p1.ps.gzbin0 -> 201061 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/clientclass.html75
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/coloredline.gifbin0 -> 5979 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/einstein.html5
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/example.html6
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/exampmap30
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/gmc.html402
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/gterm.gifbin0 -> 1689 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/gtermclass.html694
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/gui.html93
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/guiintro.html9
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowse.gifbin0 -> 4642 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/controlForm.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirName.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirSelect.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/headerText.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/imageButton.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/none.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/objView.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/panel.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/sectionBox.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/statusBox.html3
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/imtool.gifbin0 -> 13848 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/intro.gifbin0 -> 228 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/irafgui.gifbin0 -> 1102 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/llama.gifbin0 -> 21774 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/marker.gifbin0 -> 1297 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/newgui.html18
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/notyet.html5
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/notyet2.html5
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/otherwidgets.html10
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/params.gifbin0 -> 420 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/redline.gifbin0 -> 75 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/serverclass.html38
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/servercom.html375
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/softgui.gifbin0 -> 381 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/tcl.gifbin0 -> 186 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/tcl.html7
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/uiparameterclass.html107
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/widgetclass.html450
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/widgets.gifbin0 -> 378 bytes
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/widgets.html14
-rw-r--r--vendor/x11iraf/obm/docs/gui.doc/ximclient.html194
-rw-r--r--vendor/x11iraf/obm/docs/obm/Client.html75
-rw-r--r--vendor/x11iraf/obm/docs/obm/Gterm.html694
-rw-r--r--vendor/x11iraf/obm/docs/obm/Marker.html402
-rw-r--r--vendor/x11iraf/obm/docs/obm/Parameter.html107
-rw-r--r--vendor/x11iraf/obm/docs/obm/Server.html38
-rw-r--r--vendor/x11iraf/obm/docs/obm/Widget.html450
-rw-r--r--vendor/x11iraf/obm/docs/obm/alphabetic.html39
-rw-r--r--vendor/x11iraf/obm/docs/obm/index.html2515
-rw-r--r--vendor/x11iraf/obm/docs/obm/obm.html2515
-rw-r--r--vendor/x11iraf/obm/docs/obm/servercom.html375
-rw-r--r--vendor/x11iraf/obm/docs/tody.paper/todyd.html522
-rw-r--r--vendor/x11iraf/obm/docs/tody.paper/todyd1.gifbin0 -> 5681 bytes
-rw-r--r--vendor/x11iraf/obm/docs/tody.paper/todyd2.gifbin0 -> 6468 bytes
-rw-r--r--vendor/x11iraf/obm/docs/tody.paper/todyd3.gifbin0 -> 3535 bytes
-rw-r--r--vendor/x11iraf/obm/geom.c179
-rw-r--r--vendor/x11iraf/obm/gterm.c4407
-rw-r--r--vendor/x11iraf/obm/html.c1534
-rw-r--r--vendor/x11iraf/obm/listres/AllWidgets.c151
-rw-r--r--vendor/x11iraf/obm/listres/AllWidgets.h33
-rw-r--r--vendor/x11iraf/obm/listres/Imakefile20
-rw-r--r--vendor/x11iraf/obm/listres/Makefile.bak587
-rw-r--r--vendor/x11iraf/obm/listres/README29
-rw-r--r--vendor/x11iraf/obm/listres/listres.c302
-rw-r--r--vendor/x11iraf/obm/listres/listres.man54
-rw-r--r--vendor/x11iraf/obm/marker.c1869
-rw-r--r--vendor/x11iraf/obm/obmres.c2301
-rw-r--r--vendor/x11iraf/obm/obmres.dat538
-rw-r--r--vendor/x11iraf/obm/param.c401
-rw-r--r--vendor/x11iraf/obm/server.c3175
-rw-r--r--vendor/x11iraf/obm/widget.c5017
-rw-r--r--vendor/x11iraf/obm/widget.h47
580 files changed, 254904 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/Imakefile b/vendor/x11iraf/obm/Imakefile
new file mode 100644
index 00000000..3ee5a70f
--- /dev/null
+++ b/vendor/x11iraf/obm/Imakefile
@@ -0,0 +1,91 @@
+XCOMM Imakefile for the Object Manager Library.
+XCOMM
+XCOMM Doug Tody, National Optical Astronomy Observatories, IRAF project.
+XCOMM Sept93 Mar94
+
+X11IRAFDIR = ../
+#include <../X11IRAF.tmpl>
+
+#define IHaveSubdirs
+#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)'
+
+ CDEBUGFLAGS = -g
+ EXTRA_INCLUDES = -I. $(X11IRAF_INCLUDES)
+ EXTRA_DEFINES = -D_NO_PROTO
+
+
+#if HasLargeTmp | SystemV4
+ ARADD = ar ru
+#else
+ ARADD = ar rul
+#endif
+
+ LIBDIRS = Tcl ObmW
+ SUBDIRS = $(LIBDIRS)
+
+ HEADERS = Obm.h ObmP.h widget.h
+ SRCS = Obm.c client.c param.c server.c widget.c gterm.c marker.c \
+ html.c geom.c
+ OBJS = Obm.o client.o param.o server.o widget.o gterm.o marker.o \
+ html.o geom.o
+ ALL_OBJS = Tcl/[A-Za-z]*.o ObmW/[A-Za-z]*.o $(OBJS)
+ ALL_DONE = Tcl/DONE ObmW/DONE
+ RESOBJ = obmres.o
+
+all:: libobm.a
+
+World:
+ @echo "Building Release 1.2 of the IRAF Object Manager Library"
+ @date
+ @echo ""
+ $(MAKE) $(MFLAGS) Makefiles
+ $(MAKE) $(MFLAGS) clean
+ $(MAKE) $(MFLAGS) includes
+ $(MAKE) $(MFLAGS) depend
+ $(MAKE) $(MFLAGS) all
+ $(MAKE) $(MFLAGS) install
+ @date
+
+libobm.a: $(LIBDIRS) $(ALL_DONE) $(OBJS)
+ $(RM) $@
+ @(cd Tcl; $(MAKE) $(MFLAGS) all X11IRAFDIR=../../)
+ @(cd ObmW; $(MAKE) $(MFLAGS) all X11IRAFDIR=../../)
+ $(AR) $@ $(OBJS)
+ $(ARADD) $@ $(ALL_OBJS)
+ RanLibrary($@)
+
+NormalProgramTarget (obsres,obsres.o,NullParameter,NullParameter,NullParameter)
+
+ForceSubdirs($(SUBDIRS))
+DependSubdirs($(SUBDIRS))
+DependTarget()
+
+#if InstallLibraries
+install-lib:: libobm.a
+ @(set -x; $(RM) X11irafLibDir/libobm.a)
+ @(set -x; $(CP) -p libobm.a X11irafLibDir/libobm.a)
+
+install:: libobm.a
+ @(set -x; $(RM) X11irafLibDir/libobm.a)
+ @(set -x; $(CP) -p libobm.a X11irafLibDir/libobm.a)
+#endif
+
+
+LinkFileList(linklibs,libobm.a,X11irafLibDir,ObmDir)
+
+includes::
+ MakeDir(X11irafIncDir)
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/$$i; \
+ $(CP) -p ObmDir/$$i X11irafIncDir/$$i; \
+ done)
+
+#if InstallIncludes
+install::
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/$$i; \
+ done)
+ for i in $(HEADERS); do \
+ (set -x; $(CP) -p $$i $(DESTDIR)$(X11IRAFDIR)/include); \
+ done
+#endif
diff --git a/vendor/x11iraf/obm/OBM.revs b/vendor/x11iraf/obm/OBM.revs
new file mode 100644
index 00000000..4ed6b3cc
--- /dev/null
+++ b/vendor/x11iraf/obm/OBM.revs
@@ -0,0 +1,350 @@
+
+obm/marker.c:markerGetVertices() MF001
+ When called without specifying the number of points the for loop
+ wouldn't execute and so no points were being returned. Changed to
+ loop over the ngot value to return all points found by the widget
+ code. (7/14/98)
+
+obm/marker.c:markerGetVertices() MF002
+ Change the inner while loop to use *op to avoid infinite loop when
+ returning points. (7/14/98)
+
+obm/marker.c:markerGetRegion() MF003
+ Change the inner while loop to use *op to avoid infinite loop
+ causing getRegion to hang for polygon markers. (7/29/98)
+
+obm/ObmW/Gterm.c:GtRefreshMapping() MF004
+obm/ObmW/Gterm.c:refresh_source()
+obm/ObmW/Gterm.c:refresh_destination()
+obm/ObmW/Gterm.c:GetCachedXImage() +
+obm/ObmW/Gterm.c:DestroyCachedXImage() +
+obm/ObmW/Gterm.c:NewCachedXImage() +
+ Merged in image cache code from SAORD for speeding up the magnifier
+ marker. This doesn't appear to have any major impact on the memory
+ requirements, but still it can be disabled via a #define CacheXImage
+ at the top of the file. Corresponds to SAOMOD_CACHE (7/31/98)
+
+obm/ObmW/Gterm.c:GtExtractPixmap() MF005
+ Added a missing GtermWidget arg to GtDestroyRaster call (7/31/98)
+
+obm/ObmW/Gterm.c:GtExtractPixmap() MF006
+obm/ObmW/Gterm.c:GtInsertPixmap()
+ Added a missing RasterDepth arg to GtCreateRaster call (7/31/98)
+
+obm/ObmW/Gterm.c:GtCopyRaster() MF007
+ Changed declaration for sv_mp, p_mp from Mapping to 'struct mapping'
+ so the agree with argument declaration type. Pre- viously routines
+ were being called with struct mapping ** instead of struct mapping *
+ (7/31/98)
+
+obm/ObmW/Gterm.c:Destroy() MF008
+ Changed arg to GtRasterInit from 'gw' to 'w' so types agree.
+ (7/31/98)
+
+obm/ObmW/Gterm.c:gm_refocus() MF009
+ Added an event type. This was the SAOMOD_PURIFY change, seemed
+ harmless.
+
+obm/ObmW/Gterm.c:M_set() MF010
+ Removed XtArgVal cast of arg 2 for GmSetAttribute to agree with
+ function declaration.
+
+obm/ObmW/Gterm.c:GtSetMapping() MF011
+ Not sure I should have changed this, but Eric claims it fixes a bug
+ although he can't remember the details. SAOMOD_BUG.
+
+obm/ObmW/Gterm.c:Initialize() MF012
+ Added an initialization for gterm.n_wmWindows. According to Eric
+ this was done to fix a segvio that was never completely understood.
+ Even though the procedure doesn't initialize the variable it appears
+ to be properly set the first time the window gets a focus request so
+ the problem must be elsewhere, this seemed harmless so it was added
+ anyway. SAOMOD_MAYBE_FOCUS
+
+obm/ObmW/Gterm.c:GmSetVertices() MF013
+ Changed the test to be an inequality rather than a greater than.
+ What would happen is that if a call was made with fewer points than
+ currently in the struct the gm->npoints value would be wrong. (e.g.
+ polygon markers are initialized with 4 points in a unit box, creating
+ a triangle marker causes a getVertices OBM call to return the wrong
+ number of points).
+
+obm/ObmW/Gterm.c:gm_select() MF014
+obm/ObmW/Gterm.c:gm_circ_init() MF015
+obm/ObmW/Gterm.c:gm_circ_updatePolygon() MF015
+obm/ObmW/Gterm.c:gm_elip_init() MF015
+obm/ObmW/Gterm.c:gm_elip_updatePolygon() MF015
+ Two connected bugs: The symptom was that when changing a marker
+ back and forth between shapes, e.g. a rect and a circle, the marker
+ would lose the ability to determine focus when the mouse was moved
+ into it when going from a rect->circle->rect. The first bug was
+ that the value of ptop in gm_select() was pointing out of bounds
+ for the point array. Initially this would be a zero point and the
+ algorithm would coincidentally trap this and exit as expected, but
+ when you go from a circle back to a rect the point array still con-
+ tains the circle vertices so the algorithm was checking an invalid
+ line segment and finding a second crossing point and thus failing.
+ When ptop was set to point at the last element correctly the circle
+ marker suddenly lost focus: this was because the polygon points
+ computed for a circle is already closed, the updatePolygon and init
+ routines were defining an extra point to close the poly which wasn't
+ needed, in gm_select this produced another erroneous crossing
+ causing the selection to fail. Modified to use only GM_NPTSCIRCLE
+ points.
+
+obm/widget.c:widgetGet() MF016
+obm/widget.c:widgetGetFontName() + MF016
+ To help with finding portable font settings I added some new code
+ to return an XLFD font string allowing the user to now do a "get
+ font" on a widget and return a readable font string.
+
+obm/ObmW/Gterm.c:gm_elip_updatePolygon() MF017
+ The ellipse vertices were being calculated with too few points
+ causing a "stray" line segment when drawing a rotated ellipse.
+ Connected to MF015
+
+obm/ObmW/Gterm.c:GmSetVertices() MF018
+ When a polygon marker is created the pgon_points array is init-
+ ialized to a unit box, this array isn't updated with a setVertices
+ call later so when the marker visibility is turned on the marker
+ still appears as the unit box.
+
+obm/ObmW/Gterm.c: MF019
+ Big change involving the rotation of markers: Previously when a
+ marker was rotated by grabbing a knot the rotation angle would
+ be the angle of the knot being used. This means that a square
+ marker with an initial zero rotation would suddenly have a rot-
+ angle of 45 if the user grabbed and then released the upper-right
+ corner, but the marker is still drawn at an angle that looks close
+ to zero. This could be corrected once the button is released but
+ not without adding another procedure (or by muddling up the markpos
+ procedure) and requiring it to be called on a BtnUp event. Rot-
+ ations were also defined in a clockwise direction and angles had
+ to be specified in radians.
+ The changes made are that 1) angles are now read/written by
+ the GUI in (a more natural) degrees, angles are converted inter-
+ nally for computation. 2) Rotation is now defined such that zero
+ degrees is to the right, 90 degrees is up. 3) Marker rotation is
+ done using the model that the user is dragging the zero axis about
+ the marker (x,y) pos. When the rotation is begun the marker rotates
+ so that the zero axis is pointing at the knot chosen, thereafter the
+ is set as before. This means that w/ a square marker selecting the
+ upper-right knot and releasing would leave the marker drawn at what
+ looks like the correct 45 degrees.
+
+obm/ObmW/Gterm.h: MF020
+obm/ObmW/GtermP.h: MF020
+obm/ObmW/Gterm.c:gm_rotate_indicator() + MF020
+ Added a new 'rotIndicator' marker attribute as an option to draw
+ a little clock-hand indicator showing the previous and current
+ rotation angle. Added a gm_rotate_indicator() procedure.
+
+obm/ObmW/HTML.c: MF021
+ Changed the declaration of the in_anchor_cursor so it's no longer
+ static. Previously repeated invocations of a GUI would cause the
+ cursor to not change shapes when entering an anchor because it was
+ not being initialized properly.
+
+obm/ObmW/Gterm.c:GmSetAttribute() MF022
+obm/ObmW/Gterm.c:GmGetAttribute()
+ Changed the rotangle input to automatically convert from degrees
+ to radians, which is what's used internally. Previously setting
+ any angle would be interpreted initially to be in radians and the
+ resulting display would be wrong. Similarly the output angle was
+ converted from radians to degrees for readability.
+
+obm/ObmW/HTML.c:HTMLAnchorToId() MF023
+ Modified so that internal links can be of the form "name=foo" or
+ "name=#foo".
+
+obm/html.c:htmlIdToPosition() MF024
+obm/html.c:htmlAnchorToPosition()
+obm/html.c:htmlGetHRefs()
+obm/html.c:htmlGetImageSrcs()
+obm/html.c:htmlGetLinks()
+obm/html.c:htmlSearchText()
+ The Tcl_SetVar calls had arguments reversed preventing the result
+ from being returned correctly.
+
+obm/Imakefile MF025
+ Typo was preventing libobm.a from being updated correctly when not
+ building form pure source.
+
+obm/ObmW/HTML.c:setScrollbar() MF026
+ Changed the size of the 'topPosition' arg from Position to int.
+ Position is typedef'd as short and for very long HTML docs the
+ position exceeds the 32K short and you get a negative value which
+ incorrectly positions the scrollbar.
+
+obm/ObmW/Gterm.c:Gm[SG]etVertices() MF027
+ The set/getVertices and getRegions functions were changed so that
+ in the case of a polygon the setVertices call will close the polygon
+ regardless of whether the user has alread done so. To be consitent
+ the 'get' routines will not return the closing point, i.e. N points
+ in and N points out.
+
+obm/ObmW/Gterm.c:gm_circ_updatePolygon() MF028
+ The points array for a circle was being fully populated so when
+ searching through all points you would come across (0,0) values
+ while was throwing off the gm_select routine. Also added an abs()
+ call to the edge detection for safe measure.
+
+obm/ObmW/Gterm.c:Initialize() MF029
+ Added a XSetGraphicsExposures() call to the exposeGC to disable
+ expose events. It was noticed in the CTIO guider project that
+ there was a memory leak in ximtool. The leak was traced to an
+ XCopyArea call in refresh_destination. This was noticed because
+ the application is displaying many thousands of images in an anim-
+ ation sequence. With each refresh an Expose/NoExpose event was being
+ generated which was building up in the event queue (which was never
+ read) at a cost of ~100 bytes each. Adding the call disables the
+ events which are normally on by default.
+
+obm/ObmW/Gterm.c:Initialize() MF030
+ Commented out the XRecolorCursor calls for the idle and busy cursors.
+ There was a problem with xgterm blowing itself away when doing many
+ gflushes in a short time span. This was traced to a buildup of
+ BadCursor errors that eventually hit the limit in xerror() and the
+ program died. It's not clear why this is happening but the benefits
+ of these calls were minimal ....
+
+obm/html.c:htmlSetSelection() MF031
+obm/html.c:htmlSearchText()
+obm/ObmW/HTML.c:HTMLSearchText()
+ Minor bug fixes to the HTML text search code. The searchText routine
+ now will incrementally find the next occurrence of the pattern in the
+ text and wrap around the page if necessary. The start location
+ automatically resets if the pattern changes.
+
+obm/ObmW/Gterm.c MF032
+ Added a return to the blink_cursor() procedure so that when not in
+ ginmode no new timer would be started. This was necessary to avoid
+ having multiple timers running which would apparently make the cursor
+ blink faster and gradually put an increasing load on the process.
+
+obm/ObmP.h MF033
+ Added definitions for the MenuBar widget which was defined but not
+ recognized as an object for receiving messages.
+
+obm/ObmP.h MF034
+obm/obmres.c
+obm/obmres.dat
+obm/widget.c
+obm/ObmW/Tabs.c +
+obm/ObmW/Tabs.h +
+obm/ObmW/TabsP.h +
+obm/ObmW/Gcs.c +
+obm/ObmW/Gcs.h +
+obm/ObmW/Imakefile
+obm/listres/AllWidgets.c
+guidemos/tabs.gui
+ Added a new Tabs widget which creates index tabs on widgets similar to
+ what's seen on many PC configuration panels. Basically each child
+ widget would be something like a Layout/Group or Frame and as each index
+ tab is selected that child is brought to the top and displayed. Each
+ child defines a new 'tabLabel' resource string to give the label to be
+ written to the Tab for that widget. See tabs.gui for an example in the
+ x11iraf$guidemo directory.
+
+obm/ObmW/Gterm.c MF035
+ Added an initialize_mapping for the sv_mp struct in various routines.
+ This was first noticed as a failure in the GtCopyRaster routine which
+ would fail with a "cannot malloc" error because the sv_mp->datalen and
+ sv_mp->update elemets contained garbage. Once the struct was saved
+ GtCopyRaster would subsequently call get_pixel_mapping() which then
+ did the fatal alloc. It was only in GtCopyRaster that the update flag
+ was explicitly set where this would be a problem. (2/29/00)
+
+obm/geom.c MF036
+ Commented out a call to XGetVisualInfo. The results weren't being used
+ and the pointer returned was never freed causing a small memory leak.
+ (3/2/00)
+
+obm/server.c MF037
+obm/ObmW/icon.c
+ Added an XtFree() to free the resource list. Another memory leak.
+ (3/2/00)
+
+obm/ObmW/Label.c MF038
+ Added an XDestroyRegion to free space allocated in the expose call.
+ (3/2/00)
+
+xaw3d/Text.c MF039
+xaw3d/TextTr.c
+ Modified the code to make _XawDefaultTextTranslations a static array
+ rather than one allocated and never freed. Required changes to the
+ array declaration in TextTr.c, and textClassRec definition and
+ ClassInitialize() procedure. (3/2/00)
+
+obm/ObmW/Gterm.c MF040
+ Added an XFree for the visual info struct in get_colormap. (3/2/00)
+
+obm/ObmW/Gterm.c MF041
+ Added a check for raster=0 when setting the logical resolution. This
+ is the fix for the cursor positioning bug where the frame buffer is
+ larger than the screen image. (3/2/00)
+
+obm/Tcl/Imakefile MF042
+ Removed some warning flags requested for Linux. (3/3/00)
+
+obm/ObmW/Gterm.c
+ Removed the comment chars for XRecolorCursor first done for MF030.
+ While these do trigger BadCursor errors these will now be ignored by
+ the xgterm error handler. (4/7/00)
+
+obm/server.c
+ Changed a malloc to a calloc call for the timer struct. Also deleted
+ an XtFree for the callback in serverTimedProc() which would corrupt
+ memory if the timer callback were later deleted. (7/28/00)
+
+obm/ObmP.h
+obm/Obm.c
+ Added support for a new environent variable OBMOBJECTS which will help
+ restrict the messages printed during debugging. For example, it can be
+ set as
+
+ setenv OBMOBJECTS "client imagewin"
+
+ to have OBMDEBUG print only messages for the 'client' and 'imagewin'
+ objects. (8/3/00)
+
+obm/widget.c
+ Added a new 'setTop' command for the Tabs widget that can be used to
+ raise a particular tab from within the GUI. (8/29/00)
+
+obm/server.c
+ Commented out an XtFree() on a static array ('table') (03/05/01)
+
+obm/ObmP.h MF043
+obm/obmres.c
+obm/obmres.dat
+obm/widget.c
+obm/ObmW/ListTree.c +
+obm/ObmW/ListTree.h +
+obm/ObmW/ListTree.h +
+obm/ObmW/Imakefile
+obm/listres/AllWidgets.c
+ Added a new ListTree widget which creates an indented list of items
+ in a user defined hierarchy. Selecting an item "opens" it to reveal
+ lower level lists. The selection callback returns the selected item
+ label, it's level, and a full path of all parent items. The widget
+ can used for things like directory browsers, or organizing documentation
+ into sections, subsections, etc. (8/26/02)
+
+
+obm/ObmP.h
+obm/obmres.c
+obm/obmres.dat
+obm/widget.c
+obm/OBMW/Table.c
+obm/OBMW/Table.h
+obm/OBMW/color.c
+obm/OBMW/TableP.h
+obm/OBMW/Table3d.c
+obm/OBMW/Table3d.h
+obm/OBMW/TableUtil.c
+obm/OBMW/TableUtil.h
+ Added a new Table widget and support code. The Table widget supports a
+ grid layout of data items with col/row selection and cell editing. It
+ is a bit primitive so additional code was added to improve functionality.
+ (09/10/02)
diff --git a/vendor/x11iraf/obm/Obm.c b/vendor/x11iraf/obm/Obm.c
new file mode 100644
index 00000000..d9f5e7c5
--- /dev/null
+++ b/vendor/x11iraf/obm/Obm.c
@@ -0,0 +1,1039 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#define Obm_Main
+#include <ObmP.h>
+
+/*
+ * OBM.C -- Object manager for the graphics subsystem.
+ *
+ * obm = ObmOpen (app_context, argc, argv)
+ * ObmClose (obm)
+ * ObmInitialize (obm)
+ * ObmActivate (obm)
+ * ObmDeactivate (obm, unmap)
+ * status = ObmActivated (obm)
+ * status = ObmStatus (obm, app_name, app_class)
+ * status = ObmDeliverMsg (obm, object, message)
+ * st = ObmDeliverMsgFromFile (obm, object, fname)
+ * interp = ObmGetInterp (obm)
+ *
+ * Callbacks:
+ *
+ * id = ObmAddCallback (obm, callback_type, fcn, client_data)
+ * ObmRemoveCallback (obm, id)
+ *
+ * connect_callback (client_data, display, toplevel, state)
+ * activate_callback (client_data, toplevel)
+ * deactivate_callback (client_data, toplevel)
+ * setGterm_callback (client_data, gterm_widget)
+ * clientOutput_callback (client_data, tcl, key, string)
+ *
+ * The callback type bitflags are defined in <Obm.h> as OBMCB_connect,
+ * OBMCB_activate and so on.
+ *
+ * An xgterm graphics user interface (UI) consists of one or more windows
+ * containing an arbitrary hierarchy of widgets. These widgets and their
+ * runtime actions are defined by an interpreted text program downloaded
+ * by the client application, which does not itself deal directly with
+ * the window user interface.
+ *
+ * The object manager provides a higher level of abstraction for dealing
+ * with widgets and other UI objects. The main function of the object
+ * manager is to deliver messages to UI objects. Each instance of a widget
+ * is an object in the UI. The UI contains other types of objects however,
+ * including the client object (client application), the server object
+ * (the object manager itself), and the application specific UI parameters,
+ * each of which is an object with a callback list of UI procedures to be
+ * called when the parameter value changes. All of these UI objects can
+ * receive messages and take actions as a result. Messages may come from the
+ * client application, or as a result of actions executed by the interpreted
+ * UI code in response to graphics events.
+ *
+ * Object classes:
+ *
+ * Client the client application
+ * Server the object manager itself
+ * Parameter UI control parameter
+ * Gterm widget graphics terminal widget
+ * Vterm widget vt100 terminal widget
+ * various Xt and Athena widgets box, shell, label, text, list, etc.
+ *
+ * In addition to delivering messages to objects (ObmDeliverMsg), one of the
+ * functions of the object manager is to manage the hierarchy of widgets
+ * comprising the UI. ObmOpen opens the object manager. ObmInitialize
+ * initializes the object manager, destroying any existing widget hierarchy.
+ * ObmActivate readies the UI to receive graphics output and graphics input
+ * events, creating a default UI if none has been downloaded by the client.
+ *
+ * Sophisticated graphics applications will download a UI during initialization
+ * to define a custom graphics user interface. This is done by sending a
+ * message to the object manager. Naive applications assume a simple graphics
+ * terminal and do not download a UI; in this case, a default UI is created
+ * for the application when the UI is enabled with ObmEnable. The default
+ * UI is a single top level shell window containing a single gterm (graphics
+ * terminal) widget.
+ *
+ * reset-server
+ * appInitialize appname classname {resources}
+ * createObjects
+ * (UI specific code)
+ * activate
+ *
+ * A UI specification consists of a sequence of commands to be executed by
+ * the server object. This is downloaded by the client as a message for the
+ * server object. The commands should include "reset-server" (this must be
+ * the first executable command), "appInitialize" (defines the UI objects and
+ * their resources), and "createObjects" (creates the objects and the widget
+ * tree), followed by any UI specific commands to define and register UI
+ * callback procedures. Finally, "activate" is executed to activate the new
+ * user interface.
+ */
+
+#define MAXOBJ 512
+static void obm_call_activate_callbacks();
+
+
+/* ObmOpen -- Open the object manager.
+ */
+ObmContext
+ObmOpen (app_context, argc, argv)
+XtAppContext app_context;
+int argc;
+char *argv[];
+{
+ register ObmContext obm;
+ register ObjClassRec classrec;
+ register int i;
+ char *s;
+
+ /* Initialize object manager global context. */
+ obm = (ObmContext) XtCalloc (1, sizeof (struct obmContext));
+ strcpy (obm->appname, "gterm-iraf");
+ strcpy (obm->appclass, "Xgterm");
+ obm->app_context = app_context;
+ obm->argc = argc;
+ obm->argv = argv;
+ obm->debug = ((s = getenv("OBMDEBUG")) != NULL);
+ if (s && (i = atoi(s)))
+ obm->debug = i;
+ if (s = getenv("OBMOBJECTS")) {
+ obm->debug_objs = (char *) XtCalloc (1, strlen(s)+1);
+ strcpy (obm->debug_objs, s);
+ } else
+ obm->debug_objs = (char *)NULL;
+
+
+ /* Initialize object classes. */
+ for (i=0; i < XtNumber(UiObjects); i++) {
+ classrec = &UiObjects[i];
+ if (classrec->ClassInit)
+ (*(classrec->ClassInit)) (obm, classrec);
+ }
+
+ /* Create new server and client objects. */
+ ObmInitialize (obm);
+
+ return (global_obm_handle = obm);
+}
+
+
+/* ObmClose -- Close the object manager.
+ */
+void
+ObmClose (obm)
+ObmContext obm;
+{
+ register ObjClassRec classrec;
+ register int i;
+
+ /* Get rid of any current UI. */
+ ObmInitialize (obm);
+ while (obm->head)
+ obmDestroyObject (obm, obm->head);
+
+ /* Delete any callback descriptors. */
+ while (obm->callback_list)
+ obmRemoveCallback (&obm->callback_list, obm->callback_list);
+
+ /* Free any resources associated with the class descriptors. */
+ for (i=0; i < XtNumber(UiObjects); i++) {
+ classrec = &UiObjects[i];
+ (*(classrec->ClassDestroy)) (obm, classrec);
+ }
+
+ if (obm->debug_objs)
+ XtFree ((char *)obm->debug_objs);
+ XtFree ((char *)obm);
+}
+
+
+/* ObmInitialize -- Initialize the object manager, i.e., destroy any existing
+ * user interface.
+ */
+void
+ObmInitialize (obm)
+register ObmContext obm;
+{
+ register ObmObject obj, nextobj;
+ register ObmCallback cb;
+ register MenuItem ip;
+ ObjList lp, lp_next;
+ Menu mp;
+ int i;
+
+ /* Destroy the UI object tree. We need to be a little careful how
+ * we do this as objects like to destroy child objects, execute
+ * destroy callbacks, unmap windows, perform geometry requests, etc.
+ * during destruction. The widget class code can most efficiently
+ * destroy the widget tree if destroy the toplevel widget first,
+ * so we unmap the GUI and destroy the toplevel widget-class object
+ * first. Then we destroy whatever else is left.
+ */
+ obm->being_destroyed++;
+ if (obj = obmFindObject (obm, "toplevel")) {
+ obmUndisplay (obm, obj);
+ obmDestroyObject (obm, obj);
+ }
+ while (obm->head)
+ obmDestroyObject (obm, obm->head);
+
+ /* Free any cached pixmaps. */
+ for (lp = obm->pixmap_cache; lp; lp = lp_next) {
+ lp_next = lp->next;
+ freeIcon (obm, (Icon *) lp->ptr);
+ XtFree ((char *)lp);
+ }
+ obm->pixmap_cache = NULL;
+
+ /* Free any cached cursors. */
+ for (lp = obm->cursor_cache; lp; lp = lp_next) {
+ lp_next = lp->next;
+ XFreeCursor (obm->display, (Cursor)lp->ptr);
+ XtFree ((char *)lp);
+ }
+ obm->cursor_cache = NULL;
+
+ /* Free any menu lists. */
+ for (lp = obm->menu_list; lp; lp = lp_next) {
+ lp_next = lp->next;
+ freeMenu ((MenuPtr) lp->ptr);
+ }
+ obm->menu_list = NULL;
+
+ /* Close the application specific display connection. */
+ if (obm->display) {
+ /* Call the client's display connection callbacks if any to
+ * inform the client that we are about to close the display.
+ */
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & OBMCB_connect) && cb->u.fcn)
+ (*cb->u.fcn) (cb->client_data, obm->display, NULL, 0);
+
+ XFlush (obm->display);
+ XtCloseDisplay (obm->display);
+ obm->display = NULL;
+ }
+
+ /* Reinitialize the global context. */
+ memset ((void *)obm->objindex, 0, sizeof(obm->objindex));
+ strcpy (obm->appname, "gterm-iraf");
+ strcpy (obm->appclass, "Xgterm");
+ obm->head = obm->tail = NULL;
+ obm->being_destroyed = 0;
+ obm->toplevel = NULL;
+ obm->specified = 0;
+ obm->activated = 0;
+ obm->mapped = 0;
+
+ /* Free any callbacks that don't have the OBMCB_preserve flag set. */
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if (!(cb->callback_type & OBMCB_preserve))
+ obmRemoveCallback (&obm->callback_list, cb);
+
+ /* Create new server and client objects. */
+ obmNewObject (obm, "server", "Server", NULL, NULL, 0);
+ obmNewObject (obm, "client", "Client", NULL, NULL, 0);
+}
+
+
+/* ObmActivate -- Activate the UI, i.e., ensure that it is active and in
+ * such a state as to be ready for client i/o.
+ */
+void
+ObmActivate (obm)
+register ObmContext obm;
+{
+ register ObmObject obj;
+ char defaultUI[SZ_MESSAGE];
+
+ /* UI has already been activated? */
+ if (obm->activated) {
+ if (!obm->mapped) {
+ if (obj = obmFindObject (obm, "toplevel"))
+ obmDisplay (obm, obj);
+ obm->mapped++;
+
+ /* Call activate callbacks after UI has been realized. */
+ obm_call_activate_callbacks (obm, 1);
+ }
+ return;
+ }
+
+ if (!obm->specified) {
+ /* Construct a UI specification for the default UI. */
+ sprintf (defaultUI, "%s %s %s {%s.objects: %s%s%s%s%s}; %s; %s\n",
+ "appInitialize", obm->appname, obm->appclass,
+ obm->appclass, "toplevel Gterm gterm\n",
+ ".geometry: 640x480\n",
+ "*gterm.warpCursor: True\n",
+ "*gterm.raiseWindow: True\n",
+ "*gterm.deiconifyWindow: True\n",
+ "createObjects",
+ "send gterm setGterm\n");
+
+ /* Call the server to configure the default UI. */
+ ObmDeliverMsg (obm, "server", defaultUI);
+ }
+
+ /* Realize the toplevel widgets. */
+ if (obj = obmFindObject (obm, "toplevel"))
+ obmDisplay (obm, obj);
+
+ obm->activated++;
+ obm->mapped++;
+
+ XFlush (obm->display);
+ obm_call_activate_callbacks (obm, 1);
+}
+
+
+/* ObmDeactivate -- Deactivate the UI. Optionally unmap the UI widget
+ * tree and execute any deactivate callback registered by the Obm client.
+ * Deactivation does not affect the state of the UI, i.e. a reactivate
+ * will cause the UI to resume execution in the same state at which it
+ * was deactivated.
+ */
+void
+ObmDeactivate (obm, unmap)
+register ObmContext obm;
+Boolean unmap;
+{
+ register ObmObject obj;
+ register ObmCallback cb;
+ ObmFunc deactivate;
+
+ /* The Obm "activated" flag is not affected by deactivation.
+ * Deactivation merely means that control has temporarily been
+ * returned to the caller. If the activate flag has not been set
+ * that means we do not yet have a UI to deactivate.
+ */
+ if (!obm->activated)
+ return;
+
+ /* Call any client deactivate callbacks before unrealizing the UI. */
+ obm_call_activate_callbacks (obm, 0);
+
+ if (unmap) {
+ if (obj = obmFindObject (obm, "toplevel"))
+ obmUndisplay (obm, obj);
+ obm->mapped = 0;
+ }
+
+ XFlush (obm->display);
+}
+
+
+/* obm_call_activate_callbacks -- Internal procedure to search the callback
+ * lists and call any activate/deactivate callbacks.
+ */
+static void
+obm_call_activate_callbacks (obm, state)
+register ObmContext obm;
+int state;
+{
+ register ObmCallback cb;
+ register int type;
+
+ /* Call any client activate callbacks. */
+ type = state ? OBMCB_activate : OBMCB_deactivate;
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & type) && cb->u.fcn)
+ (*cb->u.fcn) (cb->client_data, obm->toplevel, state);
+
+ /* Call any GUI activate callbacks. */
+ type = state ? OBMUI_activate : OBMUI_deactivate;
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if (cb->callback_type & type) {
+ char message[SZ_NUMBER];
+ int status;
+
+ sprintf (message, "%d", state);
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ message, " ",
+ NULL);
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in activate: %s\n",
+ obm->tcl->errorLine,
+ errstr ? errstr : obm->tcl->result);
+ }
+ }
+}
+
+
+/* ObmActivated -- Test whether the GUI is activated, i.e., both defined
+ * and mapped.
+ */
+ObmActivated (obm)
+register ObmContext obm;
+{
+ return (obm->activated && obm->mapped);
+}
+
+
+/* ObmStatus -- Get the Object Manager status.
+ */
+ObmStatus (obm, app_name, app_class)
+register ObmContext obm;
+char *app_name;
+char *app_class;
+{
+ if (obm->specified) {
+ if (app_name)
+ strcpy (app_name, obm->appname);
+ if (app_class)
+ strcpy (app_class, obm->appclass);
+
+ if (obm->activated)
+ return (obm->mapped ? OBM_ACTIVE : OBM_IDLE);
+ }
+
+ return (OBM_INITIALIZED);
+}
+
+
+/* ObmGetInterp -- Get the main OBM (server object) interpreter. This can
+ * be used, e.g., by the calling program to extend the Tcl environment seen
+ * by the GUI code.
+ */
+XtPointer
+ObmGetInterp (obm)
+register ObmContext obm;
+{
+ return ((XtPointer)obm->tcl);
+}
+
+
+/* ObmDeliverMsg -- Deliver a message to a UI object.
+ */
+ObmDeliverMsg (obm, object, message)
+register ObmContext obm;
+char *object;
+char *message;
+{
+ register ObmFunc evaluate;
+ register ObmObject obj;
+ int status = TCL_ERROR;
+
+ if (obm->debug) {
+ if (!obm->debug_objs || strstr (obm->debug_objs, object) != NULL) {
+ printf ("%s: %s\n", object, message);
+ fflush (stdout);
+ }
+ }
+
+
+ /* Note -- the following can execute appInitialize, which initializes
+ * the server and creates a new Tcl, so no server context (such as
+ * obm->tcl) should be stored in an internal variable here unless
+ * updated or not used again after the evaluate call.
+ */
+ Tcl_SetResult (obm->tcl, "", TCL_STATIC);
+ if (obj = obmFindObject (obm, object)) {
+ if (evaluate = obj->core.classrec->Evaluate) {
+ status = (*evaluate)(obj, message);
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error in message to %s, line %d: %s\n",
+ object, obm->tcl->errorLine,
+ errstr ? errstr : obm->tcl->result);
+ }
+ } else
+ status = TCL_OK;
+ } else {
+ Tcl_AppendResult (obm->tcl,
+ "send: could not find object ", object, NULL);
+ status = TCL_ERROR;
+ }
+
+ return (status);
+}
+
+
+/* ObmDeliverMsgFromFile -- Deliver a message to a UI object, taking the
+ * message from the named text file.
+ */
+ObmDeliverMsgFromFile (obm, object, fname)
+register ObmContext obm;
+char *object;
+char *fname;
+{
+ struct stat fs;
+ char *message = NULL;
+ int status, nchars;
+ int fd = -1;
+
+ if (stat (fname, &fs) >= 0) {
+ nchars = fs.st_size;
+ if ((message = (char *) XtMalloc (nchars + 1)) == NULL)
+ goto err;
+ if ((fd = open (fname, 0)) < 0)
+ goto err;
+ if (read (fd, message, nchars) != nchars)
+ goto err;
+
+ message[nchars] = '\0';
+ status = ObmDeliverMsg (obm, object, message);
+
+ close (fd);
+ XtFree ((char *)message);
+ return (status);
+ }
+err:
+ printf ("cannot access file %s\n", fname);
+ if (fd >= 0)
+ close (fd);
+ if (message)
+ XtFree ((char *)message);
+ return (TCL_ERROR);
+}
+
+
+/* ObmAddCallback -- Add a callback of the given type to the OBM global
+ * callback list.
+ */
+XtPointer
+ObmAddCallback (obm, callback_type, fcn, client_data)
+register ObmContext obm;
+int callback_type;
+ObmFunc fcn;
+XtPointer client_data;
+{
+ register ObmCallback cb;
+
+ if (!(cb = obmAddCallback (&obm->callback_list)))
+ return (NULL);
+
+ cb->u.fcn = fcn;
+ cb->callback_type = callback_type;
+ cb->client_data = client_data;
+ cb->name[0] = '\0';
+}
+
+
+/* ObmRemoveCallback -- Remove a callback from the OBM global callback list.
+ */
+void
+ObmRemoveCallback (obm, callback)
+register ObmContext obm;
+ObmCallback callback;
+{
+ obmRemoveCallback (&obm->callback_list, callback);
+}
+
+
+/*
+ * Object manager internal routines.
+ * ----------------------------------
+ */
+
+/* obmFindObject -- Lookup an object by name and return a pointer to the
+ * associated object descriptor. If the object name is unique only the object
+ * name need be given, otherwise a name such as "parent1.parent2...object"
+ * may be given to specify which object to use.
+ */
+ObmObject
+obmFindObject (obm, object)
+ObmContext obm;
+char *object;
+{
+ register int hashval, n;
+ register char *ip, *op;
+ ObmObject objlist1[MAXOBJ], objlist2[MAXOBJ];
+ ObmObject obj, *otemp, *objs, *pobjs;
+ char name[SZ_NAME];
+ int nobjs;
+
+ if (object == NULL)
+ return (NULL);
+
+ objs = objlist1;
+ pobjs = objlist2;
+ pobjs[0] = objs[0] = NULL;
+ nobjs = 0;
+
+ for (ip=object; *ip; ) {
+ /* List of objects from last run becomes the list of parent objects
+ * for the current run.
+ */
+ otemp = pobjs;
+ pobjs = objs;
+ objs = otemp;
+
+ /* Get next object name. */
+ for (op=name; *ip; ) {
+ if (*ip == '.') {
+ ip++;
+ break;
+ } else
+ *op++ = *ip++;
+ }
+ *op = '\0';
+
+ /* Get list of candidate objects. */
+ if (obm_nameToObjectList (obm, name, pobjs, &nobjs, objs) == 0)
+ return (NULL);
+ }
+
+ if (nobjs <= 0)
+ return (NULL);
+ else if (nobjs > 1)
+ fprintf (stderr, "ambiguous object name: %s\n", object);
+
+ return (objs[0]);
+}
+
+
+/* obm_nameToObjectList -- Return a list of objects with the given name which
+ * are children of one of the (possibly empty) list of parent objects. If the
+ * parent object list is empty the list of all objects with the given name
+ * is returned.
+ */
+obm_nameToObjectList (obm, object, pobjs, nobjs, objs)
+ObmContext obm;
+char *object; /* object name */
+ObmObject *pobjs; /* list of parent objects */
+int *nobjs; /* number of objects found (output) */
+ObmObject *objs; /* list of objects (output) */
+{
+ register char *ip;
+ register int hashval, n;
+ register ObmObject obj;
+ int accept, i;
+
+ if (object == NULL)
+ return (0);
+
+ /* Compute hash value. */
+ for (hashval=0, ip=object, n=MAX_HASHCHARS; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+ if (hashval < 0)
+ return (0);
+
+ /* Examine any objects on the hash thread. */
+ obj = obm->objindex[hashval%SZ_INDEX];
+ for (n=0; obj; obj=obj->core.nexthash) {
+ if (strcmp (object, obj->core.name) == 0) {
+ accept = 0;
+ if (pobjs && pobjs[0]) {
+ for (i=0; pobjs[i]; i++)
+ if (obj->core.parent == pobjs[i]) {
+ accept++;
+ break;
+ }
+ } else
+ accept++;
+
+ if (accept)
+ objs[n++] = obj;
+ }
+ }
+
+ objs[n] = NULL;
+ return (*nobjs = n);
+}
+
+
+/* obmNewObject -- Create a new object of the given type.
+ */
+void
+obmNewObject (obm, name, class, parent, args, nargs)
+register ObmContext obm;
+char *name; /* name of new object */
+char *class; /* name of class to which object belongs */
+char *parent; /* name of parent widget, for widget objects */
+ArgList args; /* optional argument list */
+int nargs; /* optional argument list */
+{
+ register char *ip;
+ register int hashval, n;
+ ObmObject newobj, obj, pobj;
+ ObjClassRec classrec;
+
+ if (obm->being_destroyed)
+ return;
+
+ /* Ignore the request if parent is being destroyed. */
+ pobj = obmFindObject (obm, parent);
+ if (parent && (!pobj || pobj->core.being_destroyed))
+ return;
+
+ /* Get class record. */
+ if (!(classrec = obmGetClassrec (class))) {
+ fprintf (stderr, "obm: object %s has unknown class %s\n",
+ name, class);
+ return;
+ }
+
+ /* Create the object. */
+
+ newobj = (ObmObject) (*(classrec->Create)) (obm,
+ name, classrec, parent, args, nargs);
+ if (!newobj) {
+ fprintf (stderr, "obm: could not create object %s class %s\n",
+ name, class);
+ return;
+ }
+
+ strcpy (newobj->core.name, name);
+ newobj->core.classrec = classrec;
+ newobj->core.parent = pobj;
+
+ /* Link the object into the object list. */
+ if (!obm->head)
+ obm->head = newobj;
+ if (newobj->core.prevglob = obm->tail)
+ obm->tail->core.nextglob = newobj;
+ obm->tail = newobj;
+
+ /* Compute hash value. */
+ for (hashval=0, ip=name, n=MAX_HASHCHARS; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+
+ /* Enter the object into the hash table. */
+ if (obj = obm->objindex[hashval%SZ_INDEX]) {
+ while (obj->core.nexthash)
+ obj = obj->core.nexthash;
+ obj->core.nexthash = newobj;
+ } else
+ obm->objindex[hashval%SZ_INDEX] = newobj;
+
+ /* Add the object to the parent's list of children. */
+ if (parent) {
+ ObmObject pobj;
+ ObmObjectCore cp;
+
+ if ((pobj = obmFindObject (obm, parent)) == NULL) {
+ fprintf (stderr, "obm: object %s has unknown parent %s\n",
+ name, parent);
+ return;
+ } else
+ cp = &pobj->core;
+
+ if (cp->nchildren) {
+ cp->children = (ObmObject *) XtRealloc ((char *)cp->children,
+ (cp->nchildren + 1) * sizeof(ObmObject));
+ } else
+ cp->children = (ObmObject *) XtMalloc (sizeof(ObmObject));
+
+ cp->children[cp->nchildren++] = newobj;
+ }
+}
+
+
+/* obmDestroyObject -- Destroy an object and all its descendents.
+ */
+void
+obmDestroyObject (obm, object)
+ObmContext obm;
+ObmObject object;
+{
+ register ObmObjectCore cp = &object->core;
+ register ObmObject obj;
+ register int i;
+ int hashval, n;
+ char *ip;
+
+ if (!object)
+ return;
+ if (object->core.being_destroyed)
+ return;
+
+ /* Destroy the object instance itself. The object destroy class
+ * method is called twice when an object is destroyed, once at the
+ * beginning before any children are destroyed and once at the end
+ * after all children have been destroyed and the object descriptor
+ * has been unlinked from all Obm object data structures. It is
+ * up to the Destroy class method for the object to decide how much
+ * of the object to destroy in each call. Most objects just set a
+ * being_destroyed flag in the first call and wait until the end
+ * to destroy the object, in case the object descriptor is referenced
+ * during the destroy process. An example of a class which does
+ * things differently is the widget class. In the case of a widget
+ * the first call destroys the widget and all of its children, even
+ * though the object descriptors are not freed until the remainder of
+ * the code below is executed. This allows the window system toolkit
+ * code to determine the best way to destroy a widget hierarchy,
+ * rather than having us destroy each widget one by one from the
+ * bottom up.
+ */
+ (*(object->core.classrec->Destroy)) (object);
+
+ /* Destroy any children. Note that each time a child is destroyed the
+ * child list in the object descriptor is modified, so we merely loop
+ * until nchildren goes to zero.
+ */
+ if (cp->nchildren) {
+ while (cp->nchildren > 0)
+ obmDestroyObject (obm, cp->children[0]);
+ }
+
+ /* Remove this object from the child list of the parent. */
+ if (obj = object->core.parent) {
+ if (obj->core.nchildren == 1) {
+ XtFree ((char *)obj->core.children);
+ obj->core.nchildren = 0;
+
+ } else {
+ int nchild = obj->core.nchildren;
+ ObmObject *new_list, *ip, *op;
+
+ new_list = (ObmObject *) XtMalloc (nchild * sizeof(ObmObject));
+ op = new_list;
+
+ for (ip = obj->core.children; --nchild >= 0; ip++)
+ if (*ip != object)
+ *op++ = *ip;
+
+ XtFree ((char *)obj->core.children);
+ obj->core.children = new_list;
+ obj->core.nchildren--;
+ }
+ }
+
+ /* Unlink the object from the global object list. */
+ if (obj = object->core.prevglob) {
+ if (!(obj->core.nextglob = object->core.nextglob))
+ obm->tail = obj;
+ } else
+ obm->head = object->core.nextglob;
+
+ if (obj = object->core.nextglob) {
+ if (!(obj->core.prevglob = object->core.prevglob))
+ obm->head = obj;
+ } else
+ obm->tail = object->core.prevglob;
+
+ /* Unlink the object from the hash list. */
+ ip = object->core.name;
+ for (hashval=0, n=MAX_HASHCHARS; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+ if (obj = obm->objindex[hashval%SZ_INDEX]) {
+ while (obj && obj->core.nexthash != object)
+ obj = obj->core.nexthash;
+ if (obj)
+ obj->core.nexthash = object->core.nexthash;
+ else
+ obm->objindex[hashval%SZ_INDEX] = NULL;
+ }
+
+ /* Free the object descriptor. */
+ (*(object->core.classrec->Destroy)) (object);
+ XtFree ((char *)object);
+}
+
+
+/* obmDisplay -- Display an entire user interface, including all top level
+ * shells.
+ */
+void
+obmDisplay (obm, obj)
+ObmContext obm;
+ObmObject obj;
+{
+ register Widget w = widgetGetPointer (obj);
+ register ObmObject child;
+ register int i;
+ char buf[SZ_NAME];
+
+ for (i=0; i < obj->core.nchildren; i++) {
+ child = obj->core.children[i];
+ if (child->core.classrec->object_type == OtShell)
+ obmDisplay (obm, child);
+ }
+
+ /* The following isn't used anymore. */
+ if (obj->core.geometry[0])
+ XtVaSetValues (w, XtNgeometry, obj->core.geometry, NULL);
+
+ XtRealizeWidget (w);
+ if (obj->core.mapped)
+ XtMapWidget (w);
+}
+
+
+/* obmUndisplay -- Undisplay an entire user interface, including all top level
+ * shells.
+ */
+void
+obmUndisplay (obm, obj)
+ObmContext obm;
+ObmObject obj;
+{
+ register int i;
+ register ObmObject child;
+ register Widget w = widgetGetPointer (obj);
+ XWindowAttributes wa;
+ char *s;
+
+ for (i=0; i < obj->core.nchildren; i++) {
+ child = obj->core.children[i];
+ if (child->core.classrec->object_type == OtShell)
+ obmUndisplay (obm, child);
+ }
+
+ if (XtWindow(w)) {
+ /* The following isn't used anymore. */
+ if (s = get_geometry (obm->display, obm->screen, XtWindow(w), 1))
+ strcpy (obj->core.geometry, s);
+ if (XGetWindowAttributes (obm->display, XtWindow(w), &wa))
+ obj->core.mapped = (wa.map_state != IsUnmapped);
+ /* XtUnrealizeWidget (w); */
+
+ /* Unrealizing the widgets is too drastic, the following merely
+ * makes the window and icon disappear.
+ */
+ XmuUpdateMapHints (obm->display, XtWindow(w), NULL);
+ XWithdrawWindow (obm->display, XtWindow(w),
+ XScreenNumberOfScreen(obm->screen));
+ }
+}
+
+
+/* obmGetClassrec -- Get the class record for the named class.
+ */
+ObjClassRec
+obmGetClassrec (classname)
+char *classname;
+{
+ register ObjClassRec classrec;
+ register int i;
+
+ for (i=0; i < XtNumber(UiObjects); i++) {
+ classrec = &UiObjects[i];
+ if (strcmp (classname, classrec->name) == 0)
+ return (classrec);
+ }
+
+ return (NULL);
+}
+
+
+/* obmGenericClassDestroy - Free any resources associated with a class record.
+ */
+void
+obmGenericClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+}
+
+
+/* obmClass -- Test if a class record belongs to the given object class.
+ */
+obmClass (classrec, flag1, flag2)
+register ObjClassRec classrec;
+unsigned long flag1, flag2;
+{
+ return ((classrec->flag1 & flag1) || (classrec->flag2 & flag2));
+}
+
+
+/* obmAddCallback -- Add a callback descriptor to a callback list.
+ */
+ObmCallback
+obmAddCallback (callback_list)
+ObmCallback *callback_list;
+{
+ register ObmCallback cb, last_cb;
+
+ /* Find tail of list. */
+ for (cb = last_cb = *callback_list; cb; cb = cb->next)
+ last_cb = cb;
+
+ if (!(cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback))))
+ return (NULL);
+
+ if (!last_cb)
+ *callback_list = cb;
+ else
+ last_cb->next = cb;
+
+ return (cb);
+}
+
+
+/* obmRemoveCallback -- Remove a callback descriptor from a callback list.
+ */
+void
+obmRemoveCallback (callback_list, callback)
+ObmCallback *callback_list;
+ObmCallback callback;
+{
+ register ObmCallback cb, last_cb;
+
+ if (!callback)
+ return;
+
+ /* Search for named callback descriptor. */
+ for (cb = *callback_list, last_cb = NULL; cb; cb = cb->next) {
+ if (cb == callback)
+ break;
+ else
+ last_cb = cb;
+ }
+
+ if (last_cb)
+ last_cb->next = cb->next;
+ else
+ *callback_list = cb->next;
+
+ XtFree ((char *) cb);
+}
+
+
+/* obmDefined -- Test if the named function is a defined client function in
+ * the given Tcl interepter.
+ */
+obmClientCommand (tcl, commmand)
+Tcl_Interp *tcl;
+char *commmand;
+{
+ register char *ip, *op;
+ char name[SZ_NAME];
+ Tcl_CmdInfo info;
+
+ /* Get command name. This works even if we are passed a command
+ * line including arguments.
+ */
+ for (ip=commmand; *ip && isspace(*ip); ip++)
+ ;
+ for (op=name; *ip && !isspace(*ip) && *ip != ';'; )
+ *op++ = *ip++;
+ *op = '\0';
+ if (op - name == 0)
+ return (False);
+
+ /* Test if the named client command exists. This assumes that
+ * client commands always have the clientData field set to a
+ * non-NULL value. Tcl (at least in the current version) sets
+ * this field to NULL for the builtin commands.
+ */
+ if (Tcl_GetCommandInfo (tcl, name, &info))
+ return (info.clientData != NULL);
+ else
+ return (False);
+}
diff --git a/vendor/x11iraf/obm/Obm.h b/vendor/x11iraf/obm/Obm.h
new file mode 100644
index 00000000..9e636437
--- /dev/null
+++ b/vendor/x11iraf/obm/Obm.h
@@ -0,0 +1,45 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+/*
+ * OBM.H -- Public definitions for the object manager.
+ */
+
+#ifndef _Obm_Defined
+
+#ifndef Obm_Private
+typedef struct { int dummy; } *ObmContext;
+#endif
+
+ObmContext ObmOpen (/* app_context, argc, argv */);
+void ObmClose (/* obm */);
+void ObmInitialize (/* obm */);
+void ObmActivate (/* obm */);
+void ObmDeactivate (/* obm, unmap */);
+int ObmActivated (/* obm */);
+int ObmStatus (/* obm, app_name, app_class */);
+XtPointer ObmGetInterp (/* obm, object */);
+int ObmDeliverMsg (/* obm, object, message */);
+int ObmDeliverMsgFromFile (/* obm, object, filename */);
+XtPointer ObmAddCallback (/* obm, fcn, callback_type, client_data */);
+void ObmRemoveCallback (/* obm, callback_id */);
+
+/* Callback type flags. */
+#define OBMCB_preserve 0000001 /* preserve over ObmInit */
+
+#define OBMCB_connect 0000010 /* callback types */
+#define OBMCB_activate 0000020
+#define OBMCB_deactivate 0000040
+#define OBMCB_setGterm 0000100
+#define OBMCB_clientOutput 0000200
+
+#define OBMUI_activate 0100000 /* internal */
+#define OBMUI_deactivate 0200000 /* internal */
+
+/* ObmStatus states. */
+#define OBM_INITIALIZED 0
+#define OBM_ACTIVE 1
+#define OBM_IDLE 2
+
+#define _Obm_Defined
+#endif
diff --git a/vendor/x11iraf/obm/ObmP.h b/vendor/x11iraf/obm/ObmP.h
new file mode 100644
index 00000000..81ac52dd
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmP.h
@@ -0,0 +1,508 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+/*
+ * ObmP.h -- Private or internal global definitions for the Object Manager.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Core.h>
+#include <X11/Object.h>
+
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Grip.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/List.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Panner.h>
+#include <X11/Xaw/Porthole.h>
+#include <X11/Xaw/Repeater.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Simple.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/SmeBSB.h>
+#include <X11/Xaw/SmeLine.h>
+#include <X11/Xaw/StripChart.h>
+#include <X11/Xaw/Toggle.h>
+#include <X11/Xaw/Tree.h>
+#include <X11/Xaw/Viewport.h>
+
+#include <ObmW/Arrow.h>
+#include <ObmW/Board.h>
+#include <ObmW/Button.h>
+#include <ObmW/Common.h>
+#include <ObmW/Frame.h>
+#include <ObmW/Group.h>
+#include <ObmW/Gterm.h>
+#include <ObmW/HTML.h>
+#include <ObmW/Icon.h>
+#include <ObmW/Label.h>
+#include <ObmW/Layout.h>
+#include <ObmW/ListTree.h>
+#include <ObmW/MenuBar.h>
+#include <ObmW/MultiList.h>
+#include <ObmW/RadioGrp.h>
+#include <ObmW/RowCol.h>
+#include <ObmW/Scrollbar.h>
+#include <ObmW/Slider2.h>
+#include <ObmW/Tabs.h>
+#include <ObmW/Toggle.h>
+
+#include <X11/Xraw/Separator.h>
+#include <X11/Xraw/Table.h>
+
+#include <X11/xpm.h>
+#include <Tcl/tcl.h>
+
+/* Size limiting definitions. */
+#define SZ_NAME 128 /* class or object name */
+#define SZ_LINE 256 /* line buffer */
+#define SZ_INDEX 197 /* hash index */
+#define SZ_MESSAGE 512 /* random string buffers */
+#define SZ_COMMAND 8192 /* general command buffers */
+#define SZ_NUMBER 64 /* numeric string buffers */
+#define SZ_GEOMETRY 32 /* geometry specification */
+#define MAX_RESOURCES 2048 /* max resources in application */
+#define MAX_HASHCHARS 8 /* max chars used for hashval */
+#define MAX_ARGS 128 /* scratch arg list */
+#define MAX_MENUITEMS 64 /* max items in a menu */
+#define MAX_LEVELS 128 /* recursive nesting */
+#define MAXNDC 32767 /* NDC graphics coordinates */
+#define MAXCOLORSYM 20 /* max color resources for icons */
+
+#define MI_IGNORE 0 /* menu item type codes */
+#define MI_EXEC 1
+#define MI_LINE 2
+#define MI_DBLLINE 3
+#define MI_MENU 4
+#define MI_SPACE 5
+#define MI_TITLE 6
+
+#define M_Insensitive 000001 /* menu attribute bitflags */
+#define M_FreeBackground 000002
+#define M_FreeForeground 000004
+#define M_FreeAccel 000010
+#define M_FreeLabel 000020
+#define M_FreeData 000040
+
+/* Object class types */
+#define OtShell 1 /* shell widget class */
+#define OtNonShell 2 /* nonshell widget class */
+#define OtParameter 3 /* UI control parameter class */
+#define OtServer 4 /* UI server class */
+#define OtClient 5 /* UI client class */
+#define OtMarker 6 /* gterm marker class */
+#define OtNClasses 6
+
+typedef int (*ObmFunc)();
+typedef void (*ObmMethod)();
+
+extern void ServerClassInit(), ClientClassInit(), ParameterClassInit();
+extern void WidgetClassInit(), GenericClassDestroy();
+extern void GtermClassInit(), MarkerClassInit(), HTMLClassInit();
+
+/* Dummy WtClass bit flag definitions for initializers. */
+#define WtServer 0, 0
+#define WtClient 0, 0
+#define WtParameter 0, 0
+#define WtMarker 0, 0
+
+/* Widget class bit flags.
+ */
+#define WtCore 00000000000, 00000000001
+#define WtObject 00000000000, 00000000002
+#define WtSimple 00000000000, 00000000004
+#define WtShell 00000000000, 00000000010
+
+#define WtAsciiSink 00000000000, 00000000020
+#define WtAsciiSrc 00000000000, 00000000040
+#define WtAsciiText 00000000000, 00000000100
+#define WtBox 00000000000, 00000000200
+#define WtCommand 00000000000, 00000000400
+#define WtDialog 00000000000, 00000001000
+#define WtForm 00000000000, 00000002000
+#define WtGrip 00000000000, 00000004000
+#define WtLabel 00000000000, 00000010000
+#define WtList 00000000000, 00000020000
+#define WtMenuButton 00000000000, 00000040000
+#define WtPaned 00000000000, 00000100000
+#define WtPanner 00000000000, 00000200000
+#define WtPorthole 00000000000, 00000400000
+#define WtRepeater 00000000000, 00001000000
+#define WtScrollbar 00000000000, 00002000000
+#define WtSimpleMenu 00000000000, 00004000000
+#define WtSme 00000000000, 00010000000
+#define WtSmeBSB 00000000000, 00020000000
+#define WtSmeLine 00000000000, 00040000000
+#define WtStripChart 00000000000, 00100000000
+#define WtToggle 00000000000, 00200000000
+#define WtTree 00000000000, 00400000000
+#define WtViewport 00000000000, 01000000000
+
+#define WtGterm 00000000001, 00000000000
+#define WtLayout 00000000002, 00000000000
+#define WtHTML 00000000004, 00000000000
+#define WtArrow 00000000010, 00000000000
+#define WtBoard 00000000020, 00000000000
+#define WtScrollbar2 00000000040, 00000000000
+#define WtSlider2d 00000000100, 00000000000
+#define WtFrame 00000000200, 00000000000
+#define WtGroup 00000000400, 00000000000
+#define WtIcon 00000001000, 00000000000
+#define WtMultiList 00000002000, 00000000000
+#define WtRadioGroup 00000004000, 00000000000
+#define WtRowCol 00000010000, 00000000000
+#define WtTextBox 00000020000, 00000000000
+#define WtTextButton 00000040000, 00000000000
+#define WtTextToggle 00000100000, 00000000000
+#define WtXfwfCommon 00000200000, 00000000000
+#define WtXfwfMenuBar 00000400000, 00000000000
+#define WtTabs 00001000000, 00000000000
+#define WtListTree 00002000000, 00000000000
+#define WtSeparator 00004000000, 00000000000
+#define WtTable 00010000000, 00000000000
+
+/* Object base classes. */
+typedef struct {
+ int class; /* class type code */
+ char name[SZ_NAME]; /* class name */
+} baseClassRec, *BaseClassRec;
+
+/* UI object class descriptor. */
+typedef struct {
+ char name[SZ_NAME]; /* object class name */
+ int object_type; /* widget type (shell etc.) */
+ WidgetClass *widget_class; /* for Xt/Athena widgets */
+ unsigned long flag1, flag2; /* widget class bit flags. */
+ ObmMethod ClassInit; /* initializes class record */
+ ObmMethod ClassDestroy; /* close class record */
+ ObmFunc Create; /* create proc */
+ ObmMethod Destroy; /* destroy proc */
+ ObmFunc Evaluate; /* evaluate proc */
+ XtPointer class_data; /* class specific data */
+} objClassRec, *ObjClassRec;
+
+/* Class descriptors for all UI object classes and subclasses. In the
+ * following only the class initializer function needs to be set statically,
+ * since the class initializer function will initialize the remaining fields
+ * of the class descriptor at run time when the object manager is opened.
+ */
+#ifdef Obm_Main
+baseClassRec baseClasses[] = {
+ { OtShell, "Widget", },
+ { OtNonShell, "Widget", },
+ { OtParameter, "Parameter", },
+ { OtServer, "Server", },
+ { OtClient, "Client", },
+ { OtMarker, "Marker", },
+};
+
+objClassRec UiObjects[] = {
+ { "Server", OtServer, NULL, WtServer,
+ ServerClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Client", OtClient, NULL, WtClient,
+ ClientClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Parameter", OtParameter, NULL, WtParameter,
+ ParameterClassInit, NULL, NULL, NULL, NULL, NULL },
+
+ { "Core", OtNonShell, &coreWidgetClass, WtCore,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Object", OtNonShell, &objectClass, WtObject,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Simple", OtNonShell, &simpleWidgetClass, WtSimple,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Widget", OtNonShell, &coreWidgetClass, WtCore,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+
+ { "AsciiText", OtNonShell, &asciiTextWidgetClass, WtAsciiText,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Box", OtNonShell, &boxWidgetClass, WtBox,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Command", OtNonShell, &commandWidgetClass, WtCommand,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Dialog", OtNonShell, &dialogWidgetClass, WtDialog,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Form", OtNonShell, &formWidgetClass, WtForm,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Grip", OtNonShell, &gripWidgetClass, WtGrip,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Label", OtNonShell, &labelWidgetClass, WtLabel,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "List", OtNonShell, &listWidgetClass, WtList,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "ListTree", OtNonShell, &listtreeWidgetClass, WtListTree,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "MenuButton", OtNonShell, &menuButtonWidgetClass, WtMenuButton,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Paned", OtNonShell, &panedWidgetClass, WtPaned,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Panner", OtNonShell, &pannerWidgetClass, WtPanner,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Porthole", OtNonShell, &portholeWidgetClass, WtPorthole,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Repeater", OtNonShell, &repeaterWidgetClass, WtRepeater,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Scrollbar", OtNonShell, &scrollbarWidgetClass, WtScrollbar,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Separator", OtNonShell, &separatorWidgetClass, WtSeparator,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "SimpleMenu", OtShell, &simpleMenuWidgetClass, WtSimpleMenu,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Sme", OtNonShell, &smeObjectClass, WtSme,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "SmeBSB", OtNonShell, &smeBSBObjectClass, WtSmeBSB,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "SmeLine", OtNonShell, &smeLineObjectClass, WtSmeLine,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "StripChart", OtNonShell, &stripChartWidgetClass, WtStripChart,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Table", OtNonShell, &tableWidgetClass, WtTable,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Tabs", OtNonShell, &tabsWidgetClass, WtTabs,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Toggle", OtNonShell, &toggleWidgetClass, WtToggle,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Tree", OtNonShell, &treeWidgetClass, WtTree,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Viewport", OtNonShell, &viewportWidgetClass, WtViewport,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+
+ { "Gterm", OtNonShell, &gtermWidgetClass, WtGterm,
+ GtermClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Marker", OtMarker, NULL, WtMarker,
+ MarkerClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Layout", OtNonShell, &layoutWidgetClass, WtLayout,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "HTML", OtNonShell, &htmlWidgetClass, WtHTML,
+ HTMLClassInit, NULL, NULL, NULL, NULL, NULL },
+
+ { "Arrow", OtNonShell, &xfwfArrowWidgetClass, WtArrow,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Board", OtNonShell, &xfwfBoardWidgetClass, WtBoard,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Frame", OtNonShell, &xfwfFrameWidgetClass, WtFrame,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Group", OtNonShell, &xfwfGroupWidgetClass, WtGroup,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Icon", OtNonShell, &xfwfIconWidgetClass, WtIcon,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "MultiList", OtNonShell, &xfwfMultiListWidgetClass, WtMultiList,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "RadioGroup", OtNonShell,&xfwfRadioGroupWidgetClass,WtRadioGroup,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "RowCol", OtNonShell, &xfwfRowColWidgetClass, WtRowCol,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "TextBox", OtNonShell, &xfwfLabelWidgetClass, WtTextBox,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "TextButton", OtNonShell, &xfwfButtonWidgetClass, WtTextButton,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "TextToggle", OtNonShell, &xfwfToggleWidgetClass, WtTextToggle,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Scrollbar2", OtNonShell, &xfwfScrollbarWidgetClass, WtScrollbar2,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "Slider2d", OtNonShell, &xfwfSlider2WidgetClass, WtSlider2d,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+
+ { "Shell", OtShell, &shellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "OverrideShell",
+ OtShell, &overrideShellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "WMShell",
+ OtShell, &wmShellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "TransientShell",
+ OtShell, &transientShellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "TopLevelShell",
+ OtShell, &topLevelShellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+ { "ApplicationShell",
+ OtShell, &applicationShellWidgetClass, WtShell,
+ WidgetClassInit, NULL, NULL, NULL, NULL, NULL },
+};
+#else
+extern objClassRec UiObjects[];
+extern baseClassRec baseClasses[];
+#endif
+
+
+/* Generic object instance record, omitting the class part. The object
+ * instance records for the real object classes share the objectCore structure
+ * but have a class specific structure and are a different size.
+ */
+struct obmObject {
+ struct obmObjectCore {
+ char name[SZ_NAME]; /* object name */
+ ObjClassRec classrec; /* class record */
+ ObjClassRec superclass; /* superclass, if class is subclass */
+ struct obmObject *prevglob; /* previous object in global list */
+ struct obmObject *nextglob; /* next object in global list */
+ struct obmObject *nexthash; /* next object in hash list */
+ struct obmObject *parent; /* the object's parent */
+ int nchildren; /* number of child objects */
+ struct obmObject **children; /* list of child objects */
+ Boolean being_destroyed; /* set by Destroy method */
+ Boolean mapped; /* used to recreate shells */
+ char geometry[SZ_GEOMETRY]; /* used to recreate shells */
+ } core;
+ /* class part omitted */
+};
+
+typedef struct obmObject *ObmObject;
+typedef struct obmObjectCore *ObmObjectCore;
+
+/* Object list. */
+struct objList {
+ char name[SZ_NAME];
+ caddr_t ptr;
+ struct objList *next;
+};
+
+/* Menu item. */
+typedef struct {
+ int type;
+ XtPointer menu;
+ Widget entry;
+ char *sbuf;
+ char *label;
+ char *data;
+ char *accelerator;
+ char *background;
+ char *foreground;
+ int justify;
+ Pixmap pixmap;
+ int flags;
+} menuItem, *MenuItem;
+
+/* Menu descriptor. */
+typedef struct {
+ ObmObject obj;
+ Widget menuShell;
+ Boolean popped_up;
+ XtPointer obm;
+ int nitems;
+ menuItem items[MAX_MENUITEMS];
+} Menu, *MenuPtr;
+
+typedef struct objList *ObjList;
+
+/* Callback type codes. */
+#define Ctcallback 0 /* most widgets */
+#define Ctcharmode 1 /* text widget, char mode */
+#define Ctlinemode 2 /* text widget, char mode */
+#define CtgetValue 3 /* strip chart */
+#define CtjumpProc 4 /* scrollbar */
+#define CtscrollProc 5 /* scrollbar */
+#define CtpopdownCallback 6 /* shell, simpleMenu */
+#define CtpopupCallback 7 /* shell, simpleMenu */
+#define CtreportCallback 8 /* panner, porthole, viewport */
+#define CtstartCallback 9 /* repeater */
+#define CtstopCallback 10 /* repeater */
+
+struct _obmCallback {
+ union {
+ ObmObject obj;
+ ObmFunc fcn;
+ } u;
+ int callback_type;
+ XtPointer client_data;
+ struct _obmCallback *next;
+ char name[SZ_NAME];
+};
+
+typedef struct _obmCallback obmCallback;
+typedef struct _obmCallback *ObmCallback;
+
+/* Object manager global context. */
+struct obmContext {
+ char appname[SZ_NAME]; /* application name */
+ char appclass[SZ_NAME]; /* application class */
+ int argc; /* args for popup shell */
+ char **argv; /* args for popup shell */
+ XtAppContext app_context; /* application context */
+ Display *display; /* Obm private display connection */
+ Screen *screen; /* Obm private display connection */
+ Widget toplevel; /* toplevel shell of application */
+ Tcl_Interp *tcl; /* global or server interpreter */
+ ObmObject head; /* head of object list */
+ ObmObject tail; /* tail of object list */
+ ObmObject objindex[SZ_INDEX]; /* hash index */
+ ObjList pixmap_cache; /* cached pixmaps */
+ ObjList cursor_cache; /* cached cursors */
+ ObjList menu_list; /* list of menu descriptors */
+ ObmCallback callback_list; /* list of callback descriptors */
+ Boolean being_destroyed; /* set by Destroy method */
+ Boolean specified; /* UI has been specified */
+ Boolean activated; /* UI has been activated */
+ Boolean mapped; /* toplevel is mapped */
+
+ int debug; /* print debug messages */
+ char *debug_objs; /* debug objects, NULL=>all objs */
+};
+
+typedef struct obmContext *ObmContext;
+
+#ifdef Obm_Main
+ObmContext global_obm_handle; /* only works if single obm */
+#else
+extern ObmContext global_obm_handle;
+#endif
+
+/* Useful macros. */
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+#ifndef AIXV3
+#ifndef OSF1
+typedef unsigned char uchar;
+#endif
+#endif
+
+/* The following are the string values returned to Tcl for boolean values. */
+#define TRUESTR "1"
+#define FALSESTR "0"
+
+extern ObmObject obmFindObject();
+extern ObjClassRec obmGetClassrec();
+extern Widget widgetGetPointer();
+extern ObmCallback obmAddCallback();
+extern void widget_setTTName();
+extern char *widget_getTTName();
+extern void obmRemoveCallback();
+extern void obmNewObject();
+extern void obmFreeObject();
+extern void obmDestroyObject();
+extern void obmGenericClassDestroy();
+extern void obmDisplay(), obmUndisplay();
+extern void freeMenu();
+extern void freeIcon();
+extern Pixmap findBitmap();
+extern Pixmap findPixmap();
+extern Cursor findCursor();
+extern Icon *findIcon();
+extern char *get_geometry();
+
+/* Public functions. */
+#define Obm_Private
+#include "Obm.h"
+#undef Obm_Private
+
+extern char *getenv();
diff --git a/vendor/x11iraf/obm/ObmW/Arrow.c b/vendor/x11iraf/obm/ObmW/Arrow.c
new file mode 100644
index 00000000..3c13146a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Arrow.c
@@ -0,0 +1,465 @@
+/* Generated by wbuild from "Arrow.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "stip4.bm"
+#include <stdio.h>
+#include <assert.h>
+#include "ArrowP.h"
+static void activate_and_start_timer(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void stop_timer(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"activate_and_start_timer", activate_and_start_timer},
+{"stop_timer", stop_timer},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Down>: activate_and_start_timer() \n\
+<Btn1Up>: stop_timer() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void timer_callback(
+#if NeedFunctionPrototypes
+XtPointer ,XtIntervalId *
+#endif
+);
+static void create_arrowgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_arrowlightgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_arrowdarkgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void timer_callback(client_data,timer)XtPointer client_data;XtIntervalId * timer;
+{
+ Widget self = (Widget) client_data;
+
+ XtCallCallbackList(self, ((XfwfArrowWidget)self)->xfwfArrow.callback, NULL);
+ ((XfwfArrowWidget)self)->xfwfArrow.timer = XtAppAddTimeOut(XtWidgetToApplicationContext(self),
+ ((XfwfArrowWidget)self)->xfwfArrow.repeatDelay, timer_callback, self);
+}
+/*ARGSUSED*/static void create_arrowgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowgc != NULL) XtReleaseGC(self, ((XfwfArrowWidget)self)->xfwfArrow.arrowgc);
+ mask = GCForeground;
+ values.foreground = ((XfwfArrowWidget)self)->xfwfArrow.foreground;
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_arrowlightgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc != NULL) XtReleaseGC(self, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc);
+ switch (((XfwfArrowWidget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfArrowWidget)self)->xfwfFrame.topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfArrowWidget)self)->core.background_pixel;
+ values.stipple = ((XfwfArrowWidget)self)->xfwfFrame.topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfArrowWidgetClass)self->core.widget_class)->xfwfCommon_class.lighter_color(self, ((XfwfArrowWidget)self)->xfwfArrow.foreground, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfArrowWidget)self)->xfwfArrow.foreground;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_arrowdarkgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc != NULL) XtReleaseGC(self, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc);
+ switch (((XfwfArrowWidget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfArrowWidget)self)->xfwfFrame.bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = ((XfwfArrowWidget)self)->xfwfFrame.bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen(self));
+ values.background = ((XfwfArrowWidget)self)->core.background_pixel;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfArrowWidgetClass)self->core.widget_class)->xfwfCommon_class.darker_color(self, ((XfwfArrowWidget)self)->xfwfArrow.foreground, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfArrowWidget)self)->xfwfArrow.foreground;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc = XtGetGC(self, mask, &values);
+}
+
+static XtResource resources[] = {
+{XtNdirection,XtCDirection,XtRAlignment,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.direction),XtOffsetOf(XfwfArrowRec,xfwfArrow.direction),XtRImmediate,(XtPointer)XfwfTop },
+{XtNforeground,XtCForeground,XtRPixel,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.foreground),XtOffsetOf(XfwfArrowRec,xfwfArrow.foreground),XtRString,(XtPointer)XtDefaultBackground },
+{XtNarrowShadow,XtCArrowShadow,XtRDimension,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.arrowShadow),XtOffsetOf(XfwfArrowRec,xfwfArrow.arrowShadow),XtRImmediate,(XtPointer)2 },
+{XtNinitialDelay,XtCInitialDelay,XtRCardinal,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.initialDelay),XtOffsetOf(XfwfArrowRec,xfwfArrow.initialDelay),XtRImmediate,(XtPointer)500 },
+{XtNrepeatDelay,XtCRepeatDelay,XtRCardinal,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.repeatDelay),XtOffsetOf(XfwfArrowRec,xfwfArrow.repeatDelay),XtRImmediate,(XtPointer)200 },
+{XtNcallback,XtCCallback,XtRCallback,sizeof(((XfwfArrowRec*)NULL)->xfwfArrow.callback),XtOffsetOf(XfwfArrowRec,xfwfArrow.callback),XtRImmediate,(XtPointer)NULL },
+};
+
+XfwfArrowClassRec xfwfArrowClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfBoardClassRec,
+"Arrow",
+sizeof(XfwfArrowRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+2,
+resources,
+6,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfArrow_class part */
+0
+},
+};
+WidgetClass xfwfArrowWidgetClass = (WidgetClass) &xfwfArrowClassRec;
+/*ARGSUSED*/
+static void activate_and_start_timer(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (event->type != ButtonPress) {
+ XtWarning("The Arrow activate action isn't bound to a BtnDown event");
+ return;
+ }
+ XtCallCallbackList(self, ((XfwfArrowWidget)self)->xfwfArrow.callback, NULL);
+ ((XfwfArrowWidget)self)->xfwfArrow.timer = XtAppAddTimeOut(XtWidgetToApplicationContext(self),
+ ((XfwfArrowWidget)self)->xfwfArrow.initialDelay, timer_callback, self);
+}
+
+/*ARGSUSED*/
+static void stop_timer(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XtRemoveTimeOut(((XfwfArrowWidget)self)->xfwfArrow.timer);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfArrowWidgetClass c = (XfwfArrowWidgetClass) class;
+ XfwfArrowWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfArrowWidgetClass) return;
+ super = (XfwfArrowWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfTop && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfLeft
+ && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfRight && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfBottom) {
+ XtWarning("direction of Arrow widget incorrect; set to `top'");
+ ((XfwfArrowWidget)self)->xfwfArrow.direction = XfwfTop;
+ }
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowgc = NULL; create_arrowgc(self);
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc = NULL; create_arrowlightgc(self);
+ ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc = NULL; create_arrowdarkgc(self);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redisplay = False;
+
+ if (((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfTop && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfLeft
+ && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfRight && ((XfwfArrowWidget)self)->xfwfArrow.direction != XfwfBottom) {
+ XtWarning("direction of Arrow widget incorrect; set to `top'");
+ ((XfwfArrowWidget)self)->xfwfArrow.direction = XfwfTop;
+ }
+ if (((XfwfArrowWidget)old)->xfwfArrow.direction != ((XfwfArrowWidget)self)->xfwfArrow.direction)
+ need_redisplay = True;
+ if (((XfwfArrowWidget)old)->xfwfArrow.foreground != ((XfwfArrowWidget)self)->xfwfArrow.foreground) {
+ create_arrowgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfArrowWidget)old)->xfwfArrow.arrowShadow != ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow)
+ need_redisplay = True;
+ if (((XfwfArrowWidget)self)->xfwfFrame.shadowScheme != ((XfwfArrowWidget)old)->xfwfFrame.shadowScheme) {
+ create_arrowdarkgc(self);
+ create_arrowlightgc(self);
+ need_redisplay = True;
+ } else if (((XfwfArrowWidget)self)->xfwfFrame.shadowScheme == XfwfColor) {
+ if (((XfwfArrowWidget)self)->xfwfFrame.topShadowColor != ((XfwfArrowWidget)old)->xfwfFrame.topShadowColor) {
+ create_arrowlightgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfArrowWidget)self)->xfwfFrame.bottomShadowColor != ((XfwfArrowWidget)old)->xfwfFrame.bottomShadowColor) {
+ create_arrowdarkgc(self);
+ need_redisplay = True;
+ }
+ } else if (((XfwfArrowWidget)self)->xfwfFrame.shadowScheme = XfwfStipple) {
+ if (((XfwfArrowWidget)self)->xfwfFrame.topShadowStipple != ((XfwfArrowWidget)old)->xfwfFrame.topShadowStipple) {
+ create_arrowlightgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfArrowWidget)self)->xfwfFrame.bottomShadowStipple != ((XfwfArrowWidget)old)->xfwfFrame.bottomShadowStipple) {
+ create_arrowdarkgc(self);
+ need_redisplay = True;
+ }
+ }
+ return need_redisplay;
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ XPoint p1[3], p2[4], p3[4], p4[4];
+ Position x, y;
+ Dimension width, height, a, a2, a3;
+
+ assert(((XfwfArrowWidget)self)->xfwfArrow.direction == XfwfTop || ((XfwfArrowWidget)self)->xfwfArrow.direction == XfwfLeft
+ || ((XfwfArrowWidget)self)->xfwfArrow.direction == XfwfRight || ((XfwfArrowWidget)self)->xfwfArrow.direction == XfwfBottom);
+
+ if (! XtIsRealized(self)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, region);
+ XSetRegion(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, region);
+ XSetRegion(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, region);
+ }
+ ((XfwfArrowWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &width, &height);
+ a = ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow;
+ switch (((XfwfArrowWidget)self)->xfwfArrow.direction) {
+ case XfwfTop:
+ a2 = (1.0 + 0.71*width/height) * a;
+ a3 = (1.0 + 0.83*height/width) * a;
+ point(p1, 0, x + width/2, y + a3);
+ point(p1, 1, x + a2, y + height - a);
+ point(p1, 2, x + width - a2, y + height - a);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if (a == 0) break;
+ point(p2, 0, x + width/2, y);
+ point(p2, 1, x + width/2, y + a3);
+ point(p2, 2, x + width - a2, y + height - a);
+ point(p2, 3, x + width, y + height);
+
+ point(p3, 0, x + a2, y + height - a);
+ point(p3, 1, x, y + height);
+ point(p3, 2, x + width, y + height);
+ point(p3, 3, x + width - a2, y + height - a);
+
+ point(p4, 0, x + width/2, y);
+ point(p4, 1, x, y + height);
+ point(p4, 2, x + a2, y + height - a);
+ point(p4, 3, x + width/2, y + a3);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfLeft:
+ a2 = (1.0 + 0.83*width/height) * a;
+ a3 = (1.0 + 0.71*height/width) * a;
+ point(p1, 0, x + a2, y + height/2);
+ point(p1, 1, x + width - a, y + a3);
+ point(p1, 2, x + width - a, y + height - a3);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowShadow == 0) break;
+ point(p2, 0, x + width, y);
+ point(p2, 1, x, y + height/2);
+ point(p2, 2, x + a2, y + height/2);
+ point(p2, 3, x + width - a, y + a3);
+
+ point(p3, 0, x, y + height/2);
+ point(p3, 1, x + width, y + height);
+ point(p3, 2, x + width - a, y + height - a3);
+ point(p3, 3, x + a2, y + height/2);
+
+ point(p4, 0, x + width, y);
+ point(p4, 1, x + width - a, y + a3);
+ point(p4, 2, x + width - a, y + height - a3);
+ point(p4, 3, x + width, y + height);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfBottom:
+ a2 = (1.0 + 0.71*width/height) * a;
+ a3 = (1.0 + 0.83*height/width) * a;
+ point(p1, 0, x + width/2, y + height - a3);
+ point(p1, 1, x + a2, y + a);
+ point(p1, 2, x + width - a2, y + a);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowShadow == 0) break;
+ point(p2, 0, x, y);
+ point(p2, 1, x + width/2, y + height);
+ point(p2, 2, x + width/2, y + height - a3);
+ point(p2, 3, x + a2, y + a);
+
+ point(p3, 0, x + width, y);
+ point(p3, 1, x + width - a2, y + a);
+ point(p3, 2, x + width/2, y + height - a3);
+ point(p3, 3, x + width/2, y + height);
+
+ point(p4, 0, x, y);
+ point(p4, 1, x + a2, y + a);
+ point(p4, 2, x + width - a2, y + a);
+ point(p4, 3, x + width, y);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfRight:
+ a2 = (1.0 + 0.83*width/height) * a;
+ a3 = (1.0 + 0.71*height/width) * a;
+ point(p1, 0, x + width - ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow, y + height/2);
+ point(p1, 1, x + ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow, y + ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow);
+ point(p1, 2, x + ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow, y + height - ((XfwfArrowWidget)self)->xfwfArrow.arrowShadow);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if (((XfwfArrowWidget)self)->xfwfArrow.arrowShadow == 0) break;
+ point(p2, 0, x, y + height);
+ point(p2, 1, x + width, y + height/2);
+ point(p2, 2, x + width - a2, y + height/2);
+ point(p2, 3, x + a, y + height - a3);
+
+ point(p3, 0, x, y);
+ point(p3, 1, x + a, y + a3);
+ point(p3, 2, x + width - a2, y + height/2);
+ point(p3, 3, x + width, y + height/2);
+
+ point(p4, 0, x, y);
+ point(p4, 1, x, y + height);
+ point(p4, 2, x + a, y + height - a3);
+ point(p4, 3, x + a, y + a3);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), ((XfwfArrowWidget)self)->core.window, ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ }
+ if (region != NULL) {
+ XSetClipMask(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowgc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowlightgc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfArrowWidget)self)->xfwfArrow.arrowdarkgc, None);
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Arrow.h b/vendor/x11iraf/obm/ObmW/Arrow.h
new file mode 100644
index 00000000..c6a2442b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Arrow.h
@@ -0,0 +1,70 @@
+/* Generated by wbuild from "Arrow.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfArrow_H_
+#define _XfwfArrow_H_
+#include "Board.h"
+#ifndef XtNdirection
+#define XtNdirection "direction"
+#endif
+#ifndef XtCDirection
+#define XtCDirection "Direction"
+#endif
+#ifndef XtRAlignment
+#define XtRAlignment "Alignment"
+#endif
+
+#ifndef XtNforeground
+#define XtNforeground "foreground"
+#endif
+#ifndef XtCForeground
+#define XtCForeground "Foreground"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNarrowShadow
+#define XtNarrowShadow "arrowShadow"
+#endif
+#ifndef XtCArrowShadow
+#define XtCArrowShadow "ArrowShadow"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNinitialDelay
+#define XtNinitialDelay "initialDelay"
+#endif
+#ifndef XtCInitialDelay
+#define XtCInitialDelay "InitialDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNrepeatDelay
+#define XtNrepeatDelay "repeatDelay"
+#endif
+#ifndef XtCRepeatDelay
+#define XtCRepeatDelay "RepeatDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNcallback
+#define XtNcallback "callback"
+#endif
+#ifndef XtCCallback
+#define XtCCallback "Callback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+typedef struct _XfwfArrowClassRec *XfwfArrowWidgetClass;
+typedef struct _XfwfArrowRec *XfwfArrowWidget;
+externalref WidgetClass xfwfArrowWidgetClass;
+#endif /*_XfwfArrow_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Arrow.man b/vendor/x11iraf/obm/ObmW/Arrow.man
new file mode 100644
index 00000000..d8a7361e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Arrow.man
@@ -0,0 +1,680 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfArrow
+.SH DESCRIPTION
+The Arrow widget is usually part of a composite scrollbar widget. It
+draws a triangle pointing up, down, left or right, depending on the
+\fIdirection\fP resource. It has a single callback, that is repeatedly
+called as long as a mouse button -- button 1 by default -- is pressed.
+
+The triangle has a 3D shadow, the size of which can be controlled with
+a resource. The shadow is either stippled or colored, depending on the
+\fIshadowScheme\fP and associated resources (see the XfwfFrame widget).
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfArrow
+Name Class Type Default
+XtNdirection XtCDirection Alignment XfwfTop
+XtNforeground XtCForeground Pixel XtDefaultBackground
+XtNarrowShadow XtCArrowShadow Dimension 2
+XtNinitialDelay XtCInitialDelay Cardinal 500
+XtNrepeatDelay XtCRepeatDelay Cardinal 200
+XtNcallback XtCCallback Callback NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNdirection"
+The direction of the arrow (triangle) is given by the \fIdirection\fP
+resource, which is of type \fIAlignment\fP. Only \fI"top"\fP (\fIXfwfTop\fP),
+\fI"bottom"\fP (\fIXfwfBottom\fP), \fI"left"\fP (\fIXfwfLeft\fP) and \fI"right"\fP
+(\fIXfwfRight\fP) are valid directions. Other directions result in a
+warning.
+
+.hi
+
+.nf
+Alignment direction = XfwfTop
+.fi
+
+.eh
+
+.TP
+.I "XtNforeground"
+The color of the arrow also determines the color of the 3D shadow,
+at least if \fIshadowScheme\fP is set to \fIXfwfAuto\fP, as it is by default.
+
+.hi
+
+.nf
+Pixel foreground = <String>XtDefaultBackground
+.fi
+
+.eh
+
+.TP
+.I "XtNarrowShadow"
+The width of the arrow's shadow is by default 2 pixels.
+
+.hi
+
+.nf
+Dimension arrowShadow = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNinitialDelay"
+When the user presses and then holds the mouse button, the action
+function waits some milliseconds before it starts repeating the
+callbacks.
+
+.hi
+
+.nf
+Cardinal initialDelay = 500
+.fi
+
+.eh
+
+.TP
+.I "XtNrepeatDelay"
+Between repeated calls to the callback routines, the arrow widget
+will wait a few milliseconds.
+
+.hi
+
+.nf
+Cardinal repeatDelay = 200
+.fi
+
+.eh
+
+.TP
+.I "XtNcallback"
+The \fIcallback\fP function is called by the \fIactivate\fP action. It is
+called repeatedly until the mouse button that triggered the action is
+released again.
+
+.hi
+
+.nf
+<Callback> XtCallbackList callback = NULL
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Translations"
+
+.nf
+<Btn1Down>: activate_and_start_timer()
+.fi
+
+.nf
+<Btn1Up>: stop_timer()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "activate_and_start_timer
+
+The \fIactivate\fP action calls the \fIcallback\fP routine once and installs
+a timeout routine.
+
+.hi
+
+.nf
+void activate_and_start_timer($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if (event->type != ButtonPress) {
+ XtWarning("The Arrow activate action isn't bound to a BtnDown event");
+ return;
+ }
+ XtCallCallbackList($, $callback, NULL);
+ $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($),
+ $initialDelay, timer_callback, $);
+}
+.fi
+
+.eh
+
+.TP
+.I "stop_timer
+
+.hi
+
+.nf
+void stop_timer($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XtRemoveTimeOut($timer);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+The stipple for the shadows are loaded from a bitmap file.
+
+.nf
+
+.B incl
+ "stip4.bm"
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <assert.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The three GC's are used for drawing the arrow and its shadows.
+
+.nf
+GC arrowgc
+.fi
+
+.nf
+GC arrowlightgc
+.fi
+
+.nf
+GC arrowdarkgc
+.fi
+
+The repeating callback is implemented with a time out routine. The
+timer is a private variable of the widget.
+
+.nf
+XtIntervalId timer
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The \fIinitialize\fP method sets initial values for the three GC's and
+checks the \fIdirection\fP resource.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($direction != XfwfTop $direction != XfwfLeft
+ $direction != XfwfRight $direction != XfwfBottom) {
+ XtWarning("direction of Arrow widget incorrect; set to `top'");
+ $direction = XfwfTop;
+ }
+ $arrowgc = NULL; create_arrowgc($);
+ $arrowlightgc = NULL; create_arrowlightgc($);
+ $arrowdarkgc = NULL; create_arrowdarkgc($);
+}
+.fi
+
+When the \fIforeground\fP, \fIarrowShadow\fP or \fIdirection\fP resource changes,
+the widget has to be redrawn. Like in the \fIinitialize\fP method, the
+\fIdirection\fP resource needs to be checked for valid values.
+
+If the inherited resource \fIshadowScheme\fP or one of its family changes, new
+GC's need to be created.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redisplay = False;
+
+ if ($direction != XfwfTop $direction != XfwfLeft
+ $direction != XfwfRight $direction != XfwfBottom) {
+ XtWarning("direction of Arrow widget incorrect; set to `top'");
+ $direction = XfwfTop;
+ }
+ if ($old$direction != $direction)
+ need_redisplay = True;
+ if ($old$foreground != $foreground) {
+ create_arrowgc($);
+ need_redisplay = True;
+ }
+ if ($old$arrowShadow != $arrowShadow)
+ need_redisplay = True;
+ if ($shadowScheme != $old$shadowScheme) {
+ create_arrowdarkgc($);
+ create_arrowlightgc($);
+ need_redisplay = True;
+ } else if ($shadowScheme == XfwfColor) {
+ if ($topShadowColor != $old$topShadowColor) {
+ create_arrowlightgc($);
+ need_redisplay = True;
+ }
+ if ($bottomShadowColor != $old$bottomShadowColor) {
+ create_arrowdarkgc($);
+ need_redisplay = True;
+ }
+ } else if ($shadowScheme = XfwfStipple) {
+ if ($topShadowStipple != $old$topShadowStipple) {
+ create_arrowlightgc($);
+ need_redisplay = True;
+ }
+ if ($bottomShadowStipple != $old$bottomShadowStipple) {
+ create_arrowdarkgc($);
+ need_redisplay = True;
+ }
+ }
+ return need_redisplay;
+}
+.fi
+
+The arrow is drawn as large as possible. The arrow is actually a triangle
+with 3D shadows. \fIp1\fP is the triangle itself, \fIp2\fP, \fIp3\fP and \fIp4\fP are the
+shadows.
+
+\fBdef\fP point(p, i, xx, yy) =
+(p[i ].x =xx ),(p[i ].y =yy )
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ XPoint p1[3], p2[4], p3[4], p4[4];
+ Position x, y;
+ Dimension width, height, a, a2, a3;
+
+ assert($direction == XfwfTop || $direction == XfwfLeft
+ || $direction == XfwfRight || $direction == XfwfBottom);
+
+ if (! XtIsRealized($)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay($), $arrowgc, region);
+ XSetRegion(XtDisplay($), $arrowlightgc, region);
+ XSetRegion(XtDisplay($), $arrowdarkgc, region);
+ }
+ $compute_inside($, x, y, width, height);
+ a = $arrowShadow;
+ switch ($direction) {
+ case XfwfTop:
+ a2 = (1.0 + 0.71*width/height) * a;
+ a3 = (1.0 + 0.83*height/width) * a;
+ point(p1, 0, x + width/2, y + a3);
+ point(p1, 1, x + a2, y + height - a);
+ point(p1, 2, x + width - a2, y + height - a);
+ XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if (a == 0) break;
+ point(p2, 0, x + width/2, y);
+ point(p2, 1, x + width/2, y + a3);
+ point(p2, 2, x + width - a2, y + height - a);
+ point(p2, 3, x + width, y + height);
+
+ point(p3, 0, x + a2, y + height - a);
+ point(p3, 1, x, y + height);
+ point(p3, 2, x + width, y + height);
+ point(p3, 3, x + width - a2, y + height - a);
+
+ point(p4, 0, x + width/2, y);
+ point(p4, 1, x, y + height);
+ point(p4, 2, x + a2, y + height - a);
+ point(p4, 3, x + width/2, y + a3);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfLeft:
+ a2 = (1.0 + 0.83*width/height) * a;
+ a3 = (1.0 + 0.71*height/width) * a;
+ point(p1, 0, x + a2, y + height/2);
+ point(p1, 1, x + width - a, y + a3);
+ point(p1, 2, x + width - a, y + height - a3);
+ XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if ($arrowShadow == 0) break;
+ point(p2, 0, x + width, y);
+ point(p2, 1, x, y + height/2);
+ point(p2, 2, x + a2, y + height/2);
+ point(p2, 3, x + width - a, y + a3);
+
+ point(p3, 0, x, y + height/2);
+ point(p3, 1, x + width, y + height);
+ point(p3, 2, x + width - a, y + height - a3);
+ point(p3, 3, x + a2, y + height/2);
+
+ point(p4, 0, x + width, y);
+ point(p4, 1, x + width - a, y + a3);
+ point(p4, 2, x + width - a, y + height - a3);
+ point(p4, 3, x + width, y + height);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfBottom:
+ a2 = (1.0 + 0.71*width/height) * a;
+ a3 = (1.0 + 0.83*height/width) * a;
+ point(p1, 0, x + width/2, y + height - a3);
+ point(p1, 1, x + a2, y + a);
+ point(p1, 2, x + width - a2, y + a);
+ XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if ($arrowShadow == 0) break;
+ point(p2, 0, x, y);
+ point(p2, 1, x + width/2, y + height);
+ point(p2, 2, x + width/2, y + height - a3);
+ point(p2, 3, x + a2, y + a);
+
+ point(p3, 0, x + width, y);
+ point(p3, 1, x + width - a2, y + a);
+ point(p3, 2, x + width/2, y + height - a3);
+ point(p3, 3, x + width/2, y + height);
+
+ point(p4, 0, x, y);
+ point(p4, 1, x + a2, y + a);
+ point(p4, 2, x + width - a2, y + a);
+ point(p4, 3, x + width, y);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ case XfwfRight:
+ a2 = (1.0 + 0.83*width/height) * a;
+ a3 = (1.0 + 0.71*height/width) * a;
+ point(p1, 0, x + width - $arrowShadow, y + height/2);
+ point(p1, 1, x + $arrowShadow, y + $arrowShadow);
+ point(p1, 2, x + $arrowShadow, y + height - $arrowShadow);
+ XFillPolygon(XtDisplay($), $window, $arrowgc, p1, 3, Convex,
+ CoordModeOrigin);
+ if ($arrowShadow == 0) break;
+ point(p2, 0, x, y + height);
+ point(p2, 1, x + width, y + height/2);
+ point(p2, 2, x + width - a2, y + height/2);
+ point(p2, 3, x + a, y + height - a3);
+
+ point(p3, 0, x, y);
+ point(p3, 1, x + a, y + a3);
+ point(p3, 2, x + width - a2, y + height/2);
+ point(p3, 3, x + width, y + height/2);
+
+ point(p4, 0, x, y);
+ point(p4, 1, x, y + height);
+ point(p4, 2, x + a, y + height - a3);
+ point(p4, 3, x + a, y + a3);
+ XFillPolygon(XtDisplay($), $window, $arrowdarkgc, p2, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p3, 4, Convex,
+ CoordModeOrigin);
+ XFillPolygon(XtDisplay($), $window, $arrowlightgc, p4, 4, Convex,
+ CoordModeOrigin);
+ break;
+ }
+ if (region != NULL) {
+ XSetClipMask(XtDisplay($), $arrowgc, None);
+ XSetClipMask(XtDisplay($), $arrowlightgc, None);
+ XSetClipMask(XtDisplay($), $arrowdarkgc, None);
+ }
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The time-out calls the \fItimer_callback\fP routine. The routine
+re-installs the time-out and calls the \fIcallback\fP function (but in the
+reverse order, because we do not want time-outs to overtake each
+other). The delay is now \fIrepeatDelay\fP instead of \fIinitialDelay\fP.
+
+.nf
+timer_callback(XtPointer client_data, XtIntervalId * timer)
+{
+ Widget $ = (Widget) client_data;
+
+ XtCallCallbackList($, $callback, NULL);
+ $timer = XtAppAddTimeOut(XtWidgetToApplicationContext($),
+ $repeatDelay, timer_callback, $);
+}
+.fi
+
+The GC for the triangle is created by a utility function. It destroys the
+old GC and then creates a new one, based on the \fIforeground\fP resource.
+
+.nf
+create_arrowgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($arrowgc != NULL) XtReleaseGC($, $arrowgc);
+ mask = GCForeground;
+ values.foreground = $foreground;
+ $arrowgc = XtGetGC($, mask, values);
+}
+.fi
+
+The GC for the light shadow is dependent on the inherited \fIshadowScheme\fP
+resource. It is the same routine as for the shadows in the XfwfFrame widget.
+
+.nf
+create_arrowlightgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($arrowlightgc != NULL) XtReleaseGC($, $arrowlightgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $background_pixel;
+ values.stipple = $topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $lighter_color($, $foreground, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $foreground;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ $arrowlightgc = XtGetGC($, mask, values);
+}
+.fi
+
+The routine for the dark part of the shadow is analogous.
+
+.nf
+create_arrowdarkgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($arrowdarkgc != NULL) XtReleaseGC($, $arrowdarkgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = $bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen($));
+ values.background = $background_pixel;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $darker_color($, $foreground, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $foreground;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ $arrowdarkgc = XtGetGC($, mask, values);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/ArrowP.h b/vendor/x11iraf/obm/ObmW/ArrowP.h
new file mode 100644
index 00000000..95162708
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ArrowP.h
@@ -0,0 +1,51 @@
+/* Generated by wbuild from "Arrow.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfArrowP_H_
+#define _XfwfArrowP_H_
+#include "BoardP.h"
+#include "Arrow.h"
+typedef struct {
+/* methods */
+#define point(p, i, xx, yy) (p[i ].x =xx ),(p[i ].y =yy )
+
+
+/* class variables */
+int dummy;
+} XfwfArrowClassPart;
+typedef struct _XfwfArrowClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfArrowClassPart xfwfArrow_class;
+} XfwfArrowClassRec;
+
+typedef struct {
+/* resources */
+Alignment direction;
+Pixel foreground;
+Dimension arrowShadow;
+Cardinal initialDelay;
+Cardinal repeatDelay;
+XtCallbackList callback;
+/* private state */
+GC arrowgc;
+GC arrowlightgc;
+GC arrowdarkgc;
+XtIntervalId timer;
+} XfwfArrowPart;
+
+typedef struct _XfwfArrowRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfArrowPart xfwfArrow;
+} XfwfArrowRec;
+
+externalref XfwfArrowClassRec xfwfArrowClassRec;
+
+#endif /* _XfwfArrowP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Board.c b/vendor/x11iraf/obm/ObmW/Board.c
new file mode 100644
index 00000000..b6182234
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Board.c
@@ -0,0 +1,393 @@
+/* Generated by wbuild from "Board.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Shell.h>
+#include "BoardP.h"
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void set_abs_location(
+#if NeedFunctionPrototypes
+Widget,unsigned int ,int ,int ,int ,int
+#endif
+);
+static void resize(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static XtGeometryResult query_geometry(
+#if NeedFunctionPrototypes
+Widget,XtWidgetGeometry *,XtWidgetGeometry *
+#endif
+);
+static XtGeometryResult geometry_manager(
+#if NeedFunctionPrototypes
+Widget ,XtWidgetGeometry *,XtWidgetGeometry *
+#endif
+);
+static void change_managed(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define ceil(r) (-(int )(-(r )))
+
+
+static void generate_location(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void get_core_geometry(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+static void set_location(
+#if NeedFunctionPrototypes
+Widget,unsigned int
+#endif
+);
+#define skip_blanks(s) while (isspace (*s ))s ++
+
+
+static char * scan(
+#if NeedFunctionPrototypes
+char *,Position *,float *
+#endif
+);
+static void interpret_location(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void generate_location(self)Widget self;
+{
+ char tmp[100];
+
+ (void) sprintf(tmp, "%d+%f %d+%f %d+%f %d+%f",
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_x, ((XfwfBoardWidget)self)->xfwfBoard.rel_x, ((XfwfBoardWidget)self)->xfwfBoard.abs_y, ((XfwfBoardWidget)self)->xfwfBoard.rel_y, ((XfwfBoardWidget)self)->xfwfBoard.abs_width, ((XfwfBoardWidget)self)->xfwfBoard.rel_width,
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_height, ((XfwfBoardWidget)self)->xfwfBoard.rel_height);
+ XtFree(((XfwfBoardWidget)self)->xfwfBoard.location);
+ ((XfwfBoardWidget)self)->xfwfBoard.location = XtNewString(tmp);
+}
+/*ARGSUSED*/static void get_core_geometry(self,x,y,width,height)Widget self;Position * x;Position * y;Dimension * width;Dimension * height;
+{
+ Widget parent;
+ Position px, py;
+ Dimension pw, ph;
+ float h;
+
+ parent = ((XfwfBoardWidget)self)->core.parent;
+ if (XtIsSubclass(((XfwfBoardWidget)self)->core.parent, xfwfBoardWidgetClass))
+ ((XfwfBoardWidgetClass)parent->core.widget_class)->xfwfCommon_class.compute_inside(parent, &px, &py, &pw, &ph);
+ else {
+ px = 0;
+ py = 0;
+ pw = ((XfwfBoardWidget)parent)->core.width;
+ ph = ((XfwfBoardWidget)parent)->core.height;
+ }
+
+ *x = ceil(((XfwfBoardWidget)self)->xfwfBoard.rel_x * pw + ((XfwfBoardWidget)self)->xfwfBoard.abs_x * ((XfwfBoardWidget)self)->xfwfBoard.hunit) + px;
+ *y = ceil(((XfwfBoardWidget)self)->xfwfBoard.rel_y * ph + ((XfwfBoardWidget)self)->xfwfBoard.abs_y * ((XfwfBoardWidget)self)->xfwfBoard.vunit) + py;
+ h = ceil(((XfwfBoardWidget)self)->xfwfBoard.rel_width * pw + ((XfwfBoardWidget)self)->xfwfBoard.abs_width * ((XfwfBoardWidget)self)->xfwfBoard.hunit);
+ *width = h < 1.0 ? 1 : h;
+ h = ceil(((XfwfBoardWidget)self)->xfwfBoard.rel_height * ph + ((XfwfBoardWidget)self)->xfwfBoard.abs_height * ((XfwfBoardWidget)self)->xfwfBoard.vunit);
+ *height = h < 1.0 ? 1 : h;
+}
+/*ARGSUSED*/static void set_location(self,flags)Widget self;unsigned int flags;
+{
+ Widget parent;
+ Position px, py;
+ Dimension pw, ph;
+
+ parent = ((XfwfBoardWidget)self)->core.parent;
+ if (XtIsSubclass(((XfwfBoardWidget)self)->core.parent, xfwfBoardWidgetClass))
+ ((XfwfBoardWidgetClass)parent->core.widget_class)->xfwfCommon_class.compute_inside(parent, &px, &py, &pw, &ph);
+ else {
+ px = 0;
+ py = 0;
+ pw = ((XfwfBoardWidget)parent)->core.width;
+ ph = ((XfwfBoardWidget)parent)->core.height;
+ }
+ if (flags & CWX) {
+ ((XfwfBoardWidget)self)->xfwfBoard.rel_x = 0.0;
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_x = ceil((((XfwfBoardWidget)self)->core.x - px)/((XfwfBoardWidget)self)->xfwfBoard.hunit);
+ }
+ if (flags & CWY) {
+ ((XfwfBoardWidget)self)->xfwfBoard.rel_y = 0.0;
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_y = ceil((((XfwfBoardWidget)self)->core.y - py)/((XfwfBoardWidget)self)->xfwfBoard.vunit);
+ }
+ if (flags & CWWidth) {
+ ((XfwfBoardWidget)self)->xfwfBoard.rel_width = 0.0;
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_width = ceil(((XfwfBoardWidget)self)->core.width/((XfwfBoardWidget)self)->xfwfBoard.hunit);
+ }
+ if (flags & CWHeight) {
+ ((XfwfBoardWidget)self)->xfwfBoard.rel_height = 0.0;
+ ((XfwfBoardWidget)self)->xfwfBoard.abs_height = ceil(((XfwfBoardWidget)self)->core.height/((XfwfBoardWidget)self)->xfwfBoard.vunit);
+ }
+}
+/*ARGSUSED*/static char * scan(s,absval,relval)char * s;Position * absval;float * relval;
+{
+ Position n;
+ char *t;
+ Boolean minus;
+ extern double strtod();
+
+ *absval = 0;
+ *relval = 0.0;
+ n = strtol(s, &t, 0);
+ if (*t != '.') { /* Found an integer */
+ *absval = n;
+ s = t;
+ skip_blanks(s);
+ if (*s != '+' && *s != '-') return s; /* Nothing follows */
+ n = strtol(s + 1, &t, 0);
+ if (*t != '.') return s; /* It's not a float */
+ minus = (*s == '-');
+ *relval = (float) strtod(s + 1, &s); /* Found a float */
+ if (minus) *relval = - *relval;
+ return s;
+ } else { /* Found a float */
+ *relval = (float) strtod(s, &s);
+ skip_blanks(s);
+ if (*s != '+' && *s != '-') return s; /* Nothing follows */
+ n = strtol(s + 1, &t, 0);
+ if (*t == '.') return s; /* It's not an integer */
+ if (*s == '-') *absval = -n; else *absval = n;
+ return t;
+ }
+}
+/*ARGSUSED*/static void interpret_location(self)Widget self;
+{
+ char *s, *t;
+
+ s = ((XfwfBoardWidget)self)->xfwfBoard.location;
+ s = scan(s, &((XfwfBoardWidget)self)->xfwfBoard.abs_x, &((XfwfBoardWidget)self)->xfwfBoard.rel_x);
+ s = scan(s, &((XfwfBoardWidget)self)->xfwfBoard.abs_y, &((XfwfBoardWidget)self)->xfwfBoard.rel_y);
+ s = scan(s, &((XfwfBoardWidget)self)->xfwfBoard.abs_width, &((XfwfBoardWidget)self)->xfwfBoard.rel_width);
+ s = scan(s, &((XfwfBoardWidget)self)->xfwfBoard.abs_height, &((XfwfBoardWidget)self)->xfwfBoard.rel_height);
+}
+
+static XtResource resources[] = {
+{XtNabs_x,XtCAbs_x,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.abs_x),XtOffsetOf(XfwfBoardRec,xfwfBoard.abs_x),XtRImmediate,(XtPointer)0 },
+{XtNrel_x,XtCRel_x,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.rel_x),XtOffsetOf(XfwfBoardRec,xfwfBoard.rel_x),XtRString,(XtPointer)"0.0"},
+{XtNabs_y,XtCAbs_y,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.abs_y),XtOffsetOf(XfwfBoardRec,xfwfBoard.abs_y),XtRImmediate,(XtPointer)0 },
+{XtNrel_y,XtCRel_y,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.rel_y),XtOffsetOf(XfwfBoardRec,xfwfBoard.rel_y),XtRString,(XtPointer)"0.0"},
+{XtNx,XtCX,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->core.x),XtOffsetOf(XfwfBoardRec,core.x),XtRImmediate,(XtPointer)MAGICNUM },
+{XtNy,XtCY,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->core.y),XtOffsetOf(XfwfBoardRec,core.y),XtRImmediate,(XtPointer)MAGICNUM },
+{XtNabs_width,XtCAbs_width,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.abs_width),XtOffsetOf(XfwfBoardRec,xfwfBoard.abs_width),XtRImmediate,(XtPointer)0 },
+{XtNrel_width,XtCRel_width,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.rel_width),XtOffsetOf(XfwfBoardRec,xfwfBoard.rel_width),XtRString,(XtPointer)"1.0"},
+{XtNabs_height,XtCAbs_height,XtRPosition,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.abs_height),XtOffsetOf(XfwfBoardRec,xfwfBoard.abs_height),XtRImmediate,(XtPointer)0 },
+{XtNrel_height,XtCRel_height,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.rel_height),XtOffsetOf(XfwfBoardRec,xfwfBoard.rel_height),XtRString,(XtPointer)"1.0"},
+{XtNwidth,XtCWidth,XtRDimension,sizeof(((XfwfBoardRec*)NULL)->core.width),XtOffsetOf(XfwfBoardRec,core.width),XtRImmediate,(XtPointer)MAGICNUM },
+{XtNheight,XtCHeight,XtRDimension,sizeof(((XfwfBoardRec*)NULL)->core.height),XtOffsetOf(XfwfBoardRec,core.height),XtRImmediate,(XtPointer)MAGICNUM },
+{XtNhunit,XtCHunit,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.hunit),XtOffsetOf(XfwfBoardRec,xfwfBoard.hunit),XtRString,(XtPointer)"1.0"},
+{XtNvunit,XtCVunit,XtRFloat,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.vunit),XtOffsetOf(XfwfBoardRec,xfwfBoard.vunit),XtRString,(XtPointer)"1.0"},
+{XtNlocation,XtCLocation,XtRString,sizeof(((XfwfBoardRec*)NULL)->xfwfBoard.location),XtOffsetOf(XfwfBoardRec,xfwfBoard.location),XtRImmediate,(XtPointer)NULL },
+};
+
+XfwfBoardClassRec xfwfBoardClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfFrameClassRec,
+"Board",
+sizeof(XfwfBoardRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+NULL,
+0,
+resources,
+15,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+resize,
+XtInheritExpose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+query_geometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+geometry_manager,
+change_managed,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+set_abs_location,
+},
+};
+WidgetClass xfwfBoardWidgetClass = (WidgetClass) &xfwfBoardClassRec;
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfBoardWidgetClass c = (XfwfBoardWidgetClass) class;
+ XfwfBoardWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (CompositeClassExtensionRec *)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = (XtPointer)ext;
+ if (class == xfwfBoardWidgetClass) return;
+ super = (XfwfBoardWidgetClass)class->core_class.superclass;
+ if (c->xfwfBoard_class.set_abs_location == XtInherit_set_abs_location)
+ c->xfwfBoard_class.set_abs_location = super->xfwfBoard_class.set_abs_location;
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ XtWidgetGeometry reply;
+ int i;
+
+ if (((XfwfBoardWidget)self)->xfwfBoard.location != ((XfwfBoardWidget)old)->xfwfBoard.location) {
+ XtFree(((XfwfBoardWidget)old)->xfwfBoard.location);
+ ((XfwfBoardWidget)self)->xfwfBoard.location = XtNewString(((XfwfBoardWidget)self)->xfwfBoard.location);
+ interpret_location(self);
+ get_core_geometry(self, &((XfwfBoardWidget)self)->core.x, &((XfwfBoardWidget)self)->core.y, &((XfwfBoardWidget)self)->core.width, &((XfwfBoardWidget)self)->core.height);
+ } else if (ceil(((XfwfBoardWidget)self)->xfwfBoard.abs_x*((XfwfBoardWidget)self)->xfwfBoard.hunit) != ceil(((XfwfBoardWidget)old)->xfwfBoard.abs_x*((XfwfBoardWidget)old)->xfwfBoard.hunit)
+ || ceil(((XfwfBoardWidget)self)->xfwfBoard.abs_width*((XfwfBoardWidget)self)->xfwfBoard.hunit) != ceil(((XfwfBoardWidget)old)->xfwfBoard.abs_width*((XfwfBoardWidget)old)->xfwfBoard.hunit)
+ || ceil(((XfwfBoardWidget)self)->xfwfBoard.abs_y*((XfwfBoardWidget)self)->xfwfBoard.vunit) != ceil(((XfwfBoardWidget)old)->xfwfBoard.abs_y*((XfwfBoardWidget)old)->xfwfBoard.vunit)
+ || ceil(((XfwfBoardWidget)self)->xfwfBoard.abs_height*((XfwfBoardWidget)self)->xfwfBoard.vunit) != ceil(((XfwfBoardWidget)old)->xfwfBoard.abs_height*((XfwfBoardWidget)old)->xfwfBoard.vunit)
+ || ((XfwfBoardWidget)self)->xfwfBoard.rel_x != ((XfwfBoardWidget)old)->xfwfBoard.rel_x
+ || ((XfwfBoardWidget)self)->xfwfBoard.rel_y != ((XfwfBoardWidget)old)->xfwfBoard.rel_y
+ || ((XfwfBoardWidget)self)->xfwfBoard.rel_width != ((XfwfBoardWidget)old)->xfwfBoard.rel_width
+ || ((XfwfBoardWidget)self)->xfwfBoard.rel_height != ((XfwfBoardWidget)old)->xfwfBoard.rel_height) {
+ get_core_geometry(self, &((XfwfBoardWidget)self)->core.x, &((XfwfBoardWidget)self)->core.y, &((XfwfBoardWidget)self)->core.width, &((XfwfBoardWidget)self)->core.height);
+ generate_location(self);
+ } else if (((XfwfBoardWidget)self)->core.x != ((XfwfBoardWidget)old)->core.x
+ || ((XfwfBoardWidget)self)->core.y != ((XfwfBoardWidget)old)->core.y
+ || ((XfwfBoardWidget)self)->core.width != ((XfwfBoardWidget)old)->core.width
+ || ((XfwfBoardWidget)self)->core.height != ((XfwfBoardWidget)old)->core.height) {
+ set_location(self, CWX | CWY | CWWidth | CWHeight);
+ generate_location(self);
+ }
+ if (((XfwfBoardWidget)self)->xfwfCommon.highlightThickness + ((XfwfBoardWidget)self)->xfwfFrame.frameWidth + ((XfwfBoardWidget)self)->xfwfFrame.outerOffset + ((XfwfBoardWidget)self)->xfwfFrame.innerOffset
+ != ((XfwfBoardWidget)old)->xfwfCommon.highlightThickness + ((XfwfBoardWidget)old)->xfwfFrame.frameWidth + ((XfwfBoardWidget)old)->xfwfFrame.outerOffset
+ + ((XfwfBoardWidget)self)->xfwfFrame.innerOffset) {
+ for (i = 0; i < ((XfwfBoardWidget)self)->composite.num_children; i++) {
+ (void) XtQueryGeometry(((XfwfBoardWidget)self)->composite.children[i], NULL, &reply);
+ XtConfigureWidget(((XfwfBoardWidget)self)->composite.children[i], reply.x, reply.y, reply.width,
+ reply.height, reply.border_width);
+ }
+ }
+ return False;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfBoardWidget)self)->xfwfBoard.location != NULL) {
+ ((XfwfBoardWidget)self)->xfwfBoard.location = XtNewString(((XfwfBoardWidget)self)->xfwfBoard.location);
+ interpret_location(self);
+ get_core_geometry(self, &((XfwfBoardWidget)self)->core.x, &((XfwfBoardWidget)self)->core.y, &((XfwfBoardWidget)self)->core.width, &((XfwfBoardWidget)self)->core.height);
+ } else if (((XfwfBoardWidget)self)->core.x != MAGICNUM || ((XfwfBoardWidget)self)->core.y != MAGICNUM
+ || ((XfwfBoardWidget)self)->core.width != MAGICNUM || ((XfwfBoardWidget)self)->core.height != MAGICNUM) {
+ set_location(self, CWX | CWY | CWWidth | CWHeight);
+ generate_location(self);
+ } else {
+ generate_location(self);
+ get_core_geometry(self, &((XfwfBoardWidget)self)->core.x, &((XfwfBoardWidget)self)->core.y, &((XfwfBoardWidget)self)->core.width, &((XfwfBoardWidget)self)->core.height);
+ }
+}
+/*ARGSUSED*/static void set_abs_location(self,flags,x,y,w,h)Widget self;unsigned int flags;int x;int y;int w;int h;
+{
+ if (flags & (CWX | CWY | CWWidth | CWHeight) == 0) return;
+ if (flags & CWX) ((XfwfBoardWidget)self)->core.x = x;
+ if (flags & CWY) ((XfwfBoardWidget)self)->core.y = y;
+ if (flags & CWWidth) ((XfwfBoardWidget)self)->core.width = w;
+ if (flags & CWHeight) ((XfwfBoardWidget)self)->core.height = h;
+ set_location(self, flags);
+ generate_location(self);
+}
+/*ARGSUSED*/static void resize(self)Widget self;
+{
+ int i;
+ XtWidgetGeometry reply;
+ Widget child;
+
+ for (i = 0; i < ((XfwfBoardWidget)self)->composite.num_children; i++) {
+ child = ((XfwfBoardWidget)self)->composite.children[i];
+ (void) XtQueryGeometry(child, NULL, &reply);
+ XtConfigureWidget(child, reply.x, reply.y, reply.width,
+ reply.height, reply.border_width);
+ }
+}
+/*ARGSUSED*/static XtGeometryResult query_geometry(self,request,reply)Widget self;XtWidgetGeometry * request;XtWidgetGeometry * reply;
+{
+ reply->request_mode = CWX | CWY | CWWidth | CWHeight;
+ get_core_geometry(self, &reply->x, &reply->y,
+ &reply->width, &reply->height);
+ return XtGeometryAlmost;
+}
+/*ARGSUSED*/static XtGeometryResult geometry_manager(child,request,reply)Widget child;XtWidgetGeometry * request;XtWidgetGeometry * reply;
+{ Widget self = XtParent(child); {
+ Widget self = XtParent(child);
+ Dimension wd, ht, bw;
+ Position x, y;
+
+ /* Get complete geometry, from request or current value */
+ x = request->request_mode & CWX ? request->x : ((XfwfBoardWidget)child)->core.x;
+ y = request->request_mode & CWY ? request->y : ((XfwfBoardWidget)child)->core.y;
+ wd = request->request_mode & CWWidth ? request->width : ((XfwfBoardWidget)child)->core.width;
+ ht = request->request_mode & CWHeight ? request->height : ((XfwfBoardWidget)child)->core.height;
+ bw = request->request_mode & CWBorderWidth ? request->border_width
+ : ((XfwfBoardWidget)child)->core.border_width;
+
+ XtConfigureWidget(child, x, y, wd, ht, bw);
+ return XtGeometryDone;
+}
+}
+/*ARGSUSED*/static void change_managed(self)Widget self;
+{
+ Widget top = self, w;
+
+ while (! XtIsSubclass(top, shellWidgetClass)) top = XtParent(top) ;
+ for (w = self; w != top; w = XtParent(w)) XtInstallAllAccelerators(w, top);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Board.h b/vendor/x11iraf/obm/ObmW/Board.h
new file mode 100644
index 00000000..f38591b4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Board.h
@@ -0,0 +1,120 @@
+/* Generated by wbuild from "Board.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfBoard_H_
+#define _XfwfBoard_H_
+#include "Frame.h"
+#ifndef XtNabs_x
+#define XtNabs_x "abs_x"
+#endif
+#ifndef XtCAbs_x
+#define XtCAbs_x "Abs_x"
+#endif
+#ifndef XtRPosition
+#define XtRPosition "Position"
+#endif
+
+#ifndef XtNrel_x
+#define XtNrel_x "rel_x"
+#endif
+#ifndef XtCRel_x
+#define XtCRel_x "Rel_x"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNabs_y
+#define XtNabs_y "abs_y"
+#endif
+#ifndef XtCAbs_y
+#define XtCAbs_y "Abs_y"
+#endif
+#ifndef XtRPosition
+#define XtRPosition "Position"
+#endif
+
+#ifndef XtNrel_y
+#define XtNrel_y "rel_y"
+#endif
+#ifndef XtCRel_y
+#define XtCRel_y "Rel_y"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNabs_width
+#define XtNabs_width "abs_width"
+#endif
+#ifndef XtCAbs_width
+#define XtCAbs_width "Abs_width"
+#endif
+#ifndef XtRPosition
+#define XtRPosition "Position"
+#endif
+
+#ifndef XtNrel_width
+#define XtNrel_width "rel_width"
+#endif
+#ifndef XtCRel_width
+#define XtCRel_width "Rel_width"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNabs_height
+#define XtNabs_height "abs_height"
+#endif
+#ifndef XtCAbs_height
+#define XtCAbs_height "Abs_height"
+#endif
+#ifndef XtRPosition
+#define XtRPosition "Position"
+#endif
+
+#ifndef XtNrel_height
+#define XtNrel_height "rel_height"
+#endif
+#ifndef XtCRel_height
+#define XtCRel_height "Rel_height"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNhunit
+#define XtNhunit "hunit"
+#endif
+#ifndef XtCHunit
+#define XtCHunit "Hunit"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNvunit
+#define XtNvunit "vunit"
+#endif
+#ifndef XtCVunit
+#define XtCVunit "Vunit"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNlocation
+#define XtNlocation "location"
+#endif
+#ifndef XtCLocation
+#define XtCLocation "Location"
+#endif
+#ifndef XtRString
+#define XtRString "String"
+#endif
+
+typedef struct _XfwfBoardClassRec *XfwfBoardWidgetClass;
+typedef struct _XfwfBoardRec *XfwfBoardWidget;
+externalref WidgetClass xfwfBoardWidgetClass;
+#endif /*_XfwfBoard_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Board.man b/vendor/x11iraf/obm/ObmW/Board.man
new file mode 100644
index 00000000..412e055c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Board.man
@@ -0,0 +1,749 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfBoard
+.SH DESCRIPTION
+The Board class adds one thing to the capabilities already present
+in the Frame class, viz., location management.
+
+Location management is an improved version of the standard X geometry
+management. Size and position of a Board widget (or subclass) can be
+given as a combination of absolute and relative sizes.
+
+In contrast to its superclass Frame, Board accepts any number of
+children. No layout policy is enforced, however. The children are
+expected to be positioned with the help of their own geometry or
+location resources.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+The location management relies on a total of ten resources plus a
+string resource that combines eight of them in a more convenient and
+compact notation. The location is given by two values in each of the
+four dimensions (x, y, width and height). One value holds the absolute
+position in pixels, the other holds the position relative to the
+parent's width. E.g., When \fIabs_x\fP is 20 and \fIrel_x\fP is 0.3, the x
+position of the widget will be 20 pixels plus 0.3 times the width of
+the parent. For more examples, see the \fIlocation\fP resource below.
+
+The ninth and tenth resources are \fIhunit\fP and \fIvunit\fP. All assignments
+to the \fIabs_*\fP resources are multiplied by \fIhunit\fP (horizontal) or
+\fIvunit\fP (vertical). Normally the units are 1, but, e.g., a widget that
+displays text might set them to the width and height of character
+cells, so that \fIabs_width = 80\fP means a width of 80 characters,
+instead of 80 pixels.
+
+The geometry resources of the Core widget (\fIx\fP, \fIy\fP, \fIwidth\fP and
+\fIheight\fP are still available. When they are set, the values are
+copied to the \fIabs_*\fP variables and the \fIrel_*\fP variables are set to
+0.0.
+
+It is possible that the parent of the current widget doesn't grant the
+preferred geometry. In that case the location variables and the geometry
+variables will not be synchronized. The location variables will then be
+taken to hold the preferred geometry, instead of the actual one.
+
+.TP
+.I "XtNabs_x"
+The position is determined by the four resources \fIabs_x\fP, \fIrel_x\fP,
+\fIabs_y\fP and \fIrel_y\fP. When the parent is (a subclass of) a Board
+widget, the position is not measured from the real size of the parent,
+but from the size inside the frame.
+
+(The representation of the float values as strings seems necessary,
+because the compiler can't cast a float to a pointer.)
+
+.hi
+
+.nf
+Position abs_x = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNrel_x"
+
+.hi
+
+.nf
+float rel_x = <String>"0.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNabs_y"
+
+.hi
+
+.nf
+Position abs_y = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNrel_y"
+
+.hi
+
+.nf
+float rel_y = <String>"0.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNMAGICNUM"
+By setting default values for the \fIx\fP and \fIy\fP variables from Core
+explicitly, we can be sure that the variables are synchronized from the
+start. If the \fIinitialize\fP method detects a change in any of them, it can
+re-synchronize them.
+
+.hi
+
+.nf
+ MAGICNUM =
+.fi
+
+.eh
+
+.TP
+.I "XtNx"
+
+.hi
+
+.nf
+ x = MAGICNUM
+.fi
+
+.eh
+
+.TP
+.I "XtNy"
+
+.hi
+
+.nf
+ y = MAGICNUM
+.fi
+
+.eh
+
+.TP
+.I "XtNabs_width"
+The default values cause a Board widget to be the same size as it's
+parent at all times, provided, of course, that the parent allows that.
+If the parent is (a subclass of) a Board widget, the size is relative
+to the area inside the parent's frame, instead of the total size of
+the parent.
+
+.hi
+
+.nf
+Position abs_width = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNrel_width"
+
+.hi
+
+.nf
+float rel_width = <String>"1.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNabs_height"
+
+.hi
+
+.nf
+Position abs_height = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNrel_height"
+
+.hi
+
+.nf
+float rel_height = <String>"1.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNwidth"
+The Core variables are given strange defaults, in the hope that the
+\fIinitialize\fP method can detect a change in them.
+
+.hi
+
+.nf
+ width = MAGICNUM
+.fi
+
+.eh
+
+.TP
+.I "XtNheight"
+
+.hi
+
+.nf
+ height = MAGICNUM
+.fi
+
+.eh
+
+.TP
+.I "XtNhunit"
+\fIhunit\fP is a value in pixels by which \fIabs_x\fP and \fIabs_width\fP are
+multiplied; \fIabs_y\fP and \fIabs_height\fP are multiplied by \fIvunit\fP. The
+results are rounded to the next larger whole number.
+
+.hi
+
+.nf
+float hunit = <String>"1.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNvunit"
+
+.hi
+
+.nf
+float vunit = <String>"1.0"
+.fi
+
+.eh
+
+.TP
+.I "XtNlocation"
+Specifying eight resources in a resource file is more easily done
+with the string resource \fIlocation\fP. The string contains four
+expressions of the form $x_a\pm x_r$ or $x_r\pm x_a$ or $x_a$ or
+$x_r$, where $x_a$ is the absolute value and $x_r$ is the relative
+value. The two are distinguished by the fact that $x_r$ {\em must}
+contain a decimal point.
+
+Examples: \fI"0.5 - 20 5 40 1.0 - 50"\fP is a widget of fixed width (40
+units) that is horizontally centered; the height is always 50 units
+less than the height of the parent.
+
+\fI"0 0 2.0 3.0"\fP is a widget that is twice as wide and three times as
+high as its parent.
+
+\fI"-20 0 20 20"\fP is a widget that will be invisible, because it is
+located 20 units to the left of the parent and it is also 20 units
+wide.
+
+The initial value is \fINULL\fP, but the \fIinitialize\fP method will make sure
+that the string is synchronized with the other variables.
+
+.hi
+
+.nf
+String location = NULL
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <stdlib.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Shell.h>
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+Changes in the location resources result in changes in the core
+geometry resources. If the location resources didn't change, but the
+core geometry resources did, the location variables are set
+accordingly. If various resources are changes at the same time,
+\fIlocation\fP takes precedence, followed by the \fIabs_*\fP and \fIrel_*\fP
+variables, and finally the core geometry variables \fIx\fP, \fIy\fP, \fIwidth\fP
+and \fIheight\fP.
+
+\fIset_values\fP takes care that all these resources always correspond to
+each other; even the \fIlocation\fP string is re-generated when any of the
+others change.
+
+Since the location is handled by setting the core geometry resources,
+there is never any need to redraw the widget.
+
+A complication arises when the frame of the Board widget changes,
+since children may have sizes that are relative to the area inside the
+frame. The Board widget therefore gives its children a chance to
+calculate their new locations in this case.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ XtWidgetGeometry reply;
+ int i;
+
+ if ($location != $old$location) {
+ XtFree($old$location);
+ $location = XtNewString($location);
+ interpret_location($);
+ get_core_geometry($, $x, $y, $width, $height);
+ } else if (ceil($abs_x*$hunit) != ceil($old$abs_x*$old$hunit)
+ || ceil($abs_width*$hunit) != ceil($old$abs_width*$old$hunit)
+ || ceil($abs_y*$vunit) != ceil($old$abs_y*$old$vunit)
+ || ceil($abs_height*$vunit) != ceil($old$abs_height*$old$vunit)
+ || $rel_x != $old$rel_x
+ || $rel_y != $old$rel_y
+ || $rel_width != $old$rel_width
+ || $rel_height != $old$rel_height) {
+ get_core_geometry($, $x, $y, $width, $height);
+ generate_location($);
+ } else if ($x != $old$x
+ || $y != $old$y
+ || $width != $old$width
+ || $height != $old$height) {
+ set_location($, CWX | CWY | CWWidth | CWHeight);
+ generate_location($);
+ }
+ if ($highlightThickness + $frameWidth + $outerOffset + $innerOffset
+ != $old$highlightThickness + $old$frameWidth + $old$outerOffset
+ + $innerOffset) {
+ for (i = 0; i < $num_children; i++) {
+ (void) XtQueryGeometry($children[i], NULL, reply);
+ XtConfigureWidget($children[i], reply.x, reply.y, reply.width,
+ reply.height, reply.border_width);
+ }
+ }
+ return False;
+}
+.fi
+
+The initialize method is used to synchronize the location and geometry
+resources for the first time. It is difficult to find out which variables
+have been set from resources and which still have their initial value, we
+rely on the fact that the default value is unlikely to be used in
+practice.
+
+If the \fIlocation\fP string has been set, it will be used to set all other
+variables. If the Core geometry resources have been set, we use them,
+otherwise, the location variables will determine the size and position.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($location != NULL) {
+ $location = XtNewString($location);
+ interpret_location($);
+ get_core_geometry($, $x, $y, $width, $height);
+ } else if ($x != MAGICNUM || $y != MAGICNUM
+ || $width != MAGICNUM || $height != MAGICNUM) {
+ set_location($, CWX | CWY | CWWidth | CWHeight);
+ generate_location($);
+ } else {
+ generate_location($);
+ get_core_geometry($, $x, $y, $width, $height);
+ }
+}
+.fi
+
+The \fIset_abs_location\fP method is a convenience function for use by
+subclasses. When they want to set the \fIx\fP, \fIy\fP, \fIwidth\fP or \fIheight\fP
+resources, they can call this function which will than also adjust the
+other location resources accordingly. The flags determine which
+resources are set, it is a bitwise combination of \fICWX\fP, \fICWY\fP,
+\fICWWidth\fP and \fICWHeight\fP.
+
+.nf
+set_abs_location($, unsigned int flags, int x, int y, int w, int h)
+{
+ if (flags (CWX | CWY | CWWidth | CWHeight) == 0) return;
+ if (flags CWX) $x = x;
+ if (flags CWY) $y = y;
+ if (flags CWWidth) $width = w;
+ if (flags CWHeight) $height = h;
+ set_location($, flags);
+ generate_location($);
+}
+.fi
+
+The \fIresize\fP method is called when the widget is resized. The children
+of the Board widget will be given a chance to re-compute their preferred
+locations, which will then be granted them. It may be possible that the
+parent of the current widget didn't grant the preferred geometry. In that
+case the geometry variables will be different from the location variables.
+The latter will not be changed, in the hope that the requested geometry
+can be set later.
+
+.nf
+resize($)
+{
+ int i;
+ XtWidgetGeometry reply;
+ Widget child;
+
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ (void) XtQueryGeometry(child, NULL, reply);
+ XtConfigureWidget(child, reply.x, reply.y, reply.width,
+ reply.height, reply.border_width);
+ }
+}
+.fi
+
+When the Board's parent asks for this widget's preferred geometry,
+simply return the geometry as indicated by the location variables.
+Currently, the method always returns \fIXtGeometryAlmost\fP. It doesn't bother
+to check if the preferred geometry is equal to the current geometry (in
+which case it should really return \fIXtGeometryNo\fP) or if the preferred
+geometry is equal to what the parent proposed (in which case a return of
+\fIXtGeometryYes\fP should have been given.
+
+It seems that no harm is done by always returning \fIXtGeometryAlmost\fP and
+letting Xt figure out what really needs to be changed.
+
+.nf
+XtGeometryResult query_geometry($, XtWidgetGeometry * request, XtWidgetGeometry * reply)
+{
+ reply->request_mode = CWX | CWY | CWWidth | CWHeight;
+ get_core_geometry($, reply->x, reply->y,
+ reply->width, reply->height);
+ return XtGeometryAlmost;
+}
+.fi
+
+If a child requests to be resized, the request is always granted. We
+ignore stacking order.
+
+.nf
+XtGeometryResult geometry_manager(Widget child, XtWidgetGeometry * request, XtWidgetGeometry * reply)
+{
+ Widget $ = XtParent(child);
+ Dimension wd, ht, bw;
+ Position x, y;
+
+ /* Get complete geometry, from request or current value */
+ x = request->request_mode CWX ? request->x : $child$x;
+ y = request->request_mode CWY ? request->y : $child$y;
+ wd = request->request_mode CWWidth ? request->width : $child$width;
+ ht = request->request_mode CWHeight ? request->height : $child$height;
+ bw = request->request_mode CWBorderWidth ? request->border_width
+ : $child$border_width;
+
+ XtConfigureWidget(child, x, y, wd, ht, bw);
+ return XtGeometryDone;
+}
+.fi
+
+If a child becomes managed or unmanaged, the Board widget is given a
+change to resize or reposition the child. The Board widget doesn't do
+that, but it does install all accelerators of its descendants here.
+
+.nf
+change_managed($)
+{
+ Widget top = $, w;
+
+ while (! XtIsSubclass(top, shellWidgetClass)) top = XtParent(top) ;
+ for (w = $; w != top; w = XtParent(w)) XtInstallAllAccelerators(w, top);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+\fBdef\fP ceil(r) =
+(-(int )(-(r )))
+
+The routine \fIgenerate_location\fP creates the string \fIlocation\fP from the
+values of the location resources.
+
+.nf
+generate_location($)
+{
+ char tmp[100];
+
+ (void) sprintf(tmp, "%d+%f %d+%f %d+%f %d+%f",
+ $abs_x, $rel_x, $abs_y, $rel_y, $abs_width, $rel_width,
+ $abs_height, $rel_height);
+ XtFree($location);
+ $location = XtNewString(tmp);
+}
+.fi
+
+To get the core geometry from the location variables, the function
+\fIget_core_geometry\fP is used. It combines the relative and absolute
+parts of the location and sets the result in the passed variables.
+When the parent is a Board widget or a subclass thereof, the area
+inside the parent's frame is used for calculations, otherwise the
+whole area of the parent will be used.
+
+As a safeguard against possible non-positive sizes, the width and
+height cannot become smaller than 1 pixel.
+
+.nf
+get_core_geometry($, Position * x, Position * y, Dimension * width, Dimension * height)
+{
+ Widget parent;
+ Position px, py;
+ Dimension pw, ph;
+ float h;
+
+ parent = $parent;
+ if (XtIsSubclass($parent, xfwfBoardWidgetClass))
+ $parent$compute_inside(parent, px, py, pw, ph);
+ else {
+ px = 0;
+ py = 0;
+ pw = $parent$width;
+ ph = $parent$height;
+ }
+
+ *x = ceil($rel_x * pw + $abs_x * $hunit) + px;
+ *y = ceil($rel_y * ph + $abs_y * $vunit) + py;
+ h = ceil($rel_width * pw + $abs_width * $hunit);
+ *width = h < 1.0 ? 1 : h;
+ h = ceil($rel_height * ph + $abs_height * $vunit);
+ *height = h < 1.0 ? 1 : h;
+}
+.fi
+
+The reverse operation, computing the location variables from the core
+geometry is done by \fIset_location\fP.
+
+.nf
+set_location($, unsigned int flags)
+{
+ Widget parent;
+ Position px, py;
+ Dimension pw, ph;
+
+ parent = $parent;
+ if (XtIsSubclass($parent, xfwfBoardWidgetClass))
+ $parent$compute_inside(parent, px, py, pw, ph);
+ else {
+ px = 0;
+ py = 0;
+ pw = $parent$width;
+ ph = $parent$height;
+ }
+ if (flags CWX) {
+ $rel_x = 0.0;
+ $abs_x = ceil(($x - px)/$hunit);
+ }
+ if (flags CWY) {
+ $rel_y = 0.0;
+ $abs_y = ceil(($y - py)/$vunit);
+ }
+ if (flags CWWidth) {
+ $rel_width = 0.0;
+ $abs_width = ceil($width/$hunit);
+ }
+ if (flags CWHeight) {
+ $rel_height = 0.0;
+ $abs_height = ceil($height/$vunit);
+ }
+}
+.fi
+
+Interpreting the \fIlocation\fP string is a little harder, but still
+straightforward. Only numbers (with or without decimal points) and plus
+and minus signs can appear in the string.
+
+\fIscan\fP recognizes four formats: an integer followed by a plus or minus
+and a float, a float followed by a plus or minus and an integer, a single
+integer, or a single float.
+
+\fBdef\fP skip_blanks(s) =
+while (isspace (*s ))s ++
+
+.nf
+char * scan(char * s, Position * absval, float * relval)
+{
+ Position n;
+ char *t;
+ Boolean minus;
+
+ *absval = 0;
+ *relval = 0.0;
+ n = strtol(s, t, 0);
+ if (*t != '.') { /* Found an integer */
+ *absval = n;
+ s = t;
+ skip_blanks(s);
+ if (*s != '+' *s != '-') return s; /* Nothing follows */
+ n = strtol(s + 1, t, 0);
+ if (*t != '.') return s; /* It's not a float */
+ minus = (*s == '-');
+ *relval = strtod(s + 1, s); /* Found a float */
+ if (minus) *relval = - *relval;
+ return s;
+ } else { /* Found a float */
+ *relval = strtod(s, s);
+ skip_blanks(s);
+ if (*s != '+' *s != '-') return s; /* Nothing follows */
+ n = strtol(s + 1, t, 0);
+ if (*t == '.') return s; /* It's not an integer */
+ if (*s == '-') *absval = -n; else *absval = n;
+ return t;
+ }
+}
+.fi
+
+.nf
+interpret_location($)
+{
+ char *s, *t;
+
+ s = $location;
+ s = scan(s, $abs_x, $rel_x);
+ s = scan(s, $abs_y, $rel_y);
+ s = scan(s, $abs_width, $rel_width);
+ s = scan(s, $abs_height, $rel_height);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/BoardP.h b/vendor/x11iraf/obm/ObmW/BoardP.h
new file mode 100644
index 00000000..6824bc93
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/BoardP.h
@@ -0,0 +1,56 @@
+/* Generated by wbuild from "Board.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfBoardP_H_
+#define _XfwfBoardP_H_
+#include "FrameP.h"
+#include "Board.h"
+typedef void (*set_abs_location_Proc)(
+#if NeedFunctionPrototypes
+Widget,unsigned int ,int ,int ,int ,int
+#endif
+);
+#define XtInherit_set_abs_location ((set_abs_location_Proc) _XtInherit)
+typedef struct {
+/* methods */
+set_abs_location_Proc set_abs_location;
+/* class variables */
+} XfwfBoardClassPart;
+typedef struct _XfwfBoardClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+} XfwfBoardClassRec;
+
+typedef struct {
+/* resources */
+Position abs_x;
+float rel_x;
+Position abs_y;
+float rel_y;
+#define MAGICNUM 12349
+
+
+Position abs_width;
+float rel_width;
+Position abs_height;
+float rel_height;
+float hunit;
+float vunit;
+String location;
+/* private state */
+} XfwfBoardPart;
+
+typedef struct _XfwfBoardRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+} XfwfBoardRec;
+
+externalref XfwfBoardClassRec xfwfBoardClassRec;
+
+#endif /* _XfwfBoardP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Button.c b/vendor/x11iraf/obm/ObmW/Button.c
new file mode 100644
index 00000000..1704a886
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Button.c
@@ -0,0 +1,123 @@
+/* Generated by wbuild from "Button.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "ButtonP.h"
+static void activate(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"activate", activate},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Down>: set_shadow(sunken) \n\
+<Btn1Down>,<Btn1Up>: activate() set_shadow() \n\
+Button1<Leave>: set_shadow() \n\
+<Key>Return: set_shadow(sunken) activate() set_shadow() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+
+static XtResource resources[] = {
+{XtNactivate,XtCActivate,XtRCallback,sizeof(((XfwfButtonRec*)NULL)->xfwfButton.activate),XtOffsetOf(XfwfButtonRec,xfwfButton.activate),XtRImmediate,(XtPointer)NULL },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfButtonRec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfButtonRec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)2 },
+{XtNtraversalOn,XtCTraversalOn,XtRBoolean,sizeof(((XfwfButtonRec*)NULL)->xfwfCommon.traversalOn),XtOffsetOf(XfwfButtonRec,xfwfCommon.traversalOn),XtRImmediate,(XtPointer)True },
+};
+
+XfwfButtonClassRec xfwfButtonClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfLabelClassRec,
+"TextButton",
+sizeof(XfwfButtonRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+NULL,
+NULL,
+XtInheritRealize,
+actionsList,
+1,
+resources,
+3,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+XtInheritExpose,
+NULL,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfLabel_class part */
+XtInherit_set_label,
+},
+{ /* XfwfButton_class part */
+0
+},
+};
+WidgetClass xfwfButtonWidgetClass = (WidgetClass) &xfwfButtonClassRec;
+/*ARGSUSED*/
+static void activate(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XtCallCallbackList(self, ((XfwfButtonWidget)self)->xfwfButton.activate, event);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfButtonWidgetClass c = (XfwfButtonWidgetClass) class;
+ XfwfButtonWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (CompositeClassExtensionRec *) XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = (XtPointer) ext;
+ if (class == xfwfButtonWidgetClass) return;
+ super = (XfwfButtonWidgetClass)class->core_class.superclass;
+}
diff --git a/vendor/x11iraf/obm/ObmW/Button.h b/vendor/x11iraf/obm/ObmW/Button.h
new file mode 100644
index 00000000..5d75b421
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Button.h
@@ -0,0 +1,20 @@
+/* Generated by wbuild from "Button.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfButton_H_
+#define _XfwfButton_H_
+#include "Label.h"
+#ifndef XtNactivate
+#define XtNactivate "activate"
+#endif
+#ifndef XtCActivate
+#define XtCActivate "Activate"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+typedef struct _XfwfButtonClassRec *XfwfButtonWidgetClass;
+typedef struct _XfwfButtonRec *XfwfButtonWidget;
+externalref WidgetClass xfwfButtonWidgetClass;
+#endif /*_XfwfButton_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Button.man b/vendor/x11iraf/obm/ObmW/Button.man
new file mode 100644
index 00000000..f9aad118
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Button.man
@@ -0,0 +1,264 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfButton
+.SH DESCRIPTION
+The \fIXfwfButton\fP widget is a simple button with a
+single callback \fIactivate_callback\fP. Except for that
+callback, all resources are inherited from the
+\fIXfwfLabel\fP widget. Subclasses provide buttons of
+other, more specialized types. \fIXfwfButton\fP inherits
+its 3D frame from \fIXfwfFrame\fP, the location
+specification resources from \fIXfwfBoard\fP and the
+multi-line label from \fIXfwfLabel\fP.
+
+The implementation is also very simple, since nearly
+all code is inherited from \fIXfwfLabel\fP. There are no
+new or redefined methods. In fact, just six lines of
+actual code suffice to implement the widget: Object
+Oriented Programming at its best!
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfButton
+Name Class Type Default
+XtNactivate XtCActivate Callback NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNactivate"
+The \fIactivate\fP is invoked from the \fIactivate\fP
+action, which is normally bound to a mouse click. The
+\fIcall_data\fP argument of the callbacks routines is
+filled with a pointer to the event that triggered the
+action.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList activate = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+The default \fIframeWidth\fP is set to 2 pixels.
+
+
+
+.hi
+
+.nf
+Dimension frameWidth = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNtraversalOn"
+In contrast to its superclass XfwfLabel, a button
+usually takes part in keyboard traversal.
+
+
+
+.hi
+
+.nf
+ traversalOn = True
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfLabel
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNtablist XtCTablist String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNalignment XtCAlignment Alignment 0
+XtNtopMargin XtCTopMargin Dimension 2
+XtNbottomMargin XtCBottomMargin Dimension 2
+XtNleftMargin XtCLeftMargin Dimension 2
+XtNrightMargin XtCRightMargin Dimension 2
+XtNshrinkToFit XtCShrinkToFit Boolean False
+XtNrvStart XtCRvStart Int 0
+XtNrvLength XtCRvLength Int 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Translations"
+
+By default, the \fIactivate\fP action is bound to a
+mouse click and to the Enter key.
+
+
+
+.nf
+<Btn1Down>: set_shadow(sunken)
+.fi
+
+.nf
+<Btn1Down>,<Btn1Up>: activate() set_shadow()
+.fi
+
+.nf
+Button1<Leave>: set_shadow()
+.fi
+
+.nf
+<Key>Return: set_shadow(sunken) activate() set_shadow()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "activate
+
+The \fIactivate\fP action just calls the \fIactivate\fP
+callback functions, passing the \fIXEvent\fP pointer in
+the \fIcall_data\fP argument.
+
+.hi
+
+.nf
+void activate($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XtCallCallbackList($, $activate, event);
+}
+.fi
+
+.eh
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/ButtonP.h b/vendor/x11iraf/obm/ObmW/ButtonP.h
new file mode 100644
index 00000000..12a8e708
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ButtonP.h
@@ -0,0 +1,41 @@
+/* Generated by wbuild from "Button.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfButtonP_H_
+#define _XfwfButtonP_H_
+#include "LabelP.h"
+#include "Button.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfButtonClassPart;
+typedef struct _XfwfButtonClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfLabelClassPart xfwfLabel_class;
+XfwfButtonClassPart xfwfButton_class;
+} XfwfButtonClassRec;
+
+typedef struct {
+/* resources */
+XtCallbackList activate;
+/* private state */
+} XfwfButtonPart;
+
+typedef struct _XfwfButtonRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfLabelPart xfwfLabel;
+XfwfButtonPart xfwfButton;
+} XfwfButtonRec;
+
+externalref XfwfButtonClassRec xfwfButtonClassRec;
+
+#endif /* _XfwfButtonP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/CHANGES b/vendor/x11iraf/obm/ObmW/CHANGES
new file mode 100644
index 00000000..e0eefeb7
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/CHANGES
@@ -0,0 +1,32 @@
+Layout widget:
+
+ fixed bug in laylex.l code - need to trim whitespace at end of a string
+ token.
+
+ this later turned out to be just a workaround for the real bug, which
+ was an incorrect unput(c) macro. the macro was not evaluating the (c)
+ but the lex code involves side effects that assume that this is done.
+
+ there was another bug in the Layout.c code. the code that lays out
+ the child widgets was using the size of a VariableBox to compute the
+ child offsets, as if this were part of the geometry being laid out.
+
+
+FWF widgets:
+
+ icon.c code was modified to support new version of XPM
+ pixmap files for builtin icons were edited and new icons were added
+ modified Common.c to change algorithm which computes top/bottom shadows
+ compute_inside modified in Common.c and Frame.c to avoid wrap to neg
+
+Added sed script FWFSED which converts <Xfwf/foo.h> includes and deletes
+#line references.
+
+Group widget
+
+ modified layout() to resize the child in the case where there is a single
+ child widget (actually this was done in RowCol.c).
+
+Layout widget
+
+ modified debug output to print a header containing the widget name
diff --git a/vendor/x11iraf/obm/ObmW/Common.c b/vendor/x11iraf/obm/ObmW/Common.c
new file mode 100644
index 00000000..4ffef4d4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Common.c
@@ -0,0 +1,770 @@
+/* Generated by wbuild from "Common.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <X11/Xmu/Converters.h>
+#include "Converters.h"
+#include "CommonP.h"
+#define focus_detail(detail) (detail ==NotifyAncestor ?"NotifyAncestor":detail ==NotifyVirtual ?"NotifyVirtual":detail ==NotifyInferior ?"NotifyInferior":detail ==NotifyNonlinear ?"NotifyNonlinear":detail ==NotifyNonlinearVirtual ?"NotifyNonlinearVirtual":detail ==NotifyPointer ?"NotifyPointer":detail ==NotifyPointerRoot ?"NotifyPointerRoot":detail ==NotifyDetailNone ?"NotifyDetailNone":"???")
+
+
+static void focusIn(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void focusOut(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseDown(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseUp(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseLeft(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseRight(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseNext(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traversePrev(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseNextTop(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseHome(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void traverseCurrent(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"focusIn", focusIn},
+{"focusOut", focusOut},
+{"traverseDown", traverseDown},
+{"traverseUp", traverseUp},
+{"traverseLeft", traverseLeft},
+{"traverseRight", traverseRight},
+{"traverseNext", traverseNext},
+{"traversePrev", traversePrev},
+{"traverseNextTop", traverseNextTop},
+{"traverseHome", traverseHome},
+{"traverseCurrent", traverseCurrent},
+};
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void class_initialize(
+#if NeedFunctionPrototypes
+void
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void compute_inside(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void destroy(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void highlight_border(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void unhighlight_border(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static Boolean accept_focus(
+#if NeedFunctionPrototypes
+Widget,Time *
+#endif
+);
+static Boolean would_accept_focus(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void traverse(
+#if NeedFunctionPrototypes
+Widget,TraversalDirection ,Widget ,Time *
+#endif
+);
+static Boolean choose_color(
+#if NeedFunctionPrototypes
+Widget,double ,Pixel ,Pixel *
+#endif
+);
+static Boolean lighter_color(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+static Boolean darker_color(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+#define done(type, value) do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ }while (0 )
+
+
+static Boolean cvtStringToAlignment(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+static Boolean cvtAlignmentToString(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+static char extraTranslations[] = "\
+ <FocusIn>: focusIn()\n\
+ <FocusOut>: focusOut()\n\
+ <Key>Up: traverseUp()\n\
+ <Key>Down: traverseDown()\n\
+ <Key>Left: traverseLeft()\n\
+ <Key>Right: traverseRight()\n\
+ <Key>Next: traverseNext()\n\
+ ~Shift<Key>Tab: traverseNext()\n\
+ <Key>Prior: traversePrev()\n\
+ Shift<Key>Tab: traversePrev()\n\
+ <Key>KP_Enter: traverseNextTop()\n\
+ <Key>Home: traverseHome()";
+static void create_bordergc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static Boolean traverse_to_direction(
+#if NeedFunctionPrototypes
+Widget,TraversalDirection ,int ,int ,Widget *,int *
+#endif
+);
+static void traverse_to_next(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+static void traverse_to_prev(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+static void traverse_to_next_top(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+/*ARGSUSED*/static Boolean cvtStringToAlignment(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ Alignment a = 0;
+ char c, *t, *s = (char*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToAlignment", "wrongParameters",
+ "XtToolkitError",
+ "String to Alignment conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ while (*s) {
+ for (; isspace(*s); s++) ;
+ for (t = s; *t && ! isspace(*t); t++) ;
+ c = *t;
+ *t = '\0';
+ if (XmuCompareISOLatin1(s, "top") == 0) a |= XfwfTop;
+ else if (XmuCompareISOLatin1(s, "bottom") == 0) a |= XfwfBottom;
+ else if (XmuCompareISOLatin1(s, "center") == 0) ; /* skip */
+ else if (XmuCompareISOLatin1(s, "left") == 0) a |= XfwfLeft;
+ else if (XmuCompareISOLatin1(s, "right") == 0) a |= XfwfRight;
+ else {
+ XtDisplayStringConversionWarning(display, (char*) from->addr,
+ "Alignment");
+ break;
+ }
+ *t = c;
+ s = t;
+ }
+ done(Alignment, a);
+}
+/*ARGSUSED*/static Boolean cvtAlignmentToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ Alignment *a = (Alignment*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtAlignmentToString", "wrongParameters",
+ "XtToolkitError",
+ "Alignment to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*a) {
+ case XfwfCenter: done(String, "center");
+ case XfwfBottom: done(String, "bottom");
+ case XfwfTop: done(String, "top");
+ case XfwfLeft: done(String, "left");
+ case XfwfRight: done(String, "right");
+ case XfwfBottom + XfwfLeft: done(String, "bottom left");
+ case XfwfBottom + XfwfRight: done(String, "bottom right");
+ case XfwfTop + XfwfLeft: done(String, "top left");
+ case XfwfTop + XfwfRight: done(String, "top right");
+ default: done(String, "unknown");
+ }
+}
+/*ARGSUSED*/static void create_bordergc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.bordergc) XtReleaseGC(self, ((XfwfCommonWidget)self)->xfwfCommon.bordergc);
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap != None) {
+ mask = GCFillStyle | GCTile;
+ values.fill_style = FillTiled;
+ values.tile = ((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap;
+ } else {
+ mask = GCFillStyle | GCForeground;
+ values.fill_style = FillSolid;
+ values.foreground = ((XfwfCommonWidget)self)->xfwfCommon.highlightColor;
+ }
+ ((XfwfCommonWidget)self)->xfwfCommon.bordergc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static Boolean traverse_to_direction(self,dir,x,y,found,distance)Widget self;TraversalDirection dir;int x;int y;Widget * found;int * distance;
+{
+ int i;
+ Widget child, w;
+ Position rx, ry;
+ int dist;
+ Boolean found_child = False;
+
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn) return False;
+ /*
+ * First recurse to all descendants
+ */
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtIsSubclass(((XfwfCommonWidget)self)->composite.children[i], xfwfCommonWidgetClass)
+ && traverse_to_direction(((XfwfCommonWidget)self)->composite.children[i], dir, x, y, found, distance))
+ found_child = True;
+ if (found_child) return True;
+ /*
+ * No child found, now check own position and distance
+ */
+ switch (dir) {
+ case TraverseHome: rx = 0; ry = 0; break;
+ case TraverseLeft: rx = ((XfwfCommonWidget)self)->core.width; ry = ((XfwfCommonWidget)self)->core.height/2; break;
+ case TraverseDown: rx = ((XfwfCommonWidget)self)->core.width/2; ry = 0; break;
+ case TraverseRight: rx = 0; ry = ((XfwfCommonWidget)self)->core.height/2; break;
+ case TraverseUp: rx = ((XfwfCommonWidget)self)->core.width/2; ry = ((XfwfCommonWidget)self)->core.height; break;
+ }
+ XtTranslateCoords(self, rx, ry, &rx, &ry);
+ if ((dir == TraverseUp && ry > y)
+ || (dir == TraverseLeft && rx > x)
+ || (dir == TraverseDown && ry < y)
+ || (dir == TraverseRight && rx < x)) return False;
+ dist = (rx - x)*(rx - x) + (ry - y)*(ry - y);
+ if (dist >= *distance) return False;
+ /*
+ * We are the best so far, but do we want the focus?
+ */
+ if (! ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.would_accept_focus(self)) return False;
+ *distance = dist;
+ *found = self;
+ return True;
+}
+/*ARGSUSED*/static void traverse_to_next(self,current,time)Widget self;Widget current;Time * time;
+{
+ int i = 0;
+ Widget parent = XtParent(self);
+
+ while (i < ((XfwfCommonWidget)self)->composite.num_children && ((XfwfCommonWidget)self)->composite.children[i] != current) i++;
+ for (i++; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseNext, self, time);
+}
+/*ARGSUSED*/static void traverse_to_prev(self,current,time)Widget self;Widget current;Time * time;
+{
+ int i = 0;
+ Widget parent = XtParent(self);
+
+ while (i < ((XfwfCommonWidget)self)->composite.num_children && ((XfwfCommonWidget)self)->composite.children[i] != current) i++;
+ for (i--; i >= 0; i--)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraversePrev, self, time);
+}
+/*ARGSUSED*/static void traverse_to_next_top(self,current,time)Widget self;Widget current;Time * time;
+{
+ Widget parent = XtParent(self);
+
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseNextTop, current, time);
+ else
+ XtCallCallbackList(self, ((XfwfCommonWidget)self)->xfwfCommon.nextTop, NULL);
+}
+
+static XtResource resources[] = {
+{XtNtraversalOn,XtCTraversalOn,XtRBoolean,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.traversalOn),XtOffsetOf(XfwfCommonRec,xfwfCommon.traversalOn),XtRImmediate,(XtPointer)True },
+{XtNhighlightThickness,XtCHighlightThickness,XtRDimension,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightThickness),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightThickness),XtRImmediate,(XtPointer)2 },
+{XtNhighlightColor,XtCHighlightColor,XtRPixel,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightColor),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightColor),XtRString,(XtPointer)XtDefaultForeground },
+{XtNhighlightPixmap,XtCHighlightPixmap,XtRPixmap,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightPixmap),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightPixmap),XtRImmediate,(XtPointer)None },
+{XtNnextTop,XtCNextTop,XtRCallback,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.nextTop),XtOffsetOf(XfwfCommonRec,xfwfCommon.nextTop),XtRImmediate,(XtPointer)NULL },
+{XtNuserData,XtCUserData,XtRPointer,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.userData),XtOffsetOf(XfwfCommonRec,xfwfCommon.userData),XtRImmediate,(XtPointer)NULL },
+};
+
+XfwfCommonClassRec xfwfCommonClassRec = {
+{ /* core_class part */
+(WidgetClass) &compositeClassRec,
+"XfwfCommon",
+sizeof(XfwfCommonRec),
+class_initialize,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+11,
+resources,
+6,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+destroy,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+accept_focus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+compute_inside,
+highlight_border,
+unhighlight_border,
+would_accept_focus,
+traverse,
+choose_color,
+lighter_color,
+darker_color,
+NULL ,
+},
+};
+WidgetClass xfwfCommonWidgetClass = (WidgetClass) &xfwfCommonClassRec;
+/*ARGSUSED*/
+static void focusIn(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Time time = CurrentTime;
+
+ if (event->type != FocusIn)
+ XtError("focusIn action may only be bound to FocusIn events");
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn)
+ return;
+ if (event->xfocus.detail == NotifyAncestor
+ || event->xfocus.detail == NotifyInferior
+ || event->xfocus.detail == NotifyNonlinear) {
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) (void) ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.accept_focus(self, &time);
+ } else if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.unhighlight_border(self);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ }
+}
+
+/*ARGSUSED*/
+static void focusOut(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (event->type != FocusOut)
+ XtError("focusOut action may only be bound to FocusOut events");
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.unhighlight_border(self);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ }
+}
+
+/*ARGSUSED*/
+static void traverseDown(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseDown, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseUp(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseUp, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseLeft(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseLeft, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseRight(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseRight, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseNext(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseNext, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traversePrev(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraversePrev, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseNextTop(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseNextTop, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseHome(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseHome, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+static void traverseCurrent(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn) (void) ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.accept_focus(self, &time);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfCommonWidgetClass c = (XfwfCommonWidgetClass) class;
+ XfwfCommonWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfCommonWidgetClass) return;
+ super = (XfwfCommonWidgetClass)class->core_class.superclass;
+ if (c->xfwfCommon_class.compute_inside == XtInherit_compute_inside)
+ c->xfwfCommon_class.compute_inside = super->xfwfCommon_class.compute_inside;
+ if (c->xfwfCommon_class.highlight_border == XtInherit_highlight_border)
+ c->xfwfCommon_class.highlight_border = super->xfwfCommon_class.highlight_border;
+ if (c->xfwfCommon_class.unhighlight_border == XtInherit_unhighlight_border)
+ c->xfwfCommon_class.unhighlight_border = super->xfwfCommon_class.unhighlight_border;
+ if (c->xfwfCommon_class.would_accept_focus == XtInherit_would_accept_focus)
+ c->xfwfCommon_class.would_accept_focus = super->xfwfCommon_class.would_accept_focus;
+ if (c->xfwfCommon_class.traverse == XtInherit_traverse)
+ c->xfwfCommon_class.traverse = super->xfwfCommon_class.traverse;
+ if (c->xfwfCommon_class.choose_color == XtInherit_choose_color)
+ c->xfwfCommon_class.choose_color = super->xfwfCommon_class.choose_color;
+ if (c->xfwfCommon_class.lighter_color == XtInherit_lighter_color)
+ c->xfwfCommon_class.lighter_color = super->xfwfCommon_class.lighter_color;
+ if (c->xfwfCommon_class.darker_color == XtInherit_darker_color)
+ c->xfwfCommon_class.darker_color = super->xfwfCommon_class.darker_color;
+}
+/*ARGSUSED*/static void class_initialize()
+{
+ static XtConvertArgRec args[] = {
+ { XtWidgetBaseOffset, 0, sizeof(Widget) } };
+
+ XtSetTypeConverter(XtRString, "Alignment", cvtStringToAlignment,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter("Alignment", XtRString, cvtAlignmentToString,
+ NULL, 0, XtCacheNone, NULL);
+ /* init_icon_quarks(); */
+ XtSetTypeConverter(XtRString, "Icon", cvtStringToIcon,
+ args, XtNumber(args), XtCacheNone, NULL);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans == NULL)
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans = XtParseTranslationTable(extraTranslations);
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn) {
+ XtAugmentTranslations(self, ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans);
+ ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.visible_interest = True;
+ }
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ ((XfwfCommonWidget)self)->xfwfCommon.bordergc = NULL;
+ create_bordergc(self);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redraw = False;
+ Widget parent = XtParent(self);
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn != ((XfwfCommonWidget)old)->xfwfCommon.traversalOn && ((XfwfCommonWidget)self)->xfwfCommon.traversalOn) {
+ XtAugmentTranslations(self, ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans);
+ ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.visible_interest = True;
+ }
+ if ((((XfwfCommonWidget)self)->core.sensitive != ((XfwfCommonWidget)old)->core.sensitive
+ || ((XfwfCommonWidget)self)->core.ancestor_sensitive != ((XfwfCommonWidget)old)->core.ancestor_sensitive
+ || ((XfwfCommonWidget)self)->xfwfCommon.traversalOn != ((XfwfCommonWidget)old)->xfwfCommon.traversalOn)
+ && ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseHome, self, &time);
+ }
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness != ((XfwfCommonWidget)old)->xfwfCommon.highlightThickness)
+ need_redraw = True;
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap != ((XfwfCommonWidget)old)->xfwfCommon.highlightPixmap) {
+ create_bordergc(self);
+ need_redraw = True;
+ } else if (((XfwfCommonWidget)self)->xfwfCommon.highlightColor != ((XfwfCommonWidget)old)->xfwfCommon.highlightColor) {
+ ((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap = None;
+ create_bordergc(self);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+/*ARGSUSED*/static void compute_inside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ *x = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ *y = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+
+ /* 09Mar94 DCT - max(0) applied to width and height. */
+ *w = max(0,((XfwfCommonWidget)self)->core.width - 2 * ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness);
+ *h = max(0,((XfwfCommonWidget)self)->core.height - 2 * ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness);
+}
+
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ if (! XtIsRealized(self)) return;
+ if (region != NULL) XSetRegion(XtDisplay(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, region);
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.highlight_border(self);
+ if (region != NULL) XSetClipMask(XtDisplay(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, None);
+}
+/*ARGSUSED*/static void destroy(self)Widget self;
+{
+ Widget parent = XtParent(self);
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidget)self)->core.sensitive = False;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseHome, self, &time);
+ }
+}
+/*ARGSUSED*/static void highlight_border(self)Widget self;
+{
+ XRectangle rect[4];
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness == 0) return;
+
+ rect[0].x = 0;
+ rect[0].y = 0;
+ rect[0].width = ((XfwfCommonWidget)self)->core.width;
+ rect[0].height = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+
+ rect[1].x = 0;
+ rect[1].y = 0;
+ rect[1].width = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[1].height = ((XfwfCommonWidget)self)->core.height;
+
+ rect[2].x = ((XfwfCommonWidget)self)->core.width - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[2].y = 0;
+ rect[2].width = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[2].height = ((XfwfCommonWidget)self)->core.height;
+
+ rect[3].x = 0;
+ rect[3].y = ((XfwfCommonWidget)self)->core.height - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[3].width = ((XfwfCommonWidget)self)->core.width;
+ rect[3].height = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+
+ XFillRectangles(XtDisplay(self), XtWindow(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, &rect[0], 4);
+}
+/*ARGSUSED*/static void unhighlight_border(self)Widget self;
+{
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness == 0) return;
+
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, 0, ((XfwfCommonWidget)self)->core.width, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, 0, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, ((XfwfCommonWidget)self)->core.height, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ ((XfwfCommonWidget)self)->core.width - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, 0,
+ ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, ((XfwfCommonWidget)self)->core.height, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, ((XfwfCommonWidget)self)->core.height - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness,
+ ((XfwfCommonWidget)self)->core.width, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, False);
+}
+/*ARGSUSED*/static Boolean accept_focus(self,time)Widget self;Time * time;
+{
+ int i;
+
+ if (! XtIsRealized(self) || ! ((XfwfCommonWidget)self)->core.sensitive || ! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn
+ || ! ((XfwfCommonWidget)self)->core.visible || ! ((XfwfCommonWidget)self)->core.ancestor_sensitive || ! ((XfwfCommonWidget)self)->core.managed
+ || ! ((XfwfCommonWidget)self)->core.mapped_when_managed || ((XfwfCommonWidget)self)->core.being_destroyed) return False;
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return True;
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ XSetInputFocus(XtDisplay(self), XtWindow(self), RevertToParent, *time);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = True;
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.highlight_border(self);
+ }
+ return True;
+}
+/*ARGSUSED*/static Boolean would_accept_focus(self)Widget self;
+{
+ int i;
+ Widget child;
+
+ if (! XtIsRealized(self) || ! ((XfwfCommonWidget)self)->core.sensitive || ! ((XfwfCommonWidget)self)->core.visible || ! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn)
+ return False;
+ else {
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++) {
+ child = ((XfwfCommonWidget)self)->composite.children[i];
+ if (XtIsSubclass(child, xfwfCommonWidgetClass)
+ && ((XfwfCommonWidgetClass)child->core.widget_class)->xfwfCommon_class.would_accept_focus(child))
+ return False;
+ }
+ return True;
+ }
+}
+/*ARGSUSED*/static void traverse(self,dir,current,time)Widget self;TraversalDirection dir;Widget current;Time * time;
+{
+ Widget w, parent = XtParent(self);
+ Position x, y;
+ int distance = LARGE_NUMBER;
+
+ if (dir == TraverseNextTop)
+ traverse_to_next_top(self, current, time);
+ else if (dir == TraverseNext)
+ traverse_to_next(self, current, time);
+ else if (dir == TraversePrev)
+ traverse_to_prev(self, current, time);
+ else if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, dir, current, time);
+ else {
+ switch (dir) {
+ case TraverseHome: x = 0; y = 0; break;
+ case TraverseLeft: x = 0; y = ((XfwfCommonWidget)current)->core.height/2; break;
+ case TraverseDown: x = ((XfwfCommonWidget)current)->core.width/2; y = ((XfwfCommonWidget)current)->core.height; break;
+ case TraverseRight: x = ((XfwfCommonWidget)current)->core.width; y = ((XfwfCommonWidget)current)->core.height/2; break;
+ case TraverseUp: x = ((XfwfCommonWidget)current)->core.width/2; y = 0; break;
+ }
+ if (dir != TraverseHome) XtTranslateCoords(current, x, y, &x, &y);
+ if (traverse_to_direction(self, dir, x, y, &w, &distance))
+ XtCallAcceptFocus(w, time);
+ }
+}
+/*ARGSUSED*/static Boolean choose_color(self,factor,base,result)Widget self;double factor;Pixel base;Pixel * result;
+{
+ XColor color1, color2, dummy;
+
+ color1.pixel = base;
+ XQueryColor(XtDisplay(self), DefaultColormapOfScreen(XtScreen(self)), &color1);
+ color2.red = min(65535, factor * color1.red);
+ color2.green = min(65535, factor * color1.green);
+ color2.blue = min(65535, factor * color1.blue);
+ if (! XAllocColor(XtDisplay(self),
+ DefaultColormapOfScreen(XtScreen(self)), &color2))
+ return False;
+ if (base == color2.pixel) {
+ if (! XAllocNamedColor(XtDisplay(self),
+ DefaultColormapOfScreen(XtScreen(self)), "gray75",
+ &color2, &dummy))
+ return False;
+ }
+ *result = color2.pixel;
+ return True;
+}
+/*ARGSUSED*/static Boolean lighter_color(self,base,result)Widget self;Pixel base;Pixel * result;
+{
+ /* return choose_color(self, 1.5, base, result); */
+ return choose_color(self, 1.25, base, result);
+}
+/*ARGSUSED*/static Boolean darker_color(self,base,result)Widget self;Pixel base;Pixel * result;
+{
+ /* return choose_color(self, 0.667, base, result); */
+ return choose_color(self, 0.500, base, result);
+}
+/*ARGSUSED*/void XfwfCallComputeInside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ if (XtIsSubclass(self, xfwfCommonWidgetClass) && ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside)
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, x, y, w, h);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Common.c.ORIG b/vendor/x11iraf/obm/ObmW/Common.c.ORIG
new file mode 100644
index 00000000..7d67213f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Common.c.ORIG
@@ -0,0 +1,852 @@
+/* Generated by wbuild from "Common.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#line 929 "Common.w"
+#include <stdio.h>
+#line 930 "Common.w"
+#include <X11/Xmu/Converters.h>
+#line 931 "Common.w"
+#include "Converters.h"
+#include "CommonP.h"
+#define focus_detail(detail) (detail ==NotifyAncestor ?"NotifyAncestor":detail ==NotifyVirtual ?"NotifyVirtual":detail ==NotifyInferior ?"NotifyInferior":detail ==NotifyNonlinear ?"NotifyNonlinear":detail ==NotifyNonlinearVirtual ?"NotifyNonlinearVirtual":detail ==NotifyPointer ?"NotifyPointer":detail ==NotifyPointerRoot ?"NotifyPointerRoot":detail ==NotifyDetailNone ?"NotifyDetailNone":"???")
+
+
+#line 800 "Common.w"
+static void focusIn(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 821 "Common.w"
+static void focusOut(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 837 "Common.w"
+static void traverseDown(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 846 "Common.w"
+static void traverseUp(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 855 "Common.w"
+static void traverseLeft(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 864 "Common.w"
+static void traverseRight(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 876 "Common.w"
+static void traverseNext(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 885 "Common.w"
+static void traversePrev(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 896 "Common.w"
+static void traverseNextTop(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 905 "Common.w"
+static void traverseHome(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+#line 915 "Common.w"
+static void traverseCurrent(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"focusIn", focusIn},
+{"focusOut", focusOut},
+{"traverseDown", traverseDown},
+{"traverseUp", traverseUp},
+{"traverseLeft", traverseLeft},
+{"traverseRight", traverseRight},
+{"traverseNext", traverseNext},
+{"traversePrev", traversePrev},
+{"traverseNextTop", traverseNextTop},
+{"traverseHome", traverseHome},
+{"traverseCurrent", traverseCurrent},
+};
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+#line 161 "Common.w"
+static void class_initialize(
+#if NeedFunctionPrototypes
+void
+#endif
+);
+#line 184 "Common.w"
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+#line 206 "Common.w"
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+#line 243 "Common.w"
+static void compute_inside(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+#line 254 "Common.w"
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+#line 266 "Common.w"
+static void destroy(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#line 284 "Common.w"
+static void highlight_border(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#line 313 "Common.w"
+static void unhighlight_border(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#line 338 "Common.w"
+static Boolean accept_focus(
+#if NeedFunctionPrototypes
+Widget,Time *
+#endif
+);
+#line 360 "Common.w"
+static Boolean would_accept_focus(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#line 470 "Common.w"
+static void traverse(
+#if NeedFunctionPrototypes
+Widget,TraversalDirection ,Widget ,Time *
+#endif
+);
+#line 733 "Common.w"
+static Boolean choose_color(
+#if NeedFunctionPrototypes
+Widget,double ,Pixel ,Pixel *
+#endif
+);
+#line 760 "Common.w"
+static Boolean lighter_color(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+#line 770 "Common.w"
+static Boolean darker_color(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+#line 505 "Common.w"
+#define done(type, value) do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ }while (0 )
+
+
+#line 522 "Common.w"
+static Boolean cvtStringToAlignment(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+#line 557 "Common.w"
+static Boolean cvtAlignmentToString(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+#line 586 "Common.w"
+static char extraTranslations[] = "\
+ <FocusIn>: focusIn()\n\
+ <FocusOut>: focusOut()\n\
+ <Key>Up: traverseUp()\n\
+ <Key>Down: traverseDown()\n\
+ <Key>Left: traverseLeft()\n\
+ <Key>Right: traverseRight()\n\
+ <Key>Next: traverseNext()\n\
+ ~Shift<Key>Tab: traverseNext()\n\
+ <Key>Prior: traversePrev()\n\
+ Shift<Key>Tab: traversePrev()\n\
+ <Key>KP_Enter: traverseNextTop()\n\
+ <Key>Home: traverseHome()";
+#line 604 "Common.w"
+static void create_bordergc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#line 631 "Common.w"
+static Boolean traverse_to_direction(
+#if NeedFunctionPrototypes
+Widget,TraversalDirection ,int ,int ,Widget *,int *
+#endif
+);
+#line 680 "Common.w"
+static void traverse_to_next(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+#line 697 "Common.w"
+static void traverse_to_prev(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+#line 710 "Common.w"
+static void traverse_to_next_top(
+#if NeedFunctionPrototypes
+Widget,Widget ,Time *
+#endif
+);
+#line 522 "Common.w"
+/*ARGSUSED*/static Boolean cvtStringToAlignment(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ Alignment a = 0;
+ char c, *t, *s = (char*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToAlignment", "wrongParameters",
+ "XtToolkitError",
+ "String to Alignment conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ while (*s) {
+ for (; isspace(*s); s++) ;
+ for (t = s; *t && ! isspace(*t); t++) ;
+ c = *t;
+ *t = '\0';
+ if (XmuCompareISOLatin1(s, "top") == 0) a |= XfwfTop;
+ else if (XmuCompareISOLatin1(s, "bottom") == 0) a |= XfwfBottom;
+ else if (XmuCompareISOLatin1(s, "center") == 0) ; /* skip */
+ else if (XmuCompareISOLatin1(s, "left") == 0) a |= XfwfLeft;
+ else if (XmuCompareISOLatin1(s, "right") == 0) a |= XfwfRight;
+ else {
+ XtDisplayStringConversionWarning(display, (char*) from->addr,
+ "Alignment");
+ break;
+ }
+ *t = c;
+ s = t;
+ }
+ done(Alignment, a);
+}
+#line 557 "Common.w"
+/*ARGSUSED*/static Boolean cvtAlignmentToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ Alignment *a = (Alignment*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtAlignmentToString", "wrongParameters",
+ "XtToolkitError",
+ "Alignment to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*a) {
+ case XfwfCenter: done(String, "center");
+ case XfwfBottom: done(String, "bottom");
+ case XfwfTop: done(String, "top");
+ case XfwfLeft: done(String, "left");
+ case XfwfRight: done(String, "right");
+ case XfwfBottom + XfwfLeft: done(String, "bottom left");
+ case XfwfBottom + XfwfRight: done(String, "bottom right");
+ case XfwfTop + XfwfLeft: done(String, "top left");
+ case XfwfTop + XfwfRight: done(String, "top right");
+ default: done(String, "unknown");
+ }
+}
+#line 604 "Common.w"
+/*ARGSUSED*/static void create_bordergc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.bordergc) XtReleaseGC(self, ((XfwfCommonWidget)self)->xfwfCommon.bordergc);
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap != None) {
+ mask = GCFillStyle | GCTile;
+ values.fill_style = FillTiled;
+ values.tile = ((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap;
+ } else {
+ mask = GCFillStyle | GCForeground;
+ values.fill_style = FillSolid;
+ values.foreground = ((XfwfCommonWidget)self)->xfwfCommon.highlightColor;
+ }
+ ((XfwfCommonWidget)self)->xfwfCommon.bordergc = XtGetGC(self, mask, &values);
+}
+#line 631 "Common.w"
+/*ARGSUSED*/static Boolean traverse_to_direction(self,dir,x,y,found,distance)Widget self;TraversalDirection dir;int x;int y;Widget * found;int * distance;
+{
+ int i;
+ Widget child, w;
+ Position rx, ry;
+ int dist;
+ Boolean found_child = False;
+
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn) return False;
+ /*
+ * First recurse to all descendants
+ */
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtIsSubclass(((XfwfCommonWidget)self)->composite.children[i], xfwfCommonWidgetClass)
+ && traverse_to_direction(((XfwfCommonWidget)self)->composite.children[i], dir, x, y, found, distance))
+ found_child = True;
+ if (found_child) return True;
+ /*
+ * No child found, now check own position and distance
+ */
+ switch (dir) {
+ case TraverseHome: rx = 0; ry = 0; break;
+ case TraverseLeft: rx = ((XfwfCommonWidget)self)->core.width; ry = ((XfwfCommonWidget)self)->core.height/2; break;
+ case TraverseDown: rx = ((XfwfCommonWidget)self)->core.width/2; ry = 0; break;
+ case TraverseRight: rx = 0; ry = ((XfwfCommonWidget)self)->core.height/2; break;
+ case TraverseUp: rx = ((XfwfCommonWidget)self)->core.width/2; ry = ((XfwfCommonWidget)self)->core.height; break;
+ }
+ XtTranslateCoords(self, rx, ry, &rx, &ry);
+ if ((dir == TraverseUp && ry > y)
+ || (dir == TraverseLeft && rx > x)
+ || (dir == TraverseDown && ry < y)
+ || (dir == TraverseRight && rx < x)) return False;
+ dist = (rx - x)*(rx - x) + (ry - y)*(ry - y);
+ if (dist >= *distance) return False;
+ /*
+ * We are the best so far, but do we want the focus?
+ */
+ if (! ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.would_accept_focus(self)) return False;
+ *distance = dist;
+ *found = self;
+ return True;
+}
+#line 680 "Common.w"
+/*ARGSUSED*/static void traverse_to_next(self,current,time)Widget self;Widget current;Time * time;
+{
+ int i = 0;
+ Widget parent = XtParent(self);
+
+ while (i < ((XfwfCommonWidget)self)->composite.num_children && ((XfwfCommonWidget)self)->composite.children[i] != current) i++;
+ for (i++; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseNext, self, time);
+}
+#line 697 "Common.w"
+/*ARGSUSED*/static void traverse_to_prev(self,current,time)Widget self;Widget current;Time * time;
+{
+ int i = 0;
+ Widget parent = XtParent(self);
+
+ while (i < ((XfwfCommonWidget)self)->composite.num_children && ((XfwfCommonWidget)self)->composite.children[i] != current) i++;
+ for (i--; i >= 0; i--)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraversePrev, self, time);
+}
+#line 710 "Common.w"
+/*ARGSUSED*/static void traverse_to_next_top(self,current,time)Widget self;Widget current;Time * time;
+{
+ Widget parent = XtParent(self);
+
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseNextTop, current, time);
+ else
+ XtCallCallbackList(self, ((XfwfCommonWidget)self)->xfwfCommon.nextTop, NULL);
+}
+
+static XtResource resources[] = {
+#line 75 "Common.w"
+{XtNtraversalOn,XtCTraversalOn,XtRBoolean,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.traversalOn),XtOffsetOf(XfwfCommonRec,xfwfCommon.traversalOn),XtRImmediate,(XtPointer)True },
+#line 83 "Common.w"
+{XtNhighlightThickness,XtCHighlightThickness,XtRDimension,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightThickness),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightThickness),XtRImmediate,(XtPointer)2 },
+#line 91 "Common.w"
+{XtNhighlightColor,XtCHighlightColor,XtRPixel,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightColor),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightColor),XtRString,(XtPointer)XtDefaultForeground },
+#line 98 "Common.w"
+{XtNhighlightPixmap,XtCHighlightPixmap,XtRPixmap,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.highlightPixmap),XtOffsetOf(XfwfCommonRec,xfwfCommon.highlightPixmap),XtRImmediate,(XtPointer)None },
+#line 108 "Common.w"
+{XtNnextTop,XtCNextTop,XtRCallback,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.nextTop),XtOffsetOf(XfwfCommonRec,xfwfCommon.nextTop),XtRImmediate,(XtPointer)NULL },
+#line 114 "Common.w"
+{XtNuserData,XtCUserData,XtRPointer,sizeof(((XfwfCommonRec*)NULL)->xfwfCommon.userData),XtOffsetOf(XfwfCommonRec,xfwfCommon.userData),XtRImmediate,(XtPointer)NULL },
+};
+
+XfwfCommonClassRec xfwfCommonClassRec = {
+{ /* core_class part */
+(WidgetClass) &compositeClassRec,
+"XfwfCommon",
+sizeof(XfwfCommonRec),
+class_initialize,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+11,
+resources,
+6,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+destroy,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+accept_focus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+compute_inside,
+highlight_border,
+unhighlight_border,
+would_accept_focus,
+traverse,
+choose_color,
+lighter_color,
+darker_color,
+NULL ,
+},
+};
+WidgetClass xfwfCommonWidgetClass = (WidgetClass) &xfwfCommonClassRec;
+/*ARGSUSED*/
+#line 800 "Common.w"
+static void focusIn(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Time time = CurrentTime;
+
+ if (event->type != FocusIn)
+ XtError("focusIn action may only be bound to FocusIn events");
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn)
+ return;
+ if (event->xfocus.detail == NotifyAncestor
+ || event->xfocus.detail == NotifyInferior
+ || event->xfocus.detail == NotifyNonlinear) {
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) (void) ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.accept_focus(self, &time);
+ } else if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.unhighlight_border(self);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ }
+}
+
+/*ARGSUSED*/
+#line 821 "Common.w"
+static void focusOut(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (event->type != FocusOut)
+ XtError("focusOut action may only be bound to FocusOut events");
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.unhighlight_border(self);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ }
+}
+
+/*ARGSUSED*/
+#line 837 "Common.w"
+static void traverseDown(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseDown, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 846 "Common.w"
+static void traverseUp(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseUp, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 855 "Common.w"
+static void traverseLeft(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseLeft, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 864 "Common.w"
+static void traverseRight(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseRight, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 876 "Common.w"
+static void traverseNext(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseNext, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 885 "Common.w"
+static void traversePrev(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraversePrev, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 896 "Common.w"
+static void traverseNextTop(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseNextTop, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 905 "Common.w"
+static void traverseHome(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traverse(self, TraverseHome, self, &event->xkey.time);
+}
+
+/*ARGSUSED*/
+#line 915 "Common.w"
+static void traverseCurrent(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn) (void) ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.accept_focus(self, &time);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfCommonWidgetClass c = (XfwfCommonWidgetClass) class;
+ XfwfCommonWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfCommonWidgetClass) return;
+ super = (XfwfCommonWidgetClass)class->core_class.superclass;
+ if (c->xfwfCommon_class.compute_inside == XtInherit_compute_inside)
+ c->xfwfCommon_class.compute_inside = super->xfwfCommon_class.compute_inside;
+ if (c->xfwfCommon_class.highlight_border == XtInherit_highlight_border)
+ c->xfwfCommon_class.highlight_border = super->xfwfCommon_class.highlight_border;
+ if (c->xfwfCommon_class.unhighlight_border == XtInherit_unhighlight_border)
+ c->xfwfCommon_class.unhighlight_border = super->xfwfCommon_class.unhighlight_border;
+ if (c->xfwfCommon_class.would_accept_focus == XtInherit_would_accept_focus)
+ c->xfwfCommon_class.would_accept_focus = super->xfwfCommon_class.would_accept_focus;
+ if (c->xfwfCommon_class.traverse == XtInherit_traverse)
+ c->xfwfCommon_class.traverse = super->xfwfCommon_class.traverse;
+ if (c->xfwfCommon_class.choose_color == XtInherit_choose_color)
+ c->xfwfCommon_class.choose_color = super->xfwfCommon_class.choose_color;
+ if (c->xfwfCommon_class.lighter_color == XtInherit_lighter_color)
+ c->xfwfCommon_class.lighter_color = super->xfwfCommon_class.lighter_color;
+ if (c->xfwfCommon_class.darker_color == XtInherit_darker_color)
+ c->xfwfCommon_class.darker_color = super->xfwfCommon_class.darker_color;
+}
+#line 161 "Common.w"
+/*ARGSUSED*/static void class_initialize()
+{
+ static XtConvertArgRec args[] = {
+ { XtWidgetBaseOffset, 0, sizeof(Widget) } };
+
+ XtSetTypeConverter(XtRString, "Alignment", cvtStringToAlignment,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter("Alignment", XtRString, cvtAlignmentToString,
+ NULL, 0, XtCacheNone, NULL);
+ /* init_icon_quarks(); */
+ XtSetTypeConverter(XtRString, "Icon", cvtStringToIcon,
+ args, XtNumber(args), XtCacheNone, NULL);
+}
+#line 184 "Common.w"
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans == NULL)
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans = XtParseTranslationTable(extraTranslations);
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn) {
+ XtAugmentTranslations(self, ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans);
+ ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.visible_interest = True;
+ }
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = False;
+ ((XfwfCommonWidget)self)->xfwfCommon.bordergc = NULL;
+ create_bordergc(self);
+}
+#line 206 "Common.w"
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redraw = False;
+ Widget parent = XtParent(self);
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversalOn != ((XfwfCommonWidget)old)->xfwfCommon.traversalOn && ((XfwfCommonWidget)self)->xfwfCommon.traversalOn) {
+ XtAugmentTranslations(self, ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.traversal_trans);
+ ((XfwfCommonWidgetClass)self->core.widget_class)->core_class.visible_interest = True;
+ }
+ if ((((XfwfCommonWidget)self)->core.sensitive != ((XfwfCommonWidget)old)->core.sensitive
+ || ((XfwfCommonWidget)self)->core.ancestor_sensitive != ((XfwfCommonWidget)old)->core.ancestor_sensitive
+ || ((XfwfCommonWidget)self)->xfwfCommon.traversalOn != ((XfwfCommonWidget)old)->xfwfCommon.traversalOn)
+ && ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseHome, self, &time);
+ }
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness != ((XfwfCommonWidget)old)->xfwfCommon.highlightThickness)
+ need_redraw = True;
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap != ((XfwfCommonWidget)old)->xfwfCommon.highlightPixmap) {
+ create_bordergc(self);
+ need_redraw = True;
+ } else if (((XfwfCommonWidget)self)->xfwfCommon.highlightColor != ((XfwfCommonWidget)old)->xfwfCommon.highlightColor) {
+ ((XfwfCommonWidget)self)->xfwfCommon.highlightPixmap = None;
+ create_bordergc(self);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+#line 243 "Common.w"
+/*ARGSUSED*/static void compute_inside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ *x = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ *y = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ *w = ((XfwfCommonWidget)self)->core.width - 2 * ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ *h = ((XfwfCommonWidget)self)->core.height - 2 * ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+}
+#line 254 "Common.w"
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ if (! XtIsRealized(self)) return;
+ if (region != NULL) XSetRegion(XtDisplay(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, region);
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.highlight_border(self);
+ if (region != NULL) XSetClipMask(XtDisplay(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, None);
+}
+#line 266 "Common.w"
+/*ARGSUSED*/static void destroy(self)Widget self;
+{
+ Widget parent = XtParent(self);
+ Time time = CurrentTime;
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ ((XfwfCommonWidget)self)->core.sensitive = False;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, TraverseHome, self, &time);
+ }
+}
+#line 284 "Common.w"
+/*ARGSUSED*/static void highlight_border(self)Widget self;
+{
+ XRectangle rect[4];
+
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness == 0) return;
+
+ rect[0].x = 0;
+ rect[0].y = 0;
+ rect[0].width = ((XfwfCommonWidget)self)->core.width;
+ rect[0].height = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+
+ rect[1].x = 0;
+ rect[1].y = 0;
+ rect[1].width = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[1].height = ((XfwfCommonWidget)self)->core.height;
+
+ rect[2].x = ((XfwfCommonWidget)self)->core.width - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[2].y = 0;
+ rect[2].width = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[2].height = ((XfwfCommonWidget)self)->core.height;
+
+ rect[3].x = 0;
+ rect[3].y = ((XfwfCommonWidget)self)->core.height - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+ rect[3].width = ((XfwfCommonWidget)self)->core.width;
+ rect[3].height = ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness;
+
+ XFillRectangles(XtDisplay(self), XtWindow(self), ((XfwfCommonWidget)self)->xfwfCommon.bordergc, &rect[0], 4);
+}
+#line 313 "Common.w"
+/*ARGSUSED*/static void unhighlight_border(self)Widget self;
+{
+ if (((XfwfCommonWidget)self)->xfwfCommon.highlightThickness == 0) return;
+
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, 0, ((XfwfCommonWidget)self)->core.width, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, 0, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, ((XfwfCommonWidget)self)->core.height, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ ((XfwfCommonWidget)self)->core.width - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, 0,
+ ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, ((XfwfCommonWidget)self)->core.height, False);
+ XClearArea(XtDisplay(self), XtWindow(self),
+ 0, ((XfwfCommonWidget)self)->core.height - ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness,
+ ((XfwfCommonWidget)self)->core.width, ((XfwfCommonWidget)self)->xfwfCommon.highlightThickness, False);
+}
+#line 338 "Common.w"
+/*ARGSUSED*/static Boolean accept_focus(self,time)Widget self;Time * time;
+{
+ int i;
+
+ if (! XtIsRealized(self) || ! ((XfwfCommonWidget)self)->core.sensitive || ! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn
+ || ! ((XfwfCommonWidget)self)->core.visible || ! ((XfwfCommonWidget)self)->core.ancestor_sensitive || ! ((XfwfCommonWidget)self)->core.managed
+ || ! ((XfwfCommonWidget)self)->core.mapped_when_managed || ((XfwfCommonWidget)self)->core.being_destroyed) return False;
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++)
+ if (XtCallAcceptFocus(((XfwfCommonWidget)self)->composite.children[i], time)) return True;
+ if (! ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus) {
+ XSetInputFocus(XtDisplay(self), XtWindow(self), RevertToParent, *time);
+ ((XfwfCommonWidget)self)->xfwfCommon.traversal_focus = True;
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.highlight_border(self);
+ }
+ return True;
+}
+#line 360 "Common.w"
+/*ARGSUSED*/static Boolean would_accept_focus(self)Widget self;
+{
+ int i;
+ Widget child;
+
+ if (! XtIsRealized(self) || ! ((XfwfCommonWidget)self)->core.sensitive || ! ((XfwfCommonWidget)self)->core.visible || ! ((XfwfCommonWidget)self)->xfwfCommon.traversalOn)
+ return False;
+ else {
+ for (i = 0; i < ((XfwfCommonWidget)self)->composite.num_children; i++) {
+ child = ((XfwfCommonWidget)self)->composite.children[i];
+ if (XtIsSubclass(child, xfwfCommonWidgetClass)
+ && ((XfwfCommonWidgetClass)child->core.widget_class)->xfwfCommon_class.would_accept_focus(child))
+ return False;
+ }
+ return True;
+ }
+}
+#line 470 "Common.w"
+/*ARGSUSED*/static void traverse(self,dir,current,time)Widget self;TraversalDirection dir;Widget current;Time * time;
+{
+ Widget w, parent = XtParent(self);
+ Position x, y;
+ int distance = LARGE_NUMBER;
+
+ if (dir == TraverseNextTop)
+ traverse_to_next_top(self, current, time);
+ else if (dir == TraverseNext)
+ traverse_to_next(self, current, time);
+ else if (dir == TraversePrev)
+ traverse_to_prev(self, current, time);
+ else if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ ((XfwfCommonWidgetClass)parent->core.widget_class)->xfwfCommon_class.traverse(parent, dir, current, time);
+ else {
+ switch (dir) {
+ case TraverseHome: x = 0; y = 0; break;
+ case TraverseLeft: x = 0; y = ((XfwfCommonWidget)current)->core.height/2; break;
+ case TraverseDown: x = ((XfwfCommonWidget)current)->core.width/2; y = ((XfwfCommonWidget)current)->core.height; break;
+ case TraverseRight: x = ((XfwfCommonWidget)current)->core.width; y = ((XfwfCommonWidget)current)->core.height/2; break;
+ case TraverseUp: x = ((XfwfCommonWidget)current)->core.width/2; y = 0; break;
+ }
+ if (dir != TraverseHome) XtTranslateCoords(current, x, y, &x, &y);
+ if (traverse_to_direction(self, dir, x, y, &w, &distance))
+ XtCallAcceptFocus(w, time);
+ }
+}
+#line 733 "Common.w"
+/*ARGSUSED*/static Boolean choose_color(self,factor,base,result)Widget self;double factor;Pixel base;Pixel * result;
+{
+ XColor color1, color2, dummy;
+
+ color1.pixel = base;
+ XQueryColor(XtDisplay(self), DefaultColormapOfScreen(XtScreen(self)), &color1);
+ color2.red = min(65535, factor * color1.red);
+ color2.green = min(65535, factor * color1.green);
+ color2.blue = min(65535, factor * color1.blue);
+ if (! XAllocColor(XtDisplay(self),
+ DefaultColormapOfScreen(XtScreen(self)), &color2))
+ return False;
+ if (base == color2.pixel) {
+ if (! XAllocNamedColor(XtDisplay(self),
+ DefaultColormapOfScreen(XtScreen(self)), "gray75",
+ &color2, &dummy))
+ return False;
+ }
+ *result = color2.pixel;
+ return True;
+}
+#line 760 "Common.w"
+/*ARGSUSED*/static Boolean lighter_color(self,base,result)Widget self;Pixel base;Pixel * result;
+{
+ return choose_color(self, 1.5, base, result);
+}
+#line 770 "Common.w"
+/*ARGSUSED*/static Boolean darker_color(self,base,result)Widget self;Pixel base;Pixel * result;
+{
+ return choose_color(self, 0.667, base, result);
+}
+#line 28 "Common.w"
+#line 33 "Common.w"
+#line 34 "Common.w"
+#line 35 "Common.w"
+#line 36 "Common.w"
+#line 37 "Common.w"
+#line 43 "Common.w"
+#line 44 "Common.w"
+#line 45 "Common.w"
+#line 46 "Common.w"
+#line 52 "Common.w"
+#line 61 "Common.w"
+/*ARGSUSED*/void XfwfCallComputeInside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ if (XtIsSubclass(self, xfwfCommonWidgetClass) && ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside)
+ ((XfwfCommonWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, x, y, w, h);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Common.h b/vendor/x11iraf/obm/ObmW/Common.h
new file mode 100644
index 00000000..b1a9a97a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Common.h
@@ -0,0 +1,108 @@
+/* Generated by wbuild from "Common.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfCommon_H_
+#define _XfwfCommon_H_
+#include <X11/Composite.h>
+typedef int Alignment;
+
+#define XfwfCenter 0
+
+
+#define XfwfLeft 1
+
+
+#define XfwfRight 2
+
+
+#define XfwfTop 4
+
+
+#define XfwfBottom 8
+
+
+#define XfwfTopLeft (XfwfTop +XfwfLeft )
+
+
+#define XfwfTopRight (XfwfTop +XfwfRight )
+
+
+#define XfwfBottomLeft (XfwfBottom +XfwfLeft )
+
+
+#define XfwfBottomRight (XfwfBottom +XfwfRight )
+
+
+typedef enum {
+ TraverseLeft, TraverseRight, TraverseUp, TraverseDown,
+ TraverseNext, TraversePrev, TraverseHome, TraverseNextTop } TraversalDirection;
+
+void XfwfCallComputeInside(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+#ifndef XtNtraversalOn
+#define XtNtraversalOn "traversalOn"
+#endif
+#ifndef XtCTraversalOn
+#define XtCTraversalOn "TraversalOn"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+#ifndef XtNhighlightThickness
+#define XtNhighlightThickness "highlightThickness"
+#endif
+#ifndef XtCHighlightThickness
+#define XtCHighlightThickness "HighlightThickness"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNhighlightColor
+#define XtNhighlightColor "highlightColor"
+#endif
+#ifndef XtCHighlightColor
+#define XtCHighlightColor "HighlightColor"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNhighlightPixmap
+#define XtNhighlightPixmap "highlightPixmap"
+#endif
+#ifndef XtCHighlightPixmap
+#define XtCHighlightPixmap "HighlightPixmap"
+#endif
+#ifndef XtRPixmap
+#define XtRPixmap "Pixmap"
+#endif
+
+#ifndef XtNnextTop
+#define XtNnextTop "nextTop"
+#endif
+#ifndef XtCNextTop
+#define XtCNextTop "NextTop"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+#ifndef XtNuserData
+#define XtNuserData "userData"
+#endif
+#ifndef XtCUserData
+#define XtCUserData "UserData"
+#endif
+#ifndef XtRPointer
+#define XtRPointer "Pointer"
+#endif
+
+typedef struct _XfwfCommonClassRec *XfwfCommonWidgetClass;
+typedef struct _XfwfCommonRec *XfwfCommonWidget;
+externalref WidgetClass xfwfCommonWidgetClass;
+#endif /*_XfwfCommon_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Common.man b/vendor/x11iraf/obm/ObmW/Common.man
new file mode 100644
index 00000000..b64484ab
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Common.man
@@ -0,0 +1,1226 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfCommon
+.SH DESCRIPTION
+The Common class is not meant to be instantiated. It only serves as
+the common superclass for a family of widgets, to ensure that these
+widgets have some common methods and resources. The Common class
+defines common types, symbolic constants, and type converters and it
+also provides the basis for keyboard traversal. The code for keyboard
+traversal is roughly based on that in the Xw widget set (created by
+Hewlett Packard), but it uses the \fIaccept_focus\fP method.
+
+When the resource \fItraversalOn\fP is set to \fITrue\fP (either at creation
+time, or via a \fIXtSetValues\fP later), a set of translations is added to
+the widget. If the widget's parent is also a subclass of Common, these
+translations will then implement keyboard traversal, using the cursor
+keys (up, down, prev, etc.) Of course, when the widget already uses
+these keys for other purposes, the keyboard traversal will not work.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNtraversalOn"
+The resource \fItraversalOn\fP determines whether keyboard traversal is
+used. If it is \fITrue\fP initially, or if it is set to \fITrue\fP later, a
+set of translations will be added to the widget.
+
+
+
+.hi
+
+.nf
+Boolean traversalOn = True
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightThickness"
+Keyboard focus is indicated by border highlighting. When keyboard
+traversal is on and the widget receives the focus, the highlight border
+is filled with the highlight color or tile. If the widget does not
+have the focus, the area is left in the default background.
+
+
+
+.hi
+
+.nf
+Dimension highlightThickness = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightColor"
+The highlight border can have a color or it can be tiled with a
+pixmap. Whichever of the resources \fIhighlightColor\fP or
+\fIhighlightPixmap\fP is set latest, is used. When both are set, the
+pixmap is used.
+
+
+
+.hi
+
+.nf
+Pixel highlightColor = <String>XtDefaultForeground
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightPixmap"
+The \fIhighlightPixmap\fP can be set to a pixmap with which the
+highlight border will be tiled. Only one of \fIhighlightPixmap\fP and
+\fIhighlightColor\fP can be set, see above.
+
+
+
+.hi
+
+.nf
+Pixmap highlightPixmap = None
+.fi
+
+.eh
+
+.TP
+.I "XtNnextTop"
+When an application has several top level windows, it should have a
+way of setting the focus between windows. The Enter key in any widget
+with keyboard traversal on normally invokes the \fItraverseNextTop\fP
+action, that will call the callbacks of the topmost Common (or
+subclass) widget in the hierarchy. The callback may set the focus to
+another top level widget, with \fIXtCallAcceptFocus\fP.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList nextTop = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNuserData"
+The resource \fIuserData\fP is provided for applications that want to
+attach their own data to a widget. It is not used by the widget itself
+in any way.
+
+
+
+.hi
+
+.nf
+<Pointer> XtPointer userData = NULL
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The type \fIAlignment\fP is actually an integer, but it is given a
+different name to allow a type converter to be installed for it.
+
+
+
+.nf
+
+.B type
+ Alignment = int
+.fi
+
+The symbolic constants can be added together to form an alignment.
+Various widgets use this to position labels, other widgets, etcetera.
+
+
+
+\fBdef\fP XfwfCenter = 0
+
+\fBdef\fP XfwfLeft = 1
+
+\fBdef\fP XfwfRight = 2
+
+\fBdef\fP XfwfTop = 4
+
+\fBdef\fP XfwfBottom = 8
+
+For convenience, the eight possible combinations also have symbolic
+names.
+
+
+
+\fBdef\fP XfwfTopLeft = (XfwfTop +XfwfLeft )
+
+\fBdef\fP XfwfTopRight = (XfwfTop +XfwfRight )
+
+\fBdef\fP XfwfBottomLeft = (XfwfBottom +XfwfLeft )
+
+\fBdef\fP XfwfBottomRight = (XfwfBottom +XfwfRight )
+
+The directions of traversal are used as arguments to the \fItraverse\fP
+method. They are probably only useful to subclasses.
+
+
+
+.nf
+
+.B type
+ TraversalDirection = enum {
+ TraverseLeft, TraverseRight, TraverseUp, TraverseDown,
+ TraverseNext, TraversePrev, TraverseHome, TraverseNextTop }
+.fi
+
+To know the inside area of a Common widget might be useful to other
+widgets than subclasses alone. Calling \fIXfwfCallComputeInside\fP will
+call the \fIcompute_inside\fP method, if available.
+
+.nf
+XfwfCallComputeInside( $, Position * x, Position * y, Dimension * w, Dimension * h)
+.fi
+
+.hi
+{
+ if (XtIsSubclass($, xfwfCommonWidgetClass) $compute_inside)
+ $compute_inside($, x, y, w, h);
+}
+.eh
+
+.hi
+.SS "Actions"
+
+When the widget receives or looses the focus, the border highlight
+is drawn or removed. This action function draws the highlight border
+and in case the widget has set \fItraversalOn\fP, it also sets the
+keyboard focus to the widget itself, or one of its children.
+
+However, FocusIn events may also be so-called virtual events, meaning
+that not the receiving widget, but one of its descendants gets the
+real focus. When \fIfocusIn\fP receives one of those, it removes the
+highlight border.
+
+.hi
+\fBdef\fP focus_detail(detail) =
+(detail ==NotifyAncestor ?"NotifyAncestor":detail ==NotifyVirtual ?"NotifyVirtual":detail ==NotifyInferior ?"NotifyInferior":detail ==NotifyNonlinear ?"NotifyNonlinear":detail ==NotifyNonlinearVirtual ?"NotifyNonlinearVirtual":detail ==NotifyPointer ?"NotifyPointer":detail ==NotifyPointerRoot ?"NotifyPointerRoot":detail ==NotifyDetailNone ?"NotifyDetailNone":"???")
+.eh
+
+.TP
+.I "focusIn
+
+.hi
+
+.nf
+void focusIn($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Time time = CurrentTime;
+
+ if (event->type != FocusIn)
+ XtError("focusIn action may only be bound to FocusIn events");
+ if (! $traversalOn)
+ return;
+ if (event->xfocus.detail == NotifyAncestor
+ || event->xfocus.detail == NotifyInferior
+ || event->xfocus.detail == NotifyNonlinear) {
+ if (! $traversal_focus) (void) $accept_focus($, time);
+ } else if ($traversal_focus) {
+ $unhighlight_border($);
+ $traversal_focus = False;
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "focusOut
+
+This action removes the highlight border.
+
+.hi
+
+.nf
+void focusOut($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if (event->type != FocusOut)
+ XtError("focusOut action may only be bound to FocusOut events");
+ if ($traversal_focus) {
+ $unhighlight_border($);
+ $traversal_focus = False;
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseDown
+
+This and the following actions all call the \fItraverse\fP method of the
+widget's parent, with the appropiate direction arguments.
+\fItraverseDown\fP tries to set the focus to a widget that is located
+roughly below the current one.
+
+.hi
+
+.nf
+void traverseDown($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseDown, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseUp
+
+The action tries to set the focus to a widget that is above the this
+one.
+
+.hi
+
+.nf
+void traverseUp($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseUp, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseLeft
+
+\fItraverseLeft\fP looks for a widget to the left of the current one and
+sets the keyboard focus to that.
+
+.hi
+
+.nf
+void traverseLeft($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseLeft, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseRight
+
+The action looks for a widget that will aceept the focus to the
+right of the current one.
+
+.hi
+
+.nf
+void traverseRight($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseRight, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseNext
+
+The next sibling gets the focus. The precise order is determined by
+the parent, but usually is will be the order in which the widgets were
+created. If there is no suitable sibling, the request is passed to the
+grandparent, so that an `aunt widget' or other relation can get the
+focus.
+
+.hi
+
+.nf
+void traverseNext($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseNext, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traversePrev
+
+The previous widget gets the focus. See also the description of
+\fItraverseNext\fP above.
+
+.hi
+
+.nf
+void traversePrev($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraversePrev, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseNextTop
+
+\fItraverseNextTop\fP finds the topmost ancestor that is a subclass of
+Common and lets it call the \fInextTop\fP callbacks that have been
+registered there. These callbacks can be used by an application that
+has multiple top level windows to set the focus to another window.
+
+.hi
+
+.nf
+void traverseNextTop($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseNextTop, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseHome
+
+The action sets the focus to the sibling widget that is closest to
+the upper left corner of the parent.
+
+.hi
+
+.nf
+void traverseHome($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseHome, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseCurrent
+
+The \fItraverseCurrent\fP action can be used by widgets to set the focus
+to themselves. It is not used in the set of translations that is added
+when \fItraversalOn\fP is set to \fITrue\fP.
+
+.hi
+
+.nf
+void traverseCurrent($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Time time = CurrentTime;
+
+ if ($traversalOn) (void) $accept_focus($, time);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+Most of the included files have to do with the \fIIcon\fP type. Six
+icons are preloaded.
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Xmu/Converters.h>
+.fi
+
+.nf
+
+.B incl
+ <Xfwf/Converters.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+\fIabs\fP, \fImin\fP and \fImax\fP are used often enough in various subclasses
+to define them here. They will end up in the private(!) header file.
+
+
+
+.nf
+ max
+.fi
+
+.nf
+ min
+.fi
+
+.nf
+ abs
+.fi
+
+A private variable is used to track the keyboard focus, but only
+while traversal is on. If \fItraversal_focus\fP is \fITrue\fP, it means that
+the widget has keyboard focus and that that focus is a result of
+keyboard traversal. It also means that the widget's border is
+highlighted, although that is only visible if the \fIhighlightThickness\fP
+is positive.
+
+
+
+.nf
+Boolean traversal_focus
+.fi
+
+The highlight border is filled with a color or a tile.
+
+
+
+.nf
+GC bordergc
+.fi
+
+.hi
+
+.hi
+.SH "Class variables"
+
+\fItraversal_trans\fP holds the compiled version of the
+\fIextraTranslations\fP.
+
+
+
+.nf
+XtTranslations traversal_trans = NULL
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The type converter \fIcvtStringToAlignment\fP is installed in the
+\fIclass_initialize\fP method, after the quarks for the recognized strings
+are created.
+
+The converter from String to Icon needs one extra argument, viz., the
+widget for which the icon is loaded. An offset of 0 should give a
+pointer to the widget itself.
+
+.nf
+class_initialize()
+{
+ static XtConvertArgRec args[] = {
+ { XtWidgetBaseOffset, 0, sizeof(Widget) } };
+
+ XtSetTypeConverter(XtRString, "Alignment", cvtStringToAlignment,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter("Alignment", XtRString, cvtAlignmentToString,
+ NULL, 0, XtCacheNone, NULL);
+ /* init_icon_quarks(); */
+ XtSetTypeConverter(XtRString, "Icon", cvtStringToIcon,
+ args, XtNumber(args), XtCacheNone, NULL);
+}
+.fi
+
+The \fIextraTranslations\fP are compiled into Xt's internal form and
+stored in a class variable \fItraversal_trans\fP, but only if that hasn't
+been done before. (It should have been done in the \fIclass_initialize\fP
+method, but wbuild's `\fI$\fP' syntax doesn't work there (yet)).
+
+If the widget has the \fItraversalOn\fP resource set, the translations are
+merged with the widgets existing translations.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($traversal_trans == NULL)
+ $traversal_trans = XtParseTranslationTable(extraTranslations);
+ if ($traversalOn) {
+ XtAugmentTranslations($, $traversal_trans);
+ $visible_interest = True;
+ }
+ $traversal_focus = False;
+ $bordergc = NULL;
+ create_bordergc($);
+}
+.fi
+
+The \fIset_values\fP method checks if the keyboard traversal has been
+turned on and adds the traversal translations. (It can only be turned
+on, not turned off.)
+
+If something changes that causes the widget to loose keyboard focus,
+the parent is asked to put the focus somewhere else. Otherwise the
+whole application might suddenly loose keyboard focus.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redraw = False;
+ Widget parent = XtParent($);
+ Time time = CurrentTime;
+
+ if ($traversalOn != $old$traversalOn $traversalOn) {
+ XtAugmentTranslations($, $traversal_trans);
+ $visible_interest = True;
+ }
+ if (($sensitive != $old$sensitive
+ || $ancestor_sensitive != $old$ancestor_sensitive
+ || $traversalOn != $old$traversalOn)
+ $traversal_focus) {
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseHome, $, time);
+ }
+ if ($highlightThickness != $old$highlightThickness)
+ need_redraw = True;
+ if ($highlightPixmap != $old$highlightPixmap) {
+ create_bordergc($);
+ need_redraw = True;
+ } else if ($highlightColor != $old$highlightColor) {
+ $highlightPixmap = None;
+ create_bordergc($);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+.fi
+
+A new method \fIcompute_inside\fP is defined, that returns the area
+inside the highlight border. Subclasses should use this to compute
+their drawable area, in preference to computing it from \fI$width\fP and
+\fI$height\fP. Subclasses, such as the Frame widget, redefine the method
+if they add more border material.
+
+.nf
+compute_inside($, Position * x, Position * y, Dimension * w, Dimension * h)
+{
+ *x = $highlightThickness;
+ *y = $highlightThickness;
+ *w = $width - 2 * $highlightThickness;
+ *h = $height - 2 * $highlightThickness;
+}
+.fi
+
+The \fIexpose\fP method draws the highlight border, if there is one.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ if (! XtIsRealized($)) return;
+ if (region != NULL) XSetRegion(XtDisplay($), $bordergc, region);
+ if ($traversal_focus) $highlight_border($);
+ if (region != NULL) XSetClipMask(XtDisplay($), $bordergc, None);
+}
+.fi
+
+When the widget is destroyed and the widget still has the keyboard
+focus, the parent is asked to give it to another widget.
+
+.nf
+destroy($)
+{
+ Widget parent = XtParent($);
+ Time time = CurrentTime;
+
+ if ($traversal_focus) {
+ $sensitive = False;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseHome, $, time);
+ }
+}
+.fi
+
+The border highlight is drawn and removed with two methods, although
+few subclasses will want to redefine them. The methods are called by
+the \fIfocusIn\fP and \fIfocusOut\fP actions and \fIhighlight_border\fP is also
+called by \fIexpose\fP.
+
+.nf
+highlight_border($)
+{
+ XRectangle rect[4];
+
+ if ($highlightThickness == 0) return;
+
+ rect[0].x = 0;
+ rect[0].y = 0;
+ rect[0].width = $width;
+ rect[0].height = $highlightThickness;
+
+ rect[1].x = 0;
+ rect[1].y = 0;
+ rect[1].width = $highlightThickness;
+ rect[1].height = $height;
+
+ rect[2].x = $width - $highlightThickness;
+ rect[2].y = 0;
+ rect[2].width = $highlightThickness;
+ rect[2].height = $height;
+
+ rect[3].x = 0;
+ rect[3].y = $height - $highlightThickness;
+ rect[3].width = $width;
+ rect[3].height = $highlightThickness;
+
+ XFillRectangles(XtDisplay($), XtWindow($), $bordergc, rect[0], 4);
+}
+.fi
+
+.nf
+unhighlight_border($)
+{
+ if ($highlightThickness == 0) return;
+
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, 0, $width, $highlightThickness, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, 0, $highlightThickness, $height, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ $width - $highlightThickness, 0,
+ $highlightThickness, $height, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, $height - $highlightThickness,
+ $width, $highlightThickness, False);
+}
+.fi
+
+When the \fIaccept_focus\fP method is called, the widget should try to set
+the focus to itself or one of its children. If it succeeds, it returns
+\fITrue\fP else \fIFalse\fP. If there are children, each is asked in turn,
+until one is found that accepts the focus. If none is found, the
+widget checks it's own \fIsensitive\fP resource, to see if it can receive
+keyboard events. If so, it sets the focus to itself and returns
+\fITrue\fP, otherwise \fIFalse\fP.
+
+.nf
+Boolean accept_focus($, Time * time)
+{
+ int i;
+
+ if (! XtIsRealized($) || ! $sensitive || ! $traversalOn
+ || ! $visible || ! $ancestor_sensitive || ! $managed
+ || ! $mapped_when_managed || $being_destroyed) return False;
+ for (i = 0; i < $num_children; i++)
+ if (XtCallAcceptFocus($children[i], time)) return True;
+ if (! $traversal_focus) {
+ XSetInputFocus(XtDisplay($), XtWindow($), RevertToParent, *time);
+ $traversal_focus = True;
+ $highlight_border($);
+ }
+ return True;
+}
+.fi
+
+A Common widget (and most subclasses) return \fITrue\fP for
+\fIwould_accept_focus\fP, if the \fIsensitive\fP, \fIvisible\fP and \fItraversalOn\fP
+resources are set and none of the children wants the focus.
+
+.nf
+Boolean would_accept_focus($)
+{
+ int i;
+ Widget child;
+
+ if (! XtIsRealized($) || ! $sensitive || ! $visible || ! $traversalOn)
+ return False;
+ else {
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ if (XtIsSubclass(child, xfwfCommonWidgetClass)
+ $child$would_accept_focus(child))
+ return False;
+ }
+ return True;
+ }
+}
+.fi
+
+The algorithm behind keyboard traversal
+
+* Handling focus events
+
+If a widget receives a (non-virtual) FocusIn event, this is usually
+caused by the \fIaccept_focus\fP method of that widget, except in the case
+that a top level widget receives the focus from the window manager. In
+the first case, the window can just draw the highlight border, in the
+second case, the widget should try to set the focus to one of its
+children.
+
+To be able to distinguish the two cases, the \fIaccept_focus\fP method
+sets the private instance variable \fItraversal_focus\fP to \fITrue\fP before
+it calls \fIXSetInputFocus\fP. The \fIfocusIn\fP action then checks this
+variable and if it is not set, calls the \fIaccept_focus\fP method.
+
+The \fIfocusOut\fP action resets \fItraversal_focus\fP to \fIFalse\fP.
+
+The \fItraversal_focus\fP variable can be interpreted to mean, that the
+widget has the keyboard focus and that it is because of keyboard
+traversal. At least in the Common widget, it can never be \fITrue\fP when
+\fItraversalOn\fP is not set. It can also only be \fITrue\fP when the widget
+actually has the focus, except in the short time between the
+\fIXSetInputFocus\fP call and the delivery of the \fIFocusIn\fP event.
+(However, this scheme depends on the \fIfocusOut\fP action for resetting
+\fItraversal_focus\fP to \fIFalse\fP, so, if the translation for the
+\fIFocusOut\fP event is overridden, it will break down.)
+
+* User events
+
+The \fItraverseXXX\fP actions can be bound to keyboard events. They call
+the \fItraverse\fP method, which will try to change the focus in the
+indicated direction. The directions are: Home, Up, Left, Down, Right,
+Next, Prev. Each direction can be considered a constraint or
+criterium for choosing the focus widget, e.g., `Up' selects the
+nearest widget that is above the current widget. `Next' and `Prev' are
+simpler, in that they do not check the distance, but only the order in
+the list of children.
+
+The \fItraverseCurrent\fP action is different. It is usually bound to a
+mouse click and its task is to set the focus to the widget itself. It
+does this by calling \fIaccept_focus\fP on itself.
+
+The \fItraverse\fP method looks for a widget in the indicated direction,
+within the same application. If the direction is not `Next' or `Prev',
+the method first recurses upwards, to the toplevel widget. From there
+it recurses down again, to all children, grandchildren, etc., looking
+for the widget that best matches the criterium. If a widget is found,
+the focus will be set to it with a call to \fIXSetInputFocus\fP. The
+private variable \fItraversal_focus\fP will be set to \fITrue\fP to indicate
+that the widget received the focus as a result of keyboard traversal,
+and not from the window manager or any other source.
+
+If the \fIdirection\fP argument is `Next' or `Prev', \fItraverse\fP will try
+to set the focus to a sister widget, using the \fIaccept_focus\fP method.
+If there is no suitable sister, the parent will be asked to find an
+aunt widget, and so on.
+
+Note that the \fItraverse\fP and \fIaccept_focus\fP methods of the Common
+widget only set the focus to a child, if the widget itself has
+\fItraversalOn\fP. Thus, setting \fItraversalOn\fP to \fIFalse\fP for a certain
+widget not only excludes the widget itself from keyboard traversal,
+but also all its children.
+
+The \fItraverse\fP function is a method and not a utility function,
+because it is expected that a few subclasses may want to redefine it.
+E.g., the (not yet existing) Group widget may want to limit traversal
+to widgets within itself. (And presumably define new actions to jump
+outside the group.)
+
+To check if a widget suits the criterium, two things must be
+determined: is the widget eligible for the focus and what is the
+distance between the widget and the target position. To be able to
+determine if the widget can accept the focus without actually setting
+it, a method \fIwould_accept_focus\fP is defined, that returns \fITrue\fP if
+the widget is willing to set the focus to itself.
+
+If the \fIdir\fP argument to \fItraverse\fP is \fITraverseNext\fP or
+\fITraversePrev\fP, the \fItraverse_to_next\fP or \fItraverse_to_prev\fP utility
+functions are called. Otherwise, the \fItraverse\fP method checks the
+class of the parent. If the parent is a subclass of \fIXfwfCommon\fP, it
+also has a \fItraverse\fP method and the task of finding a widget to
+traverse to is delegated to the parent. Otherwise, the desired widget
+is looked for with the help of a utility function.
+
+The \fIdir\fP argument is one of Home, Up, Down, Left, Right, Next or
+Prev. The \fIcurrent\fP argument holds the widget that currently has the
+focus and relative to which the focus will have to move.
+
+\fBdef\fP LARGE_NUMBER = 2000000000
+
+.nf
+traverse($, TraversalDirection dir, Widget current, Time * time)
+{
+ Widget w, parent = XtParent($);
+ Position x, y;
+ int distance = LARGE_NUMBER;
+
+ if (dir == TraverseNextTop)
+ traverse_to_next_top($, current, time);
+ else if (dir == TraverseNext)
+ traverse_to_next($, current, time);
+ else if (dir == TraversePrev)
+ traverse_to_prev($, current, time);
+ else if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, dir, current, time);
+ else {
+ switch (dir) {
+ case TraverseHome: x = 0; y = 0; break;
+ case TraverseLeft: x = 0; y = $current$height/2; break;
+ case TraverseDown: x = $current$width/2; y = $current$height; break;
+ case TraverseRight: x = $current$width; y = $current$height/2; break;
+ case TraverseUp: x = $current$width/2; y = 0; break;
+ }
+ if (dir != TraverseHome) XtTranslateCoords(current, x, y, x, y);
+ if (traverse_to_direction($, dir, x, y, w, distance))
+ XtCallAcceptFocus(w, time);
+ }
+}
+.fi
+
+To choose a color that is somewhat darker or lighter than another
+color, the function \fIchoose_color\fP queries the RGB values of a pixel
+and multiplies them with a factor. If all goes well, the function
+returns \fITrue\fP. If the chosen color ends up being the same as the
+original, the color gray75 is returned instead.
+
+It is defined as a method, to make it accessible to subclasses. There
+seems to be no need to make it available globally.
+
+.nf
+Boolean choose_color($, double factor, Pixel base, Pixel * result)
+{
+ XColor color1, color2, dummy;
+
+ color1.pixel = base;
+ XQueryColor(XtDisplay($), DefaultColormapOfScreen(XtScreen($)), color1);
+ color2.red = min(65535, factor * color1.red);
+ color2.green = min(65535, factor * color1.green);
+ color2.blue = min(65535, factor * color1.blue);
+ if (! XAllocColor(XtDisplay($),
+ DefaultColormapOfScreen(XtScreen($)), color2))
+ return False;
+ if (base == color2.pixel) {
+ if (! XAllocNamedColor(XtDisplay($),
+ DefaultColormapOfScreen(XtScreen($)), "gray75",
+ color2, dummy))
+ return False;
+ }
+ *result = color2.pixel;
+ return True;
+}
+.fi
+
+The method \fIlighter_color\fP uses \fIchoose_color\fP to compute a color
+that is 1.5 times as bright as the color passed in as argument. The
+function result is \fITrue\fP if a color was allocated, else \fIFalse\fP.
+
+.nf
+Boolean lighter_color($, Pixel base, Pixel * result)
+{
+ return choose_color($, 1.5, base, result);
+}
+.fi
+
+The method \fIdarker_color\fP uses \fIchoose_color\fP to compute a color
+that is 2/3 times as bright as the color passed in as argument. The
+function result is \fITrue\fP if a color was allocated, else \fIFalse\fP.
+
+.nf
+Boolean darker_color($, Pixel base, Pixel * result)
+{
+ return choose_color($, 0.667, base, result);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The converter \fIcvtStringToAlignment\fP converts strings like `right',
+`top left' and `bottom center' to values of type \fIAlignment\fP.
+
+\fBdef\fP done(type, value) =
+do {
+ if (to->addr != NULL) {
+ if (to->size < sizeof(type)) {
+ to->size = sizeof(type);
+ return False;
+ }
+ *(type*)(to->addr) = (value);
+ } else {
+ static type static_val;
+ static_val = (value);
+ to->addr = (XtPointer)static_val;
+ }
+ to->size = sizeof(type);
+ return True;
+ }while (0 )
+
+.nf
+Boolean cvtStringToAlignment(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ Alignment a = 0;
+ char c, *t, *s = (char*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToAlignment", "wrongParameters",
+ "XtToolkitError",
+ "String to Alignment conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ while (*s) {
+ for (; isspace(*s); s++) ;
+ for (t = s; *t ! isspace(*t); t++) ;
+ c = *t;
+ *t = '\\0';
+ if (XmuCompareISOLatin1(s, "top") == 0) a |= XfwfTop;
+ else if (XmuCompareISOLatin1(s, "bottom") == 0) a |= XfwfBottom;
+ else if (XmuCompareISOLatin1(s, "center") == 0) ; /* skip */
+ else if (XmuCompareISOLatin1(s, "left") == 0) a |= XfwfLeft;
+ else if (XmuCompareISOLatin1(s, "right") == 0) a |= XfwfRight;
+ else {
+ XtDisplayStringConversionWarning(display, (char*) from->addr,
+ "Alignment");
+ break;
+ }
+ *t = c;
+ s = t;
+ }
+ done(Alignment, a);
+}
+.fi
+
+The converter \fIcvtAlignmentToString\fP does the reverse: it convertes values of type \fIAlignment\fP (\fIint\fP's) to strings.
+
+.nf
+Boolean cvtAlignmentToString(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ Alignment *a = (Alignment*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtAlignmentToString", "wrongParameters",
+ "XtToolkitError",
+ "Alignment to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*a) {
+ case XfwfCenter: done(String, "center");
+ case XfwfBottom: done(String, "bottom");
+ case XfwfTop: done(String, "top");
+ case XfwfLeft: done(String, "left");
+ case XfwfRight: done(String, "right");
+ case XfwfBottom + XfwfLeft: done(String, "bottom left");
+ case XfwfBottom + XfwfRight: done(String, "bottom right");
+ case XfwfTop + XfwfLeft: done(String, "top left");
+ case XfwfTop + XfwfRight: done(String, "top right");
+ default: done(String, "unknown");
+ }
+}
+.fi
+
+The following string is the set of translations that will be added
+to any widget that has \fItraversalOn\fP set to \fITrue\fP. The string is
+compiled into Xt's internal representation by the \fIclass_initialize\fP
+method.
+
+.nf
+char extraTranslations[] = "\\
+ <FocusIn>: focusIn()\\n\\
+ <FocusOut>: focusOut()\\n\\
+ <Key>Up: traverseUp()\\n\\
+ <Key>Down: traverseDown()\\n\\
+ <Key>Left: traverseLeft()\\n\\
+ <Key>Right: traverseRight()\\n\\
+ <Key>Next: traverseNext()\\n\\
+ ~Shift<Key>Tab: traverseNext()\\n\\
+ <Key>Prior: traversePrev()\\n\\
+ Shift<Key>Tab: traversePrev()\\n\\
+ <Key>KP_Enter: traverseNextTop()\\n\\
+ <Key>Home: traverseHome()"
+.fi
+
+The \fIcreate_bordergc\fP function creates a new GC for filling the
+highlight border with.
+
+.nf
+create_bordergc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($bordergc) XtReleaseGC($, $bordergc);
+ if ($highlightPixmap != None) {
+ mask = GCFillStyle | GCTile;
+ values.fill_style = FillTiled;
+ values.tile = $highlightPixmap;
+ } else {
+ mask = GCFillStyle | GCForeground;
+ values.fill_style = FillSolid;
+ values.foreground = $highlightColor;
+ }
+ $bordergc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fItraverse_to_direction\fP function returns the nearest child,
+grandchild, etc. in the indicated direction that is willing to accept
+the focus. It returns \fIFalse\fP if no widget is found. The position is the
+absolute coordinates, i.e., relative to the root window. The \fIdistance\fP
+argument holds the distance from \fIx,y\fP of the best widget so far. If the
+function finds a better one, it will return the new distance through
+this parameter.
+
+.nf
+Boolean traverse_to_direction($, TraversalDirection dir, int x, int y, Widget * found, int * distance)
+{
+ int i;
+ Widget child, w;
+ Position rx, ry;
+ int dist;
+ Boolean found_child = False;
+
+ if (! $traversalOn) return False;
+ /*
+ * First recurse to all descendants
+ */
+ for (i = 0; i < $num_children; i++)
+ if (XtIsSubclass($children[i], xfwfCommonWidgetClass)
+ traverse_to_direction($children[i], dir, x, y, found, distance))
+ found_child = True;
+ if (found_child) return True;
+ /*
+ * No child found, now check own position and distance
+ */
+ switch (dir) {
+ case TraverseHome: rx = 0; ry = 0; break;
+ case TraverseLeft: rx = $width; ry = $height/2; break;
+ case TraverseDown: rx = $width/2; ry = 0; break;
+ case TraverseRight: rx = 0; ry = $height/2; break;
+ case TraverseUp: rx = $width/2; ry = $height; break;
+ }
+ XtTranslateCoords($, rx, ry, rx, ry);
+ if ((dir == TraverseUp ry > y)
+ || (dir == TraverseLeft rx > x)
+ || (dir == TraverseDown ry < y)
+ || (dir == TraverseRight rx < x)) return False;
+ dist = (rx - x)*(rx - x) + (ry - y)*(ry - y);
+ if (dist >= *distance) return False;
+ /*
+ * We are the best so far, but do we want the focus?
+ */
+ if (! $would_accept_focus($)) return False;
+ *distance = dist;
+ *found = $;
+ return True;
+}
+.fi
+
+The \fItraverse_to_next\fP routine looks for the \fIcurrent\fP widget among
+its children. If it is found, all children following it will be tried
+until one accepts the focus. If no child does, the routine will try to
+ask the parent to find a sister widget instead.
+
+.nf
+traverse_to_next($, Widget current, Time * time)
+{
+ int i = 0;
+ Widget parent = XtParent($);
+
+ while (i < $num_children $children[i] != current) i++;
+ for (i++; i < $num_children; i++)
+ if (XtCallAcceptFocus($children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseNext, $, time);
+}
+.fi
+
+\fItraverse_to_prev\fP looks for the \fIcurrent\fP widget among the children,
+if it is found, all children before it will be asked in turn to accept
+the focus. If none does, the parent is asked to set the focus to a
+sister instead.
+
+.nf
+traverse_to_prev($, Widget current, Time * time)
+{
+ int i = 0;
+ Widget parent = XtParent($);
+
+ while (i < $num_children $children[i] != current) i++;
+ for (i--; i >= 0; i--)
+ if (XtCallAcceptFocus($children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraversePrev, $, time);
+}
+.fi
+
+.nf
+traverse_to_next_top($, Widget current, Time * time)
+{
+ Widget parent = XtParent($);
+
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseNextTop, current, time);
+ else
+ XtCallCallbackList($, $nextTop, NULL);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/CommonP.h b/vendor/x11iraf/obm/ObmW/CommonP.h
new file mode 100644
index 00000000..e98e2310
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/CommonP.h
@@ -0,0 +1,108 @@
+/* Generated by wbuild from "Common.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfCommonP_H_
+#define _XfwfCommonP_H_
+#include <X11/CompositeP.h>
+#include "Common.h"
+typedef void (*compute_inside_Proc)(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+#define XtInherit_compute_inside ((compute_inside_Proc) _XtInherit)
+typedef void (*highlight_border_Proc)(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define XtInherit_highlight_border ((highlight_border_Proc) _XtInherit)
+typedef void (*unhighlight_border_Proc)(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define XtInherit_unhighlight_border ((unhighlight_border_Proc) _XtInherit)
+typedef Boolean (*would_accept_focus_Proc)(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define XtInherit_would_accept_focus ((would_accept_focus_Proc) _XtInherit)
+typedef void (*traverse_Proc)(
+#if NeedFunctionPrototypes
+Widget,TraversalDirection ,Widget ,Time *
+#endif
+);
+#define XtInherit_traverse ((traverse_Proc) _XtInherit)
+typedef Boolean (*choose_color_Proc)(
+#if NeedFunctionPrototypes
+Widget,double ,Pixel ,Pixel *
+#endif
+);
+#define XtInherit_choose_color ((choose_color_Proc) _XtInherit)
+typedef Boolean (*lighter_color_Proc)(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+#define XtInherit_lighter_color ((lighter_color_Proc) _XtInherit)
+typedef Boolean (*darker_color_Proc)(
+#if NeedFunctionPrototypes
+Widget,Pixel ,Pixel *
+#endif
+);
+#define XtInherit_darker_color ((darker_color_Proc) _XtInherit)
+typedef struct {
+/* methods */
+compute_inside_Proc compute_inside;
+highlight_border_Proc highlight_border;
+unhighlight_border_Proc unhighlight_border;
+would_accept_focus_Proc would_accept_focus;
+#define LARGE_NUMBER 2000000000
+
+
+traverse_Proc traverse;
+choose_color_Proc choose_color;
+lighter_color_Proc lighter_color;
+darker_color_Proc darker_color;
+/* class variables */
+XtTranslations traversal_trans;
+} XfwfCommonClassPart;
+typedef struct _XfwfCommonClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+} XfwfCommonClassRec;
+
+typedef struct {
+/* resources */
+Boolean traversalOn;
+Dimension highlightThickness;
+Pixel highlightColor;
+Pixmap highlightPixmap;
+XtCallbackList nextTop;
+XtPointer userData;
+/* private state */
+#define max(a, b) ((a )>(b )?(a ):(b ))
+
+
+#define min(a, b) ((a )<(b )?(a ):(b ))
+
+
+#define abs(a) ((a )<0 ?-(a ):(a ))
+
+
+Boolean traversal_focus;
+GC bordergc;
+} XfwfCommonPart;
+
+typedef struct _XfwfCommonRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+} XfwfCommonRec;
+
+externalref XfwfCommonClassRec xfwfCommonClassRec;
+
+#endif /* _XfwfCommonP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Container.c b/vendor/x11iraf/obm/ObmW/Container.c
new file mode 100644
index 00000000..cc13769f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Container.c
@@ -0,0 +1,346 @@
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/ContainerP.h>
+
+
+
+#define UnspecifiedPixmap (Pixmap)2
+#define UndefinedGC (GC)2
+
+static void InsPixel();
+
+static XtResource resources[] = {
+#define offset(field) XtOffsetOf(ContainerRec, container.field)
+ {
+ "top.gc", "Top.gc", XtRString, sizeof(String),
+ offset(top_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "bottom.gc", "Bottom.gc", XtRString, sizeof(String),
+ offset(bottom_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(shadow_thickness), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNtopShadowPixmap, XtCTopShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(top_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(top_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNbottomShadowPixmap, XtCBottomShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(bottom_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(bottom_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(foreground), XtRString, (caddr_t) XtDefaultForeground
+ },
+ {
+ XtNuserData, XtCUserData, XtRPixmap, sizeof(Pixmap),
+ offset(user_data), XtRImmediate, (caddr_t) NULL
+ },
+ {
+ XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0
+ }
+
+};
+static void InsPixel(w, off, value)
+ Widget w;
+ int off;
+ XrmValue *value;
+{
+ register ContainerWidget p = (ContainerWidget) w;
+ static Pixel pixel;
+
+ if (off == offset(top_shadow_color))
+ {
+ p->container.top_shadow_GC = UndefinedGC;
+ }
+ else /*bottom_shadow_color */
+ {
+ p->container.bottom_shadow_GC = UndefinedGC;
+ }
+ value->addr = (caddr_t) &pixel;
+}
+
+#undef offset
+
+
+static void ClassInitialize();
+static void ClassPartInitialize();
+static void initialize();
+static void realize();
+static void destroy();
+static void Redisplay();
+
+static Boolean SetValues();
+
+/*static XtGeometryResult query_geometry();*/
+/*static XtGeometryResult geometry_manager();*/
+/*static void changed_managed();*/
+
+ContainerClassRec containerClassRec = {
+ /* Core class part */
+ {
+ /* superclass */ (WidgetClass) &constraintClassRec,
+ /* class_name */ "Container",
+ /* widget_size */ sizeof(ContainerRec),
+ /* class_cnitialize */ ClassInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ XtExposeCompressMultiple,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ destroy,
+ /* resize */ NULL,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ NULL,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ /* Composite class part */
+ {
+ /* geometry manager */ XtInheritGeometryManager,
+ /* change_managed */ XtInheritChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL,
+ },
+ /* Constraint class part */
+ {
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ 0,
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL,
+ },
+ /* Container class part */
+ {
+ /* unused */ 0,
+ }
+};
+
+WidgetClass containerWidgetClass = (WidgetClass)&containerClassRec;
+
+static void
+ClassInitialize()
+{
+}
+
+static void
+ClassPartInitialize(widget_class)
+ WidgetClass widget_class;
+{
+}
+
+/* ARGSUSED */
+static void initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ ContainerWidget sw = (ContainerWidget)new;
+ ContainerPart* cp = (ContainerPart*)&(sw->container);
+
+
+ if (cp->top_shadow_pixmap == UnspecifiedPixmap)
+ cp->top_shadow_pixmap = None;
+
+ if (cp->top_shadow_GC == NULL){
+ if (cp->top_shadow_pixmap != None)
+ cp->top_shadow_GC = AllocGCFromPixmap (new, cp->top_shadow_pixmap);
+ else
+ cp->top_shadow_GC = AllocGCFromPixel (new, cp->top_shadow_color);
+ } else if (cp->top_shadow_GC == UndefinedGC)
+ cp->top_shadow_GC = MakeTopShadowGC (new, new->core.background_pixel);
+
+
+ if (cp->bottom_shadow_pixmap == UnspecifiedPixmap)
+ cp->bottom_shadow_pixmap = None;
+
+ if (cp->bottom_shadow_GC == NULL){
+ if (cp->bottom_shadow_pixmap != None)
+ cp->bottom_shadow_GC = AllocGCFromPixmap (new, cp->bottom_shadow_pixmap);
+ else
+ cp->bottom_shadow_GC = AllocGCFromPixel (new, cp->bottom_shadow_color);
+ } else if (cp->bottom_shadow_GC == UndefinedGC)
+ cp->bottom_shadow_GC =MakeBottomShadowGC (new, new->core.background_pixel);
+
+ cp->background_GC = AllocGCFromPixel (new, new->core.background_pixel);
+}
+
+static void destroy(w)
+ Widget w;
+{
+ register ContainerWidget c = (ContainerWidget)w;
+
+ XtReleaseGC(w, c->container.top_shadow_GC);
+ XtReleaseGC(w, c->container.bottom_shadow_GC);
+ XtReleaseGC(w, c->container.background_GC);
+
+}
+
+static void realize(w, valueMask, attributes)
+ Widget w;
+ Mask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ (*coreClassRec.core_class.realize) (w, valueMask, attributes);
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ ContainerWidget s_old = (ContainerWidget) current;
+ ContainerWidget s_new = (ContainerWidget) new;
+ ContainerPart* sp = (ContainerPart*)&(s_new->container);
+ Boolean redraw = False;
+
+#define NE(field) (s_new->container.field != s_old->container.field)
+
+ if (NE(top_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixmap (new, sp->top_shadow_pixmap);
+ redraw = True;
+
+ }
+ else if (NE(top_shadow_color) && sp->top_shadow_pixmap == None)
+ {
+
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixel (new, sp->top_shadow_color);
+ redraw = True;
+
+ }
+
+ if (NE(bottom_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixmap (new, sp->bottom_shadow_pixmap);
+ redraw = True;
+
+ }
+ else if (NE(bottom_shadow_color) && sp->bottom_shadow_pixmap == None)
+ {
+
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixel (new, sp->bottom_shadow_color);
+ redraw = True;
+
+ }
+
+#undef NE
+
+ return redraw;
+}
+
+
+/* ARGSUSED */
+static void Redisplay(gw, event, region)
+ Widget gw;
+ XEvent *event; /* unused */
+ Region region; /* unused */
+{
+ register ContainerWidget c = (ContainerWidget) gw;
+
+ XClearWindow (XtDisplay(gw), XtWindow(gw));
+
+ XawDrawFrame (gw,
+ 0,
+ 0,
+ c->core.width,
+ c->core.height,
+ XawRAISED,
+ c->container.shadow_thickness,
+ c->container.top_shadow_GC,
+ c->container.bottom_shadow_GC);
+
+}
+
+void _XawQueryGeometry (widget, reply_return)
+ Widget widget;
+ XtWidgetGeometry *reply_return;
+{
+ XtGeometryResult result;
+ String subs[1];
+ Cardinal num_subs;
+ WidgetClass class;
+
+ if (widget != (Widget)NULL)
+ {
+
+ reply_return->request_mode = CWWidth | CWHeight;
+
+ result = XtQueryGeometry (widget, NULL, reply_return);
+
+ switch (result)
+ {
+ case XtGeometryNo :
+ case XtGeometryYes :
+ reply_return->width = widget->core.width;
+ reply_return->height = widget->core.height;
+ break;
+ case XtGeometryAlmost :
+ if (!(reply_return->request_mode & CWWidth))
+ reply_return->width = widget->core.width;
+
+ if (!(reply_return->request_mode & CWHeight))
+ reply_return->height = widget->core.height;
+ break;
+ default :
+ class = XtClass(widget);
+ subs[0] = class->core_class.class_name;
+ num_subs = 1;
+ XtAppWarningMsg(
+ XtWidgetToApplicationContext(widget),
+ "QueryGeometry",
+ "QueryGeometry",
+ "WidgetToolkit",
+ "WidgetClass '%s' returns invalid value for XtQueryGeometry",
+ subs, &num_subs);
+ break;
+ }
+ reply_return->request_mode = CWWidth | CWHeight;
+ }
+}
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Container.h b/vendor/x11iraf/obm/ObmW/Container.h
new file mode 100644
index 00000000..a6164a9d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Container.h
@@ -0,0 +1,61 @@
+#ifndef _XawContainer_h
+#define _XawContainer_h
+
+
+#include <X11/Xraw/XawInit.h>
+
+/***********************************************************************
+ *
+ * Container Widget (subclass of CompositeClass)
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ hSpace HSpace Dimension 4
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+/* New fields */
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+#define XtNcontainerType "containerType"
+#define XtCContainerType "ContainerType"
+#define XtRContainerType "ContainerType"
+
+/* Class record constants */
+
+extern WidgetClass containerWidgetClass;
+
+typedef struct _ContainerClassRec *ContainerWidgetClass;
+typedef struct _ContainerRec *ContainerWidget;
+
+#endif /* _XawContainer_h */
diff --git a/vendor/x11iraf/obm/ObmW/ContainerP.h b/vendor/x11iraf/obm/ObmW/ContainerP.h
new file mode 100644
index 00000000..25097a74
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ContainerP.h
@@ -0,0 +1,71 @@
+#ifndef _CONTEINER_P_H_
+#define _CONTEINER_P_H_
+
+
+#include <X11/ConstrainP.h>
+#include <X11/Xraw/Container.h>
+
+#define CORE(w) ((Widget)(w))->core
+#define COMPOSITE(w) ((CompositeWidget)(w))->composite
+#define CONTAINER(w) ((ContainerWidget)(w))->container
+
+typedef struct {
+
+ /* public instance variables */
+
+ Pixel foreground;
+
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+
+ Dimension shadow_thickness;
+
+ XtPointer user_data;
+
+ /* private instance variables */
+
+ GC bottom_shadow_GC;
+ GC top_shadow_GC;
+ GC background_GC;
+
+} ContainerPart;
+
+
+typedef struct _ContainerRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+} ContainerRec;
+
+typedef struct _ContainerClassPart{
+ int unused;
+} ContainerClassPart;
+
+
+typedef struct _ContainerClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+} ContainerClassRec;
+
+/* container constraints */
+
+typedef struct _ContainerConstraintPart {
+ int unused;
+} ContainerConstraintPart;
+
+typedef struct _ContainerConstraintRec {
+ ContainerConstraintPart container;
+} ContainerCosntraintRec, *ContainerConstraintPtr;
+
+extern ContainerClassRec containerClassRec;
+
+
+extern void _XawQueryGeometry Xraw_PROTO((Widget widget,
+ XtWidgetGeometry *reply_return));
+
+#endif /* _CONTEINER_P_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Converters.h b/vendor/x11iraf/obm/ObmW/Converters.h
new file mode 100644
index 00000000..45f15fad
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Converters.h
@@ -0,0 +1,42 @@
+#ifndef _Converters_h
+#define _Converters_h
+
+Boolean XfwfCvtLongToString(
+#if NeedFunctionPrototypes
+ Display *display,
+ XrmValuePtr args,
+ Cardinal *num_args,
+ XrmValuePtr from,
+ XrmValuePtr to,
+ XtPointer *converter_data
+#endif
+);
+
+Boolean cvtStringToIcon(
+#if NeedFunctionPrototypes
+ Display *dpy,
+ XrmValue *args,
+ Cardinal *num_args,
+ XrmValue *from,
+ XrmValue *to,
+ XtPointer *converter_data
+#endif
+);
+
+#ifndef NO_XPM
+
+#include <xpm.h>
+
+/* The |Icon| type is a convenient combination of a pixmap, a mask and
+the pixmaps's attributes. Not all attributes are stored, only width
+and height. */
+
+typedef struct _Icon {
+ Pixmap pixmap;
+ Pixmap mask;
+ XpmAttributes attributes;
+} Icon;
+
+#endif
+
+#endif /* _Converters_h */
diff --git a/vendor/x11iraf/obm/ObmW/DrawIString.c b/vendor/x11iraf/obm/ObmW/DrawIString.c
new file mode 100644
index 00000000..6f81404e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/DrawIString.c
@@ -0,0 +1,45 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "TabString.h"
+
+/*
+ * Like DrawImageString, except it takes an additional "tabs"
+ * argument, used to specify what horizontal pixel position to
+ * move to when tab characters are present in the string. If
+ * the "tabs" argument is NULL, works exactly like its
+ * counterpart.
+ */
+void
+XfwfDrawImageString(display, drawable, gc, x, y, string, length, tabs)
+ Display *display;
+ Drawable drawable;
+ GC gc;
+ int x;
+ int y;
+ String string;
+ int length;
+ int *tabs;
+{
+ register char *p, *ep;
+ register int tx, tab;
+
+ tab = tx = 0;
+ for (p = string; length; )
+ {
+ ep = strnchr(p, '\t', length);
+ if (ep && tabs)
+ {
+ XDrawImageString(display, drawable, gc, x+tx, y,
+ p, ep - p);
+ tx = tabs[tab++];
+ length -= ep - p + 1;
+ p = ep + 1;
+ }
+ else
+ {
+ XDrawImageString(display, drawable, gc, x+tx, y,
+ p, length);
+ break;
+ }
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/DrawString.c b/vendor/x11iraf/obm/ObmW/DrawString.c
new file mode 100644
index 00000000..280504e8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/DrawString.c
@@ -0,0 +1,45 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "TabString.h"
+
+/*
+ * Like DrawString, except it takes an additional "tabs"
+ * argument, used to specify what horizontal pixel position to
+ * move to when tab characters are present in the string. If
+ * the "tabs" argument is NULL, works exactly like its
+ * counterpart.
+ */
+void
+XfwfDrawString(display, drawable, gc, x, y, string, length, tabs)
+ Display *display;
+ Drawable drawable;
+ GC gc;
+ int x;
+ int y;
+ String string;
+ int length;
+ int *tabs;
+{
+ register char *p, *ep;
+ register int tx, tab;
+
+ tab = tx = 0;
+ for (p = string; length; )
+ {
+ ep = strnchr(p, '\t', length);
+ if (ep && tabs)
+ {
+ XDrawString(display, drawable, gc, x+tx, y,
+ p, ep - p);
+ tx = tabs[tab++];
+ length -= ep - p + 1;
+ p = ep + 1;
+ }
+ else
+ {
+ XDrawString(display, drawable, gc, x+tx, y,
+ p, length);
+ break;
+ }
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/DrawingArea.c b/vendor/x11iraf/obm/ObmW/DrawingArea.c
new file mode 100644
index 00000000..a316b03c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/DrawingArea.c
@@ -0,0 +1,193 @@
+/*
+ * A minimalistic constraint widget
+ *
+ * Sun Sep 12 20:03:49 GMT 1993 Gustaf Neumann
+ */
+
+#ifndef MOTIF
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+/*
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xaw/XawInit.h>
+*/
+
+#include "DrawingAreaP.h"
+
+/* Private Definitions */
+
+static void ClassInitialize(), ClassPartInitialize(), Initialize(), Resize();
+static void ConstraintInitialize();
+static Boolean SetValues(), ConstraintSetValues();
+static XtGeometryResult GeometryManager(), PreferredGeometry();
+static void ChangeManaged();
+
+DrawingAreaClassRec drawingAreaClassRec = {
+ { /* core_class fields */
+ /* superclass */ (WidgetClass) &constraintClassRec,
+ /* class_name */ "DrawingArea",
+ /* widget_size */ sizeof(DrawingAreaRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_init */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ NULL,
+ /* num_resources */ 0,
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+ /* expose */ XtInheritExpose,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ PreferredGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* composite_class fields */
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ NULL, /*ChangeManaged,*/
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ },
+ { /* constraint_class fields */
+ /* subresourses */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ 0,
+ /* initialize */ NULL, /*ConstraintInitialize,*/
+ /* destroy */ NULL,
+ /* set_values */ NULL, /*ConstraintSetValues,*/
+ /* extension */ NULL
+ },
+ { /* DrawingArea_class fields */
+ /* dummy */ 0
+ }
+};
+
+WidgetClass drawingAreaWidgetClass = (WidgetClass)&drawingAreaClassRec;
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+static void ClassInitialize()
+{
+}
+
+static void ClassPartInitialize(class)
+ WidgetClass class;
+{
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+/*
+ DrawingAreaWidget daw = (DrawingAreaWidget)new;
+*/
+}
+
+static void Resize(w)
+ Widget w;
+{
+/*
+ DrawingAreaWidget daw = (DrawingAreaWidget)w;
+ WidgetList children = daw->composite.children;
+ int num_children = daw->composite.num_children;
+ Widget *childP;
+ Position x, y;
+ Dimension width, height;
+*/
+}
+
+
+/* ARGSUSED */
+static XtGeometryResult GeometryManager(w, request, reply)
+ Widget w;
+ XtWidgetGeometry *request;
+ XtWidgetGeometry *reply; /* RETURN */
+{
+/*
+ Dimension old_width, old_height;
+ DrawingAreaWidget daw = (DrawingAreaWidget) XtParent(w);
+ DrawingAreaConstraints DrawingArea = (DrawingAreaConstraints) w->core.constraints;
+ XtWidgetGeometry allowed;
+ XtGeometryResult ret_val;
+*/
+ return(XtGeometryNo);
+}
+
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ return( FALSE );
+}
+
+
+/*ARGSUSED*/
+static Boolean ConstraintSetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+/*
+ register DrawingAreaConstraints cfc =
+ (DrawingAreaConstraints) current->core.constraints;
+ register DrawingAreaConstraints nfc =
+ (DrawingAreaConstraints) new->core.constraints;
+ */
+ return( FALSE );
+}
+
+static void ChangeManaged(w)
+ Widget w;
+{
+/*
+ DrawingAreaWidget daw = (DrawingAreaWidget)w;
+ DrawingAreaConstraints DrawingArea;
+ WidgetList children, childP;
+ int num_children = daw->composite.num_children;
+ Widget child;
+*/
+}
+
+
+static XtGeometryResult PreferredGeometry( widget, request, reply )
+ Widget widget;
+ XtWidgetGeometry *request, *reply;
+{
+/*
+ DrawingAreaWidget w = (DrawingAreaWidget)widget;
+ */
+ return XtGeometryNo;
+}
+
+
+
+#endif
diff --git a/vendor/x11iraf/obm/ObmW/DrawingArea.h b/vendor/x11iraf/obm/ObmW/DrawingArea.h
new file mode 100644
index 00000000..2d8938f4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/DrawingArea.h
@@ -0,0 +1,35 @@
+#ifndef _XawDrawingArea_h
+#define _XawDrawingArea_h
+
+/* #include <X11/Constraint.h> */
+/***********************************************************************
+ *
+ * DrawingArea Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ defaultDistance Thickness int 4
+ destroyCallback Callback Pointer NULL
+ height Height Dimension computed at realize
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension computed at realize
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+typedef struct _DrawingAreaClassRec *DrawingAreaWidgetClass;
+typedef struct _DrawingAreaRec *DrawingAreaWidget;
+
+extern WidgetClass drawingAreaWidgetClass;
+
+#endif /* _XawDrawingArea_h */
diff --git a/vendor/x11iraf/obm/ObmW/DrawingAreaP.h b/vendor/x11iraf/obm/ObmW/DrawingAreaP.h
new file mode 100644
index 00000000..221f7180
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/DrawingAreaP.h
@@ -0,0 +1,45 @@
+
+/* DrawingArea widget private definitions */
+
+#ifndef _XawDrawingAreaP_h
+#define _XawDrawingAreaP_h
+
+#include "DrawingArea.h"
+#include <X11/ConstrainP.h>
+
+#define XtInheritLayout ((Boolean (*)())_XtInherit)
+
+typedef struct {
+ int dummy;
+} DrawingAreaClassPart;
+
+
+typedef struct _DrawingAreaClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ DrawingAreaClassPart drawingArea_class;
+} DrawingAreaClassRec;
+
+extern DrawingAreaClassRec drawingAreaClassRec;
+
+typedef struct _DrawingAreaPart {
+ int dummy;
+} DrawingAreaPart;
+
+typedef struct _DrawingAreaRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ DrawingAreaPart drawingArea;
+} DrawingAreaRec;
+
+typedef struct _DrawingAreaConstraintsPart {
+ int dummy;
+} DrawingAreaConstraintsPart;
+
+typedef struct _DrawingAreaConstraintsRec {
+ int dummy;
+} DrawingAreaConstraintsRec, *DrawingAreaConstraints;
+
+#endif /* _XawDrawingAreaP_h */
diff --git a/vendor/x11iraf/obm/ObmW/FIXFWF b/vendor/x11iraf/obm/ObmW/FIXFWF
new file mode 100755
index 00000000..23d97fa9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/FIXFWF
@@ -0,0 +1,6 @@
+#! /bin/csh
+# -- Used to massage FWF widgets to fit the OBM directory structure.
+
+foreach i (`grep -l Xfwf *.[ch]`)
+ echo $i; sed -f FWFSED $i > temp; mv temp $i
+end
diff --git a/vendor/x11iraf/obm/ObmW/FWFSED b/vendor/x11iraf/obm/ObmW/FWFSED
new file mode 100644
index 00000000..97092e37
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/FWFSED
@@ -0,0 +1,17 @@
+s+<Xfwf/\(.*\)>+"\1"+
+/^#line /D
+s/"XfwfArrow"/"XfwfArrow"/
+s/"XfwfBoard"/"Board"/
+s/"XfwfButton"/"TextButton"/
+s/"XfwfCommon"/"XfwfCommon"/
+s/"XfwfFrame"/"Frame"/
+s/"XfwfGroup"/"Group"/
+s/"XfwfIcon"/"Icon"/
+s/"XfwfLabel"/"TextBox"/
+s/"XfwfMenuBar"/"XfwfMenuBar"/
+s/"XfwfMultiList"/"MultiList"/
+s/"XfwfRadioGroup"/"RadioGroup"/
+s/"XfwfRowCol"/"RowCol"/
+s/"XfwfScrollbar"/"Scrollbar2"/
+s/"XfwfSlider2"/"Slider2d"/
+s/"XfwfToggle"/"TextToggle"/
diff --git a/vendor/x11iraf/obm/ObmW/Frame.c b/vendor/x11iraf/obm/ObmW/Frame.c
new file mode 100644
index 00000000..47080b53
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Frame.c
@@ -0,0 +1,654 @@
+/* Generated by wbuild from "Frame.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <string.h>
+#include <stdio.h>
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/CharSet.h>
+#include "stip4.bm"
+#include "FrameP.h"
+static void set_shadow(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"set_shadow", set_shadow},
+};
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void class_initialize(
+#if NeedFunctionPrototypes
+void
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void realize(
+#if NeedFunctionPrototypes
+Widget,XtValueMask *,XSetWindowAttributes *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void compute_inside(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+static XtGeometryResult query_geometry(
+#if NeedFunctionPrototypes
+Widget,XtWidgetGeometry *,XtWidgetGeometry *
+#endif
+);
+static XtGeometryResult geometry_manager(
+#if NeedFunctionPrototypes
+Widget ,XtWidgetGeometry *,XtWidgetGeometry *
+#endif
+);
+static void resize(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void change_managed(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define done(type, value) do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ }while (0 )
+
+
+static char rcsid[] = "$Header: Frame.w,v 1.5 92/11/02 14:07:52 bert Exp $";
+static void create_darkgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_lightgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void compute_topcolor(
+#if NeedFunctionPrototypes
+Widget,int ,XrmValue *
+#endif
+);
+static void compute_bottomcolor(
+#if NeedFunctionPrototypes
+Widget,int ,XrmValue *
+#endif
+);
+/*ARGSUSED*/static void create_darkgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.darkgc != NULL) XtReleaseGC(self, ((XfwfFrameWidget)self)->xfwfFrame.darkgc);
+ switch (((XfwfFrameWidget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfFrameWidget)self)->xfwfFrame.bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = ((XfwfFrameWidget)self)->xfwfFrame.bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen(self));
+ values.background = ((XfwfFrameWidget)self)->core.background_pixel;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.darker_color(self, ((XfwfFrameWidget)self)->core.background_pixel, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfFrameWidget)self)->core.background_pixel;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple = ((XfwfFrameWidget)self)->xfwfFrame.stip4;
+ }
+ break;
+ }
+ ((XfwfFrameWidget)self)->xfwfFrame.darkgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_lightgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.lightgc != NULL) XtReleaseGC(self, ((XfwfFrameWidget)self)->xfwfFrame.lightgc);
+ switch (((XfwfFrameWidget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfFrameWidget)self)->xfwfFrame.topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfFrameWidget)self)->core.background_pixel;
+ values.stipple = ((XfwfFrameWidget)self)->xfwfFrame.topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.lighter_color(self, ((XfwfFrameWidget)self)->core.background_pixel, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfFrameWidget)self)->core.background_pixel;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple = ((XfwfFrameWidget)self)->xfwfFrame.stip4;
+ }
+ break;
+ }
+ ((XfwfFrameWidget)self)->xfwfFrame.lightgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void compute_topcolor(self,offset,value)Widget self;int offset;XrmValue * value;
+{
+ static Pixel color;
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.lighter_color(self, ((XfwfFrameWidget)self)->core.background_pixel, &color);
+ value->addr = (XtPointer) &color;
+}
+/*ARGSUSED*/static void compute_bottomcolor(self,offset,value)Widget self;int offset;XrmValue * value;
+{
+ static Pixel color;
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.darker_color(self, ((XfwfFrameWidget)self)->core.background_pixel, &color);
+ value->addr = (XtPointer) &color;
+}
+
+static XtResource resources[] = {
+{XtNcursor,XtCCursor,XtRCursor,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.cursor),XtOffsetOf(XfwfFrameRec,xfwfFrame.cursor),XtRImmediate,(XtPointer)None },
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfFrameRec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfRaised },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfFrameRec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)0 },
+{XtNouterOffset,XtCOuterOffset,XtRDimension,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.outerOffset),XtOffsetOf(XfwfFrameRec,xfwfFrame.outerOffset),XtRImmediate,(XtPointer)0 },
+{XtNinnerOffset,XtCInnerOffset,XtRDimension,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.innerOffset),XtOffsetOf(XfwfFrameRec,xfwfFrame.innerOffset),XtRImmediate,(XtPointer)0 },
+{XtNshadowScheme,XtCShadowScheme,XtRShadowScheme,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.shadowScheme),XtOffsetOf(XfwfFrameRec,xfwfFrame.shadowScheme),XtRImmediate,(XtPointer)XfwfAuto },
+{XtNtopShadowColor,XtCTopShadowColor,XtRPixel,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.topShadowColor),XtOffsetOf(XfwfFrameRec,xfwfFrame.topShadowColor),XtRCallProc,(XtPointer)compute_topcolor },
+{XtNbottomShadowColor,XtCBottomShadowColor,XtRPixel,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.bottomShadowColor),XtOffsetOf(XfwfFrameRec,xfwfFrame.bottomShadowColor),XtRCallProc,(XtPointer)compute_bottomcolor },
+{XtNtopShadowStipple,XtCTopShadowStipple,XtRBitmap,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.topShadowStipple),XtOffsetOf(XfwfFrameRec,xfwfFrame.topShadowStipple),XtRImmediate,(XtPointer)NULL },
+{XtNbottomShadowStipple,XtCBottomShadowStipple,XtRBitmap,sizeof(((XfwfFrameRec*)NULL)->xfwfFrame.bottomShadowStipple),XtOffsetOf(XfwfFrameRec,xfwfFrame.bottomShadowStipple),XtRImmediate,(XtPointer)NULL },
+{XtNborderWidth,XtCBorderWidth,XtRDimension,sizeof(((XfwfFrameRec*)NULL)->core.border_width),XtOffsetOf(XfwfFrameRec,core.border_width),XtRImmediate,(XtPointer)0 },
+};
+
+XfwfFrameClassRec xfwfFrameClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfCommonClassRec,
+"Frame",
+sizeof(XfwfFrameRec),
+class_initialize,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+realize,
+actionsList,
+1,
+resources,
+11,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+resize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+query_geometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+geometry_manager,
+change_managed,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+};
+WidgetClass xfwfFrameWidgetClass = (WidgetClass) &xfwfFrameClassRec;
+/*ARGSUSED*/
+static void set_shadow(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Position x, y;
+ Dimension w, h;
+ FrameType f = XfwfSunken;
+
+ if (*num_params == 0) f = ((XfwfFrameWidget)self)->xfwfFrame.old_frame_type; /* Reset to old style */
+ else if (strcmp("raised", params[0]) == 0) f = XfwfRaised;
+ else if (strcmp("sunken", params[0]) == 0) f = XfwfSunken;
+ else if (strcmp("chiseled", params[0]) == 0) f = XfwfChiseled;
+ else if (strcmp("ledged", params[0]) == 0) f = XfwfLedged;
+ else XtWarning("Unknown frame type in set_shadow action");
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.frameType != f) {
+ ((XfwfFrameWidget)self)->xfwfFrame.frameType = f;
+ xfwfCommonClassRec.xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ XfwfDrawFrame(self, x + ((XfwfFrameWidget)self)->xfwfFrame.outerOffset, y + ((XfwfFrameWidget)self)->xfwfFrame.outerOffset,
+ w - 2*((XfwfFrameWidget)self)->xfwfFrame.outerOffset, h - 2*((XfwfFrameWidget)self)->xfwfFrame.outerOffset,
+ ((XfwfFrameWidget)self)->xfwfFrame.frameType, ((XfwfFrameWidget)self)->xfwfFrame.frameWidth, ((XfwfFrameWidget)self)->xfwfFrame.lightgc, ((XfwfFrameWidget)self)->xfwfFrame.darkgc);
+ }
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfFrameWidgetClass c = (XfwfFrameWidgetClass) class;
+ XfwfFrameWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfFrameWidgetClass) return;
+ super = (XfwfFrameWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void class_initialize()
+{
+ static XtConvertArgRec screenArg[] = {
+ {XtBaseOffset, (XtPointer)XtOffset(Widget, core.screen), sizeof(Screen*)}};
+
+ XtSetTypeConverter(XtRString, XtRFrameType, cvtStringToFrameType,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRFrameType, XtRString, cvtFrameTypeToString,
+ NULL, 0, XtCacheNone, NULL);
+
+ XtAddConverter(XtRString, XtRBitmap, XmuCvtStringToBitmap,
+ screenArg, XtNumber(screenArg));
+
+ XtSetTypeConverter(XtRString, XtRShadowScheme, cvtStringToShadowScheme,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRShadowScheme, XtRString, cvtShadowSchemeToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfFrameWidget)self)->xfwfFrame.lightgc = NULL;
+ ((XfwfFrameWidget)self)->xfwfFrame.darkgc = NULL;
+ ((XfwfFrameWidget)self)->xfwfFrame.old_frame_type = ((XfwfFrameWidget)self)->xfwfFrame.frameType;
+}
+/*ARGSUSED*/static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
+{
+#ifdef USE_CWCURSOR
+ *mask |= CWCursor;
+#endif
+ attributes->cursor = ((XfwfFrameWidget)self)->xfwfFrame.cursor;
+ xfwfCommonClassRec.core_class.realize(self, mask, attributes);
+
+ ((XfwfFrameWidget)self)->xfwfFrame.stip4 = XCreateBitmapFromData(XtDisplay(self), XtWindow(self),
+ stip4_bits, stip4_width, stip4_height);
+
+ if (! ((XfwfFrameWidget)self)->xfwfFrame.topShadowStipple) ((XfwfFrameWidget)self)->xfwfFrame.topShadowStipple = ((XfwfFrameWidget)self)->xfwfFrame.stip4;
+ if (! ((XfwfFrameWidget)self)->xfwfFrame.bottomShadowStipple) ((XfwfFrameWidget)self)->xfwfFrame.bottomShadowStipple = ((XfwfFrameWidget)self)->xfwfFrame.stip4;
+
+ create_lightgc(self);
+ create_darkgc(self);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redisplay = False;
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.cursor != ((XfwfFrameWidget)old)->xfwfFrame.cursor && XtIsRealized(self))
+ XDefineCursor(XtDisplay(self), XtWindow(self), ((XfwfFrameWidget)self)->xfwfFrame.cursor);
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.frameType == XfwfChiseled || ((XfwfFrameWidget)self)->xfwfFrame.frameType == XfwfLedged)
+ ((XfwfFrameWidget)self)->xfwfFrame.frameWidth = 2 * ((int) (((XfwfFrameWidget)self)->xfwfFrame.frameWidth / 2));
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.shadowScheme != ((XfwfFrameWidget)old)->xfwfFrame.shadowScheme) {
+ create_darkgc(self);
+ create_lightgc(self);
+ need_redisplay = True;
+ } else if (((XfwfFrameWidget)self)->xfwfFrame.shadowScheme == XfwfColor) {
+ if (((XfwfFrameWidget)self)->xfwfFrame.topShadowColor != ((XfwfFrameWidget)old)->xfwfFrame.topShadowColor) {
+ create_lightgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfFrameWidget)self)->xfwfFrame.bottomShadowColor != ((XfwfFrameWidget)old)->xfwfFrame.bottomShadowColor) {
+ create_darkgc(self);
+ need_redisplay = True;
+ }
+ } else if (((XfwfFrameWidget)self)->xfwfFrame.shadowScheme == XfwfStipple) {
+ if (((XfwfFrameWidget)self)->xfwfFrame.topShadowStipple != ((XfwfFrameWidget)old)->xfwfFrame.topShadowStipple) {
+ create_lightgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfFrameWidget)self)->xfwfFrame.bottomShadowStipple != ((XfwfFrameWidget)old)->xfwfFrame.bottomShadowStipple) {
+ create_darkgc(self);
+ need_redisplay = True;
+ }
+ }
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.outerOffset != ((XfwfFrameWidget)old)->xfwfFrame.outerOffset)
+ need_redisplay = True;
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.innerOffset != ((XfwfFrameWidget)old)->xfwfFrame.innerOffset)
+ need_redisplay = True;
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.frameType != ((XfwfFrameWidget)old)->xfwfFrame.frameType) {
+ ((XfwfFrameWidget)self)->xfwfFrame.old_frame_type = ((XfwfFrameWidget)self)->xfwfFrame.frameType;
+ need_redisplay = True;
+ }
+
+ if (((XfwfFrameWidget)self)->xfwfFrame.frameWidth != ((XfwfFrameWidget)old)->xfwfFrame.frameWidth)
+ need_redisplay = True;
+ else if (((XfwfFrameWidget)self)->xfwfFrame.frameWidth == 0)
+ need_redisplay = False;
+
+ return need_redisplay;
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Position x, y;
+ Dimension w, h;
+
+ if (! XtIsRealized(self)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay(self), ((XfwfFrameWidget)self)->xfwfFrame.lightgc, region);
+ XSetRegion(XtDisplay(self), ((XfwfFrameWidget)self)->xfwfFrame.darkgc, region);
+ }
+ xfwfCommonClassRec.xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ XfwfDrawFrame(self, x + ((XfwfFrameWidget)self)->xfwfFrame.outerOffset, y + ((XfwfFrameWidget)self)->xfwfFrame.outerOffset, w - 2*((XfwfFrameWidget)self)->xfwfFrame.outerOffset,
+ h - 2*((XfwfFrameWidget)self)->xfwfFrame.outerOffset, ((XfwfFrameWidget)self)->xfwfFrame.frameType, ((XfwfFrameWidget)self)->xfwfFrame.frameWidth, ((XfwfFrameWidget)self)->xfwfFrame.lightgc, ((XfwfFrameWidget)self)->xfwfFrame.darkgc);
+ if (region != NULL) {
+ XSetClipMask(XtDisplay(self), ((XfwfFrameWidget)self)->xfwfFrame.lightgc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfFrameWidget)self)->xfwfFrame.darkgc, None);
+ }
+ xfwfCommonClassRec.core_class.expose(self, event, region);
+}
+/*ARGSUSED*/static void compute_inside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ int ww, hh; /* DCT */
+
+ xfwfCommonClassRec.xfwfCommon_class.compute_inside(self, x, y, w, h);
+ *x += ((XfwfFrameWidget)self)->xfwfFrame.outerOffset + ((XfwfFrameWidget)self)->xfwfFrame.frameWidth + ((XfwfFrameWidget)self)->xfwfFrame.innerOffset;
+ *y += ((XfwfFrameWidget)self)->xfwfFrame.outerOffset + ((XfwfFrameWidget)self)->xfwfFrame.frameWidth + ((XfwfFrameWidget)self)->xfwfFrame.innerOffset;
+
+ /* 17Mar94 DCT - keep w,h from wrapping around to 65xxxx. */
+
+/* For reasons which are not clear avoiding wrap-around here causes
+ * geometry management to fail in some circumstances while determining the
+ * initial frame size during startup.
+ *
+ * ww = *w;
+ * *w = max (0, ww - 2 * (((XfwfFrameWidget)self)->xfwfFrame.outerOffset +
+ * ((XfwfFrameWidget)self)->xfwfFrame.frameWidth +
+ * ((XfwfFrameWidget)self)->xfwfFrame.innerOffset));
+ * hh = *h;
+ * *h = max (0, hh - 2 * (((XfwfFrameWidget)self)->xfwfFrame.outerOffset +
+ * ((XfwfFrameWidget)self)->xfwfFrame.frameWidth +
+ * ((XfwfFrameWidget)self)->xfwfFrame.innerOffset));
+ */
+ *w -= 2 * (((XfwfFrameWidget)self)->xfwfFrame.outerOffset + ((XfwfFrameWidget)self)->xfwfFrame.frameWidth + ((XfwfFrameWidget)self)->xfwfFrame.innerOffset);
+ *h -= 2 * (((XfwfFrameWidget)self)->xfwfFrame.outerOffset + ((XfwfFrameWidget)self)->xfwfFrame.frameWidth + ((XfwfFrameWidget)self)->xfwfFrame.innerOffset);
+}
+
+/*ARGSUSED*/static XtGeometryResult query_geometry(self,request,reply)Widget self;XtWidgetGeometry * request;XtWidgetGeometry * reply;
+{
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Dimension h;
+
+ if (((XfwfFrameWidget)self)->composite.num_children == 0) return XtGeometryYes;
+
+ /* We're only interested in size and stacking order */
+ reply->request_mode =
+ (CWWidth | CWHeight | CWStackMode) & request->request_mode;
+
+ /* If nothing of interest is left, we can return immediately */
+ if (reply->request_mode == 0)
+ return XtGeometryYes;
+
+ /* Prepare a request to the child */
+ h = 2 * (((XfwfFrameWidget)self)->xfwfFrame.outerOffset + ((XfwfFrameWidget)self)->xfwfFrame.frameWidth + ((XfwfFrameWidget)self)->xfwfFrame.innerOffset);
+ request2.request_mode = reply->request_mode;
+ request2.width = request->width - h;
+ request2.height = request->height - h;
+ request2.sibling = request->sibling;
+ request2.stack_mode = request->stack_mode;
+
+ result = XtQueryGeometry(((XfwfFrameWidget)self)->composite.children[0], &request2, &reply2);
+
+ /* If the child accepted its proposal, we accept ours */
+ if (result == XtGeometryYes) return XtGeometryYes;
+
+ /* If the child doesn't want any change, we don't want any, either */
+ if (result == XtGeometryNo) return XtGeometryNo;
+
+ /* Otherwise, ignore everything but size and stacking order */
+ reply->request_mode &= reply2.request_mode;
+ if (reply->request_mode == 0) return XtGeometryYes;
+
+ reply->width = reply2.width + h;
+ reply->height = reply2.height + h;
+ reply->sibling = reply2.sibling;
+ reply->stack_mode = reply2.stack_mode;
+ return XtGeometryAlmost;
+}
+/*ARGSUSED*/static XtGeometryResult geometry_manager(child,request,reply)Widget child;XtWidgetGeometry * request;XtWidgetGeometry * reply;
+{ Widget self = XtParent(child); {
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Position x, y;
+ Dimension w, h, extraw, extrah;
+
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ if (! (request->request_mode & (CWWidth|CWHeight))) return XtGeometryYes;
+ extraw = ((XfwfFrameWidget)self)->core.width - w;
+ extrah = ((XfwfFrameWidget)self)->core.height - h;
+ request2.request_mode = request->request_mode & (CWWidth|CWHeight);
+ request2.width = request->width + extraw;
+ request2.height = request->height + extrah;
+ result = XtMakeGeometryRequest(self, &request2, &reply2);
+ if (result == XtGeometryNo) return XtGeometryNo;
+ if (result == XtGeometryYes) return XtGeometryYes;
+ reply->request_mode = reply2.request_mode & (CWWidth|CWHeight);
+ reply->width = reply2.width - extraw;
+ reply->height = reply2.height - extrah;
+ return XtGeometryAlmost;
+}
+}
+/*ARGSUSED*/static void resize(self)Widget self;
+{
+ Position x, y;
+ Dimension w, h;
+ Widget child;
+
+ if (((XfwfFrameWidget)self)->composite.num_children == 0) return;
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ child = ((XfwfFrameWidget)self)->composite.children[0];
+ w -= 2 * ((XfwfFrameWidget)child)->core.border_width;
+ h -= 2 * ((XfwfFrameWidget)child)->core.border_width;
+ XtConfigureWidget(child, x, y, w, h, ((XfwfFrameWidget)child)->core.border_width);
+}
+/*ARGSUSED*/static void change_managed(self)Widget self;
+{
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Widget child;
+ Position x, y;
+ Dimension w, h;
+
+ if (((XfwfFrameWidget)self)->composite.num_children == 0) return;
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ child = ((XfwfFrameWidget)self)->composite.children[0];
+ request2.request_mode = CWWidth | CWHeight;
+ request2.width = ((XfwfFrameWidget)child)->core.width + ((XfwfFrameWidget)self)->core.width - w;
+ request2.height = ((XfwfFrameWidget)child)->core.height + ((XfwfFrameWidget)self)->core.height - h;
+ result = XtMakeGeometryRequest(self, &request2, &reply2);
+ ((XfwfFrameWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ w -= 2 * ((XfwfFrameWidget)child)->core.border_width;
+ h -= 2 * ((XfwfFrameWidget)child)->core.border_width;
+ XtConfigureWidget(child, x, y, w, h, ((XfwfFrameWidget)child)->core.border_width);
+}
+/*ARGSUSED*/void XfwfDrawFrame(self,x,y,w,h,tp,t,lightgc,darkgc)Widget self;int x;int y;int w;int h;FrameType tp;int t;GC lightgc;GC darkgc;
+{
+ XPoint tlPoints[7], brPoints[7];
+
+ if (t == 0) return;
+ switch (tp) {
+ case XfwfRaised:
+ case XfwfSunken:
+ tlPoints[0].x = x; tlPoints[0].y = y;
+ tlPoints[1].x = x + w; tlPoints[1].y = y;
+ tlPoints[2].x = x + w - t; tlPoints[2].y = y + t;
+ tlPoints[3].x = x + t; tlPoints[3].y = y + t;
+ tlPoints[4].x = x + t; tlPoints[4].y = y + h - t;
+ tlPoints[5].x = x; tlPoints[5].y = y + h;
+ tlPoints[6].x = x; tlPoints[6].y = y;
+ brPoints[0].x = x + w; brPoints[0].y = y + h;
+ brPoints[1].x = x; brPoints[1].y = y + h;
+ brPoints[2].x = x + t; brPoints[2].y = y + h - t;
+ brPoints[3].x = x + w - t; brPoints[3].y = y + h - t;
+ brPoints[4].x = x + w - t; brPoints[4].y = y + t;
+ brPoints[5].x = x + w; brPoints[5].y = y;
+ brPoints[6].x = x + w; brPoints[6].y = y + h;
+ if (tp == XfwfSunken) {
+ XFillPolygon(XtDisplay(self), XtWindow(self),
+ darkgc, tlPoints, 7, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), XtWindow(self),
+ lightgc, brPoints, 7, Nonconvex, CoordModeOrigin);
+ } else {
+ XFillPolygon(XtDisplay(self), XtWindow(self),
+ lightgc, tlPoints, 7, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplay(self), XtWindow(self),
+ darkgc, brPoints, 7, Nonconvex, CoordModeOrigin);
+ }
+ break;
+ case XfwfLedged:
+ XfwfDrawFrame(self, x, y, w, h, XfwfRaised, t/2, lightgc, darkgc);
+ XfwfDrawFrame(self, x+t/2, y+t/2, w-2*(int)(t/2), h-2*(int)(t/2),
+ XfwfSunken, t/2, lightgc, darkgc);
+ break;
+ case XfwfChiseled:
+ XfwfDrawFrame(self, x, y, w, h, XfwfSunken, t/2, lightgc, darkgc);
+ XfwfDrawFrame(self, x+t/2, y+t/2, w-2*(int)(t/2), h-2*(int)(t/2),
+ XfwfRaised, t/2, lightgc, darkgc);
+ break;
+ }
+
+}
+/*ARGSUSED*/Boolean cvtStringToFrameType(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToFrameType", "wrongParameters",
+ "XtToolkitError",
+ "String to frame type conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "raised") == 0) done(FrameType, XfwfRaised);
+ if (XmuCompareISOLatin1(s, "sunken") == 0) done(FrameType, XfwfSunken);
+ if (XmuCompareISOLatin1(s, "chiseled") == 0) done(FrameType, XfwfChiseled);
+ if (XmuCompareISOLatin1(s, "ledged") == 0) done(FrameType, XfwfLedged);
+ XtDisplayStringConversionWarning(display, s, XtRFrameType);
+ done(FrameType, XfwfRaised);
+}
+/*ARGSUSED*/Boolean cvtFrameTypeToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtFrameTypeToString", "wrongParameters",
+ "XtToolkitError",
+ "Fframe type to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*(FrameType*)from->addr) {
+ case XfwfRaised: done(String, "raised");
+ case XfwfSunken: done(String, "sunken");
+ case XfwfChiseled: done(String, "chiseled");
+ case XfwfLedged: done(String, "ledged");
+ default: XtError("Illegal FrameType");
+ }
+}
+/*ARGSUSED*/Boolean cvtStringToShadowScheme(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToShadowScheme", "wrongParameters",
+ "XtToolkitError",
+ "String to shadow scheme conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "auto")==0) done(ShadowScheme, XfwfAuto);
+ if (XmuCompareISOLatin1(s, "color")==0) done(ShadowScheme, XfwfColor);
+ if (XmuCompareISOLatin1(s, "stipple")==0) done(ShadowScheme, XfwfStipple);
+ XtDisplayStringConversionWarning(display, s, XtRShadowScheme);
+ done(ShadowScheme, XfwfAuto);
+}
+/*ARGSUSED*/Boolean cvtShadowSchemeToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtShadowSchemeToString", "wrongParameters",
+ "XtToolkitError",
+ "Shadow scheme to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ switch (*(ShadowScheme*)from->addr) {
+ case XfwfAuto: done(String, "auto");
+ case XfwfColor: done(String, "color");
+ case XfwfStipple: done(String, "stipple");
+ default: XtError("Illegal ShadowScheme");
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Frame.h b/vendor/x11iraf/obm/ObmW/Frame.h
new file mode 100644
index 00000000..eafe109c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Frame.h
@@ -0,0 +1,142 @@
+/* Generated by wbuild from "Frame.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfFrame_H_
+#define _XfwfFrame_H_
+#include "Common.h"
+typedef enum {
+ XfwfRaised, XfwfSunken, XfwfChiseled, XfwfLedged } FrameType;
+
+typedef enum {XfwfAuto, XfwfColor, XfwfStipple} ShadowScheme;
+
+typedef Pixmap Bitmap;
+
+void XfwfDrawFrame(
+#if NeedFunctionPrototypes
+Widget,int ,int ,int ,int ,FrameType ,int ,GC ,GC
+#endif
+);
+Boolean cvtStringToFrameType(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+Boolean cvtFrameTypeToString(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+Boolean cvtStringToShadowScheme(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+Boolean cvtShadowSchemeToString(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+#ifndef XtNcursor
+#define XtNcursor "cursor"
+#endif
+#ifndef XtCCursor
+#define XtCCursor "Cursor"
+#endif
+#ifndef XtRCursor
+#define XtRCursor "Cursor"
+#endif
+
+#ifndef XtNframeType
+#define XtNframeType "frameType"
+#endif
+#ifndef XtCFrameType
+#define XtCFrameType "FrameType"
+#endif
+#ifndef XtRFrameType
+#define XtRFrameType "FrameType"
+#endif
+
+#ifndef XtNframeWidth
+#define XtNframeWidth "frameWidth"
+#endif
+#ifndef XtCFrameWidth
+#define XtCFrameWidth "FrameWidth"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNouterOffset
+#define XtNouterOffset "outerOffset"
+#endif
+#ifndef XtCOuterOffset
+#define XtCOuterOffset "OuterOffset"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNinnerOffset
+#define XtNinnerOffset "innerOffset"
+#endif
+#ifndef XtCInnerOffset
+#define XtCInnerOffset "InnerOffset"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNshadowScheme
+#define XtNshadowScheme "shadowScheme"
+#endif
+#ifndef XtCShadowScheme
+#define XtCShadowScheme "ShadowScheme"
+#endif
+#ifndef XtRShadowScheme
+#define XtRShadowScheme "ShadowScheme"
+#endif
+
+#ifndef XtNtopShadowColor
+#define XtNtopShadowColor "topShadowColor"
+#endif
+#ifndef XtCTopShadowColor
+#define XtCTopShadowColor "TopShadowColor"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNbottomShadowColor
+#define XtNbottomShadowColor "bottomShadowColor"
+#endif
+#ifndef XtCBottomShadowColor
+#define XtCBottomShadowColor "BottomShadowColor"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNtopShadowStipple
+#define XtNtopShadowStipple "topShadowStipple"
+#endif
+#ifndef XtCTopShadowStipple
+#define XtCTopShadowStipple "TopShadowStipple"
+#endif
+#ifndef XtRBitmap
+#define XtRBitmap "Bitmap"
+#endif
+
+#ifndef XtNbottomShadowStipple
+#define XtNbottomShadowStipple "bottomShadowStipple"
+#endif
+#ifndef XtCBottomShadowStipple
+#define XtCBottomShadowStipple "BottomShadowStipple"
+#endif
+#ifndef XtRBitmap
+#define XtRBitmap "Bitmap"
+#endif
+
+typedef struct _XfwfFrameClassRec *XfwfFrameWidgetClass;
+typedef struct _XfwfFrameRec *XfwfFrameWidget;
+externalref WidgetClass xfwfFrameWidgetClass;
+#endif /*_XfwfFrame_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Frame.man b/vendor/x11iraf/obm/ObmW/Frame.man
new file mode 100644
index 00000000..66fdb4c3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Frame.man
@@ -0,0 +1,1062 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfFrame
+.SH DESCRIPTION
+The Frame widget is a composite widget that accepts just one child.
+Its only purpose is to draw a frame around widgets that do not have a
+frame of their own. It always uses the size of its child, with a
+little extra for the frame. There are several types of frames
+available, selectable with a resource.
+
+Widget writers can also use the Frame class as a superclass for new
+widgets. The frame is drawn by the \fIexpose\fP method (which must
+therefore be called by subclasses). Its width is given by
+\fIXtNframeWidth\fP, the appearance by \fIXtNframeType\fP. The possible types
+are:
+
+\item{\fIXfwfRaised\fP} Gives a beveled look. The top and left borders will
+be lighter, the bottom and right sides darker.
+
+\item{\fIXfwfSunken\fP} Just the opposite.
+
+\item{\fIXfwfChiseled\fP} The border will look as if it was made with a
+chisel.
+
+\item{\fIXfwfLedged\fP} The border will be a ledge that juts out of the
+background.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNcursor"
+The cursor (when not \fINone\fP) is the mouse cursor that is displayed
+when the mouse is over the Board widget. The default value \fINone\fP
+causes the parent's cursor to be used.
+
+
+
+.hi
+
+.nf
+Cursor cursor = None
+.fi
+
+.eh
+
+.TP
+.I "XtNframeType"
+The \fIXtNframeType\fP determines how the border looks.
+
+
+
+.hi
+
+.nf
+FrameType frameType = XfwfRaised
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+\fIXtNframeWidth\fP gives the width of the border. The default value
+of 0 shows no border at all. The border is drawn {\it inside\/} the
+widget. (See also \fIXtNouterOffset\fP.)
+
+
+
+.hi
+
+.nf
+Dimension frameWidth = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNouterOffset"
+Normally, the border is draw along the outer edge of the widget, but
+it can be moved inward. \fIXtNouterOffset\fP is the number of pixels
+between the edge and the frame.
+
+
+
+.hi
+
+.nf
+Dimension outerOffset = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNinnerOffset"
+Between the frame and whatever is inside the widget, there is also
+margin. By default, however, it is 0.
+
+
+
+.hi
+
+.nf
+Dimension innerOffset = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNshadowScheme"
+The colors of the top and bottom shadows can be set with the
+resources \fItopShadowColor\fP and \fIbottomShadowColor\fP, but it is also
+possible to use a stiple of foreground and background colors. This may
+be preferable on workstations with limited or no color capabilities.
+However, the easiest way (which is also the default) is to let the
+widget determine its own shadow colors or stipples, based on the
+widget's background color and the color capabilities of the screen.
+
+The resource \fIshadowScheme\fP can be set to \fIXfwfColor\fP, \fIXfwfStipple\fP
+or \fIXfwfAuto\fP. The converter for the shadow pixmap accepts the strings
+\fI"stipple0"\fP through \fI"stipple8"\fP, which create pixmaps of the current
+background and foreground colors, with \fI"stipple0"\fP entirely
+background and \fI"stipple8"\fP entirely foreground. Setting pixmaps or
+colors is only useful when \fIshadowScheme\fP is set to \fIXfwfStipple\fP or
+\fIXfwfColor\fP respectively.
+
+The values of \fItopShadowColor\fP and \fIbottomShadowColor\fP are ignored by
+the Frame widget as long as \fIshadowScheme\fP is not \fIXfwfColor\fP, but the
+default values are computed nevertheless, since they are useful, e.g.,
+when an icon uses `topShadowColor' and `bottomShadowColor' as dynamic
+colors.
+
+
+
+.hi
+
+.nf
+ShadowScheme shadowScheme = XfwfAuto
+.fi
+
+.eh
+
+.TP
+.I "XtNtopShadowColor"
+
+.hi
+
+.nf
+Pixel topShadowColor = <CallProc>compute_topcolor
+.fi
+
+.eh
+
+.TP
+.I "XtNbottomShadowColor"
+
+.hi
+
+.nf
+Pixel bottomShadowColor = <CallProc>compute_bottomcolor
+.fi
+
+.eh
+
+.TP
+.I "XtNtopShadowStipple"
+
+.hi
+
+.nf
+Bitmap topShadowStipple = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNbottomShadowStipple"
+
+.hi
+
+.nf
+Bitmap bottomShadowStipple = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNborder_width"
+The inherited resource \fIborderWidth\fP is given a default value of 0,
+instead of 1.
+
+
+
+.hi
+
+.nf
+ border_width = 0
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+A number of new types is introduced by the Common class. The
+possible types of borders are enumerated in \fIFrame3dType\fP (see the
+introduction).
+
+
+
+.nf
+
+.B type
+ FrameType = enum {
+ XfwfRaised, XfwfSunken, XfwfChiseled, XfwfLedged }
+.fi
+
+The shadow scheme can be used to choose colors, pixmaps or automatic
+shadows.
+
+
+
+.nf
+
+.B type
+ ShadowScheme = enum {XfwfAuto, XfwfColor, XfwfStipple}
+.fi
+
+The type \fIBitmap\fP is an alias for \fIPixmap\fP, but it is meant to
+contain only bitmaps, i.e., pixmaps of depth one.
+
+
+
+.nf
+
+.B type
+ Bitmap = Pixmap
+.fi
+
+The routine that draws the border is generally useful, so it is
+exported. \fIt\fP is the thickness of the frame. The frame is drawn inside
+the rectangle \fI(x, y, x+w-1, y+h-1)\fP.
+
+.nf
+XfwfDrawFrame( $, int x, int y, int w, int h, FrameType tp, int t, GC lightgc, GC darkgc)
+.fi
+
+.hi
+{
+ XPoint tlPoints[7], brPoints[7];
+
+ if (t == 0) return;
+ switch (tp) {
+ case XfwfRaised:
+ case XfwfSunken:
+ tlPoints[0].x = x; tlPoints[0].y = y;
+ tlPoints[1].x = x + w; tlPoints[1].y = y;
+ tlPoints[2].x = x + w - t; tlPoints[2].y = y + t;
+ tlPoints[3].x = x + t; tlPoints[3].y = y + t;
+ tlPoints[4].x = x + t; tlPoints[4].y = y + h - t;
+ tlPoints[5].x = x; tlPoints[5].y = y + h;
+ tlPoints[6].x = x; tlPoints[6].y = y;
+ brPoints[0].x = x + w; brPoints[0].y = y + h;
+ brPoints[1].x = x; brPoints[1].y = y + h;
+ brPoints[2].x = x + t; brPoints[2].y = y + h - t;
+ brPoints[3].x = x + w - t; brPoints[3].y = y + h - t;
+ brPoints[4].x = x + w - t; brPoints[4].y = y + t;
+ brPoints[5].x = x + w; brPoints[5].y = y;
+ brPoints[6].x = x + w; brPoints[6].y = y + h;
+ if (tp == XfwfSunken) {
+ XFillPolygon(XtDisplay($), XtWindow($),
+ darkgc, tlPoints, 7, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplay($), XtWindow($),
+ lightgc, brPoints, 7, Nonconvex, CoordModeOrigin);
+ } else {
+ XFillPolygon(XtDisplay($), XtWindow($),
+ lightgc, tlPoints, 7, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplay($), XtWindow($),
+ darkgc, brPoints, 7, Nonconvex, CoordModeOrigin);
+ }
+ break;
+ case XfwfLedged:
+ XfwfDrawFrame($, x, y, w, h, XfwfRaised, t/2, lightgc, darkgc);
+ XfwfDrawFrame($, x+t/2, y+t/2, w-2*(int)(t/2), h-2*(int)(t/2),
+ XfwfSunken, t/2, lightgc, darkgc);
+ break;
+ case XfwfChiseled:
+ XfwfDrawFrame($, x, y, w, h, XfwfSunken, t/2, lightgc, darkgc);
+ XfwfDrawFrame($, x+t/2, y+t/2, w-2*(int)(t/2), h-2*(int)(t/2),
+ XfwfRaised, t/2, lightgc, darkgc);
+ break;
+ }
+
+}
+.eh
+
+\fIcvtStringToFrameType\fP converts the strings `raised', `sunken',
+`chiseled' and `ledged'. Case doesn't matter.
+
+.nf
+Boolean cvtStringToFrameType(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+.fi
+
+.hi
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToFrameType", "wrongParameters",
+ "XtToolkitError",
+ "String to frame type conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "raised") == 0) done(FrameType, XfwfRaised);
+ if (XmuCompareISOLatin1(s, "sunken") == 0) done(FrameType, XfwfSunken);
+ if (XmuCompareISOLatin1(s, "chiseled") == 0) done(FrameType, XfwfChiseled);
+ if (XmuCompareISOLatin1(s, "ledged") == 0) done(FrameType, XfwfLedged);
+ XtDisplayStringConversionWarning(display, s, XtRFrameType);
+ done(FrameType, XfwfRaised);
+}
+.eh
+
+.nf
+Boolean cvtFrameTypeToString(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+.fi
+
+.hi
+{
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtFrameTypeToString", "wrongParameters",
+ "XtToolkitError",
+ "Fframe type to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*(FrameType*)from->addr) {
+ case XfwfRaised: done(String, "raised");
+ case XfwfSunken: done(String, "sunken");
+ case XfwfChiseled: done(String, "chiseled");
+ case XfwfLedged: done(String, "ledged");
+ default: XtError("Illegal FrameType");
+ }
+}
+.eh
+
+The converter \fIcvtStringToShadowScheme\fP converts strings `color',
+`auto' and `stipple' to \fIXfwfColor\fP, \fIXfwfAuto\fP and \fIXfwfStipple\fP.
+
+.nf
+Boolean cvtStringToShadowScheme(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+.fi
+
+.hi
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToShadowScheme", "wrongParameters",
+ "XtToolkitError",
+ "String to shadow scheme conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "auto")==0) done(ShadowScheme, XfwfAuto);
+ if (XmuCompareISOLatin1(s, "color")==0) done(ShadowScheme, XfwfColor);
+ if (XmuCompareISOLatin1(s, "stipple")==0) done(ShadowScheme, XfwfStipple);
+ XtDisplayStringConversionWarning(display, s, XtRShadowScheme);
+ done(ShadowScheme, XfwfAuto);
+}
+.eh
+
+.nf
+Boolean cvtShadowSchemeToString(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+.fi
+
+.hi
+{
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtShadowSchemeToString", "wrongParameters",
+ "XtToolkitError",
+ "Shadow scheme to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ switch (*(ShadowScheme*)from->addr) {
+ case XfwfAuto: done(String, "auto");
+ case XfwfColor: done(String, "color");
+ case XfwfStipple: done(String, "stipple");
+ default: XtError("Illegal ShadowScheme");
+ }
+}
+.eh
+
+.hi
+.SS "Actions"
+
+.TP
+.I "set_shadow
+
+Although the Frame widget has no translations, one action is
+defined, that may be of use to subclasses. The action function
+\fIset_shadow\fP can be used to change the shadow frame. It has zero or
+one argument. Without an argument, it resets the shadow to its
+original type; with an argument, it sets the shadow to the type given
+in the argument.
+
+Warning: the function uses the \fIXfwfDrawFrame\fP routine to draw the
+frames directly, instead of calling the \fIexpose\fP or even \fIset_values\fP
+methods. Any subclass that defines behaviour that depends on knowing
+the frame type, will have to redefine the \fIset_shadow\fP action.
+
+.hi
+
+.nf
+void set_shadow($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Position x, y;
+ Dimension w, h;
+ FrameType f = XfwfSunken;
+
+ if (*num_params == 0) f = $old_frame_type; /* Reset to old style */
+ else if (strcmp("raised", params[0]) == 0) f = XfwfRaised;
+ else if (strcmp("sunken", params[0]) == 0) f = XfwfSunken;
+ else if (strcmp("chiseled", params[0]) == 0) f = XfwfChiseled;
+ else if (strcmp("ledged", params[0]) == 0) f = XfwfLedged;
+ else XtWarning("Unknown frame type in set_shadow action");
+
+ if ($frameType != f) {
+ $frameType = f;
+ #compute_inside($, x, y, w, h);
+ XfwfDrawFrame($, x + $outerOffset, y + $outerOffset,
+ w - 2*$outerOffset, h - 2*$outerOffset,
+ $frameType, $frameWidth, $lightgc, $darkgc);
+ }
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <string.h>
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Xmu/Converters.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Xmu/CharSet.h>
+.fi
+
+The stipple for the shadows is loaded from a bitmap file.
+
+.nf
+
+.B incl
+ "stip4.bm"
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The GC for drawing the light parts of the frame:
+
+
+
+.nf
+GC lightgc
+.fi
+
+The GC for drawing the dark parts of the frame:
+
+
+
+.nf
+GC darkgc
+.fi
+
+The \fIstip4\fP bitmap is used on screens with insufficient colors to
+simulate light and dark shadows. It will be created by the
+\fIinitialize\fP method, whether or not it is needed. Since it is but a
+small bitmap, this can't hurt much.
+
+
+
+.nf
+Pixmap stip4
+.fi
+
+The \fIold_frame_type\fP variable is used by the \fIset_shadow\fP action
+function to store the original frame type, when it is temporarily
+changed.
+
+
+
+.nf
+FrameType old_frame_type
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+\fIclass_initialize\fP installs the type converters. The type converters
+back to String are installed as a convenience, so resources can be
+retrieved in readable form with \fIXtVaGetValues\fP.
+
+.nf
+class_initialize()
+{
+ static XtConvertArgRec screenArg[] = {
+ {XtBaseOffset, (XtPointer)XtOffset(Widget, core.screen), sizeof(Screen*)}};
+
+ XtSetTypeConverter(XtRString, XtRFrameType, cvtStringToFrameType,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRFrameType, XtRString, cvtFrameTypeToString,
+ NULL, 0, XtCacheNone, NULL);
+
+ XtAddConverter(XtRString, XtRBitmap, XmuCvtStringToBitmap,
+ screenArg, XtNumber(screenArg));
+
+ XtSetTypeConverter(XtRString, XtRShadowScheme, cvtStringToShadowScheme,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRShadowScheme, XtRString, cvtShadowSchemeToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+.fi
+
+Much of the initialization that one would expect in the \fIinitialize\fP
+method is actually delegated to the \fIrealize\fP method, since a window
+ID is needed for most of the initializations.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $lightgc = NULL;
+ $darkgc = NULL;
+ $old_frame_type = $frameType;
+}
+.fi
+
+The \fIrealize\fP method uses the inherited method, but adds the cursor
+attribute.
+
+This is also the place to create the \fIstip4\fP bitmap, that is used for
+stippled shadows. It could not be created in \fIinitialize\fP, since
+creating a bitmap requires a window ID.
+
+The GC's must be created after the \fIstip4\fP bitmaps, since they might
+have to use it as a stipple.
+
+.nf
+realize($, XtValueMask * mask, XSetWindowAttributes * attributes)
+{
+ *mask |= CWCursor;
+ attributes->cursor = $cursor;
+ #realize($, mask, attributes);
+
+ $stip4 = XCreateBitmapFromData(XtDisplay($), XtWindow($),
+ stip4_bits, stip4_width, stip4_height);
+
+ if (! $topShadowStipple) $topShadowStipple = $stip4;
+ if (! $bottomShadowStipple) $bottomShadowStipple = $stip4;
+
+ create_lightgc($);
+ create_darkgc($);
+}
+.fi
+
+The \fIset_values\fP method has to create new GC's if the resources
+change. It also makes sure that \fIframeWidth\fP is even if the frame type
+is chiseled or ledged.
+
+If the frame width was and is zero, nothing needs to be drawn,
+regardless of the changes in other resources. Therefore, at the end
+\fIneed_redisplay\fP is set to False.
+
+When the cursor changes, the \fIset_values\fP method uses the
+\fIXDefineCursor\fP routine to set the attribute on the widget's window,
+provided the widget is realized.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redisplay = False;
+
+ if ($cursor != $old$cursor XtIsRealized($))
+ XDefineCursor(XtDisplay($), XtWindow($), $cursor);
+
+ if ($frameType == XfwfChiseled || $frameType == XfwfLedged)
+ $frameWidth = 2 * ((int) ($frameWidth / 2));
+
+ if ($shadowScheme != $old$shadowScheme) {
+ create_darkgc($);
+ create_lightgc($);
+ need_redisplay = True;
+ } else if ($shadowScheme == XfwfColor) {
+ if ($topShadowColor != $old$topShadowColor) {
+ create_lightgc($);
+ need_redisplay = True;
+ }
+ if ($bottomShadowColor != $old$bottomShadowColor) {
+ create_darkgc($);
+ need_redisplay = True;
+ }
+ } else if ($shadowScheme == XfwfStipple) {
+ if ($topShadowStipple != $old$topShadowStipple) {
+ create_lightgc($);
+ need_redisplay = True;
+ }
+ if ($bottomShadowStipple != $old$bottomShadowStipple) {
+ create_darkgc($);
+ need_redisplay = True;
+ }
+ }
+
+ if ($outerOffset != $old$outerOffset)
+ need_redisplay = True;
+
+ if ($innerOffset != $old$innerOffset)
+ need_redisplay = True;
+
+ if ($frameType != $old$frameType) {
+ $old_frame_type = $frameType;
+ need_redisplay = True;
+ }
+
+ if ($frameWidth != $old$frameWidth)
+ need_redisplay = True;
+ else if ($frameWidth == 0)
+ need_redisplay = False;
+
+ return need_redisplay;
+}
+.fi
+
+The \fIexpose\fP method draws the frame, for which it uses the
+\fIXfwfDrawFrame\fP routine. Before it calls the routine, it sets the clip
+region. Afterwards, the clip region is reset, because we don't know
+which other widgets share the same GC's. As explained in {\em X
+Toolkit Intrinsics Programming Manual} (Nye \& O'Reilly, Motif
+Edition, 1990, p~223), the test for \fIXtIsRealized\fP is there for the
+unlikely case when an expose event arrives after the widget has been
+destroyed or unrealized.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Position x, y;
+ Dimension w, h;
+
+ if (! XtIsRealized($)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay($), $lightgc, region);
+ XSetRegion(XtDisplay($), $darkgc, region);
+ }
+ #compute_inside($, x, y, w, h);
+ XfwfDrawFrame($, x + $outerOffset, y + $outerOffset, w - 2*$outerOffset,
+ h - 2*$outerOffset, $frameType, $frameWidth, $lightgc, $darkgc);
+ if (region != NULL) {
+ XSetClipMask(XtDisplay($), $lightgc, None);
+ XSetClipMask(XtDisplay($), $darkgc, None);
+ }
+ #expose($, event, region);
+}
+.fi
+
+The method \fIcompute_inside\fP is re-defined. The method now returns
+the area inside the frame. It calls the superclass's method and then
+decreases the area by the width of the frame.
+
+.nf
+compute_inside($, Position * x, Position * y, Dimension * w, Dimension * h)
+{
+ #compute_inside($, x, y, w, h);
+ *x += $outerOffset + $frameWidth + $innerOffset;
+ *y += $outerOffset + $frameWidth + $innerOffset;
+ *w -= 2 * ($outerOffset + $frameWidth + $innerOffset);
+ *h -= 2 * ($outerOffset + $frameWidth + $innerOffset);
+}
+.fi
+
+A Frame widget passes its parent's inquiry on to its (presumably)
+single child. If there is no child, the proposal is accepted.
+The border and position proposals are always accepted, the stacking
+order and size are left to the child to decide.
+
+.nf
+XtGeometryResult query_geometry($, XtWidgetGeometry * request, XtWidgetGeometry * reply)
+{
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Dimension h;
+
+ if ($num_children == 0) return XtGeometryYes;
+
+ /* We're only interested in size and stacking order */
+ reply->request_mode =
+ (CWWidth | CWHeight | CWStackMode) request->request_mode;
+
+ /* If nothing of interest is left, we can return immediately */
+ if (reply->request_mode == 0)
+ return XtGeometryYes;
+
+ /* Prepare a request to the child */
+ h = 2 * ($outerOffset + $frameWidth + $innerOffset);
+ request2.request_mode = reply->request_mode;
+ request2.width = request->width - h;
+ request2.height = request->height - h;
+ request2.sibling = request->sibling;
+ request2.stack_mode = request->stack_mode;
+
+ result = XtQueryGeometry($children[0], request2, reply2);
+
+ /* If the child accepted its proposal, we accept ours */
+ if (result == XtGeometryYes) return XtGeometryYes;
+
+ /* If the child doesn't want any change, we don't want any, either */
+ if (result == XtGeometryNo) return XtGeometryNo;
+
+ /* Otherwise, ignore everything but size and stacking order */
+ reply->request_mode = reply2.request_mode;
+ if (reply->request_mode == 0) return XtGeometryYes;
+
+ reply->width = reply2.width + h;
+ reply->height = reply2.height + h;
+ reply->sibling = reply2.sibling;
+ reply->stack_mode = reply2.stack_mode;
+ return XtGeometryAlmost;
+}
+.fi
+
+Requests by the child to be resized are passed on to the parent. If
+the parent replies with \fIXtGeometryYes\fP, the change is accepted and
+(if not \fIXtCWQueryOnly\fP) already done. In that case the Frame widget
+accepts its child's request. If the parent replies with
+\fIXtGeometryNo\fP, the change is denied and the denial is passed on. If
+the parent replies with a different geometry, the geometry is passed
+on, after compensating for the frame width.
+
+Requests for anything other than width or height are always granted.
+
+.nf
+XtGeometryResult geometry_manager(Widget child, XtWidgetGeometry * request, XtWidgetGeometry * reply)
+{
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Position x, y;
+ Dimension w, h, extraw, extrah;
+
+ $compute_inside($, x, y, w, h);
+ if (! (request->request_mode (CWWidth|CWHeight))) return XtGeometryYes;
+ extraw = $width - w;
+ extrah = $height - h;
+ request2.request_mode = request->request_mode (CWWidth|CWHeight);
+ request2.width = request->width + extraw;
+ request2.height = request->height + extrah;
+ result = XtMakeGeometryRequest($, request2, reply2);
+ if (result == XtGeometryNo) return XtGeometryNo;
+ if (result == XtGeometryYes) return XtGeometryYes;
+ reply->request_mode = reply2.request_mode (CWWidth|CWHeight);
+ reply->width = reply2.width - extraw;
+ reply->height = reply2.height - extrah;
+ return XtGeometryAlmost;
+}
+.fi
+
+The \fIresize\fP method doesn't have to recompute any private variables,
+but it passes on the resize message to its child, after decreasing the
+area by the amount needed for the frame.
+
+.nf
+resize($)
+{
+ Position x, y;
+ Dimension w, h;
+ Widget child;
+
+ if ($num_children == 0) return;
+ $compute_inside($, x, y, w, h);
+ child = $children[0];
+ w -= 2 * $child$border_width;
+ h -= 2 * $child$border_width;
+ XtConfigureWidget(child, x, y, w, h, $child$border_width);
+}
+.fi
+
+The \fIchange_managed\fP method is called when a child becomes managed
+or unmanaged. The task of the routine is enforcing the layout policy,
+which in this case consists of trying to take on the size of the child
+or otherwise resize the child to fit inside the frame.
+If the parent of the Frame widget doesn't allow the Frame widget to be
+resized, the child of the Frame widget will be resized instead.
+
+.nf
+change_managed($)
+{
+ XtWidgetGeometry request2, reply2;
+ XtGeometryResult result;
+ Widget child;
+ Position x, y;
+ Dimension w, h;
+
+ if ($num_children == 0) return;
+ $compute_inside($, x, y, w, h);
+ child = $children[0];
+ request2.request_mode = CWWidth | CWHeight;
+ request2.width = $child$width + $width - w;
+ request2.height = $child$height + $height - h;
+ result = XtMakeGeometryRequest($, request2, reply2);
+ $compute_inside($, x, y, w, h);
+ w -= 2 * $child$border_width;
+ h -= 2 * $child$border_width;
+ XtConfigureWidget(child, x, y, w, h, $child$border_width);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The converters use the following macro.
+
+\fBdef\fP done(type, value) =
+do {
+ if (to->addr != NULL) {
+ if (to->size < sizeof(type)) {
+ to->size = sizeof(type);
+ return False;
+ }
+ *(type*)(to->addr) = (value);
+ } else {
+ static type static_val;
+ static_val = (value);
+ to->addr = (XtPointer)static_val;
+ }
+ to->size = sizeof(type);
+ return True;
+ }while (0 )
+
+The variable \fIrcsid\fP isn't used for anything, except tracking of
+versions. The version number is that of the specification file (this
+file) from which the widget's source is build.
+
+.nf
+char rcsid[] = "$Header: Frame.w,v 1.5 92/11/02 14:07:52 bert Exp $"
+.fi
+
+The \fIcreate_darkgc\fP function creates the GC for the dark parts of
+the frame. The contents of the GC depend on the resources
+\fIshadowScheme\fP and possibly \fIbackground_pixel\fP, \fIbottomShadowColor\fP,
+\fItopShadowColor\fP, \fIbottomShadowStipple\fP and \fItopShadowStipple\fP.
+
+.nf
+create_darkgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($darkgc != NULL) XtReleaseGC($, $darkgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = $bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen($));
+ values.background = $background_pixel;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $darker_color($, $background_pixel, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $background_pixel;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple = $stip4;
+ }
+ break;
+ }
+ $darkgc = XtGetGC($, mask, values);
+}
+.fi
+
+\fIcreate_lightgc\fP does the same for the light parts of the frame.
+When the \fIshadowScheme\fP resource is \fIXfwfAuto\fP, the depth of the screen
+and the availability of colors determines whether colors or stipples
+will be used for the frame.
+
+.nf
+create_lightgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($lightgc != NULL) XtReleaseGC($, $lightgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $background_pixel;
+ values.stipple = $topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $lighter_color($, $background_pixel, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $background_pixel;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple = $stip4;
+ }
+ break;
+ }
+ $lightgc = XtGetGC($, mask, values);
+}
+.fi
+
+The function \fIcompute_topcolor\fP is a resource default proc. It is
+used to compute the value of the \fItopShadowColor\fP relative to the
+\fIbackground\fP color.
+
+.nf
+compute_topcolor($, int offset, XrmValue * value)
+{
+ static Pixel color;
+ $lighter_color($, $background_pixel, color);
+ value->addr = (XtPointer) color;
+}
+.fi
+
+.nf
+compute_bottomcolor($, int offset, XrmValue * value)
+{
+ static Pixel color;
+ $darker_color($, $background_pixel, color);
+ value->addr = (XtPointer) color;
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/FrameP.h b/vendor/x11iraf/obm/ObmW/FrameP.h
new file mode 100644
index 00000000..07b6779a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/FrameP.h
@@ -0,0 +1,48 @@
+/* Generated by wbuild from "Frame.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfFrameP_H_
+#define _XfwfFrameP_H_
+#include "CommonP.h"
+#include "Frame.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfFrameClassPart;
+typedef struct _XfwfFrameClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+} XfwfFrameClassRec;
+
+typedef struct {
+/* resources */
+Cursor cursor;
+FrameType frameType;
+Dimension frameWidth;
+Dimension outerOffset;
+Dimension innerOffset;
+ShadowScheme shadowScheme;
+Pixel topShadowColor;
+Pixel bottomShadowColor;
+Bitmap topShadowStipple;
+Bitmap bottomShadowStipple;
+/* private state */
+GC lightgc;
+GC darkgc;
+Pixmap stip4;
+FrameType old_frame_type;
+} XfwfFramePart;
+
+typedef struct _XfwfFrameRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+} XfwfFrameRec;
+
+externalref XfwfFrameClassRec xfwfFrameClassRec;
+
+#endif /* _XfwfFrameP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Gcs.c b/vendor/x11iraf/obm/ObmW/Gcs.c
new file mode 100644
index 00000000..0074bf8f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gcs.c
@@ -0,0 +1,580 @@
+static char rcsid[] = "$Id: Gcs.c,v 1.7 1999/09/08 17:44:12 falk Exp $" ;
+
+/*
+ * Gcs.c - Utility functions to allocate GCs.
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: Sept 29, 1998
+ *
+ *
+ * $Log: Gcs.c,v $
+ * Revision 1.7 1999/09/08 17:44:12 falk
+ * Added XtAllocateGC
+ * Now requires Ansi C
+ *
+ * Revision 1.6 1999/08/25 17:01:26 falk
+ * now sets Xcolor.flags before allocating color
+ *
+ * Revision 1.5 1999/08/24 16:00:19 falk
+ * removed unused variables
+ *
+ * Revision 1.4 1999/08/24 15:44:10 falk
+ * Added AllocShadeGC(), AllocGreyPixelC()
+ *
+ * Revision 1.3 1998/12/15 04:55:05 falk
+ * now uses Xmu library for stippled bitmap
+ * now includes font in foreground & grey GC
+ *
+ * Revision 1.2 1998/10/12 16:29:32 falk
+ * Now exports the allocPixel and GetGrey50 functions
+ *
+ * Revision 1.1 1998/10/12 01:38:14 falk
+ * Initial revision
+ *
+ */
+
+/* Functions:
+ *
+ * GC AllocFgGC(w, fg, font)
+ * Return a GC with foreground set as specified.
+ * If font is None, then the returned GC is allocated with font specified
+ * as a "don't care" value.
+ *
+ * GC
+ * AllocBackgroundGC(w, font)
+ * Return a GC with the foreground set to the widget's background color.
+ *
+ * GC
+ * AllocGreyGC(w, fg, font, contrast, be_nice_to_cmap)
+ * Widget w ;
+ * Pixel fg ;
+ * Font font ;
+ * int contrast ;
+ * int be_nice_to_cmap ;
+ *
+ * Return a GC suitable for rendering a widget in its "inactive" color.
+ * Normally returns a GC with a color somewhere between the widget's
+ * background color and the specified foreground. If font is None, then
+ * the returned GC is allocated with font specified as "don't care".
+ * If be_nice_to_cmap is True, the returned GC is created using a 50%
+ * dither instead of a new color.
+ *
+ *
+ * GC
+ * AllocShadeGC(w, fg, bg, font, contrast, be_nice_to_cmap)
+ * Widget w ;
+ * Pixel fg, bg ;
+ * Font font ;
+ * int contrast ;
+ * int be_nice_to_cmap ;
+ *
+ * Return a GC suitable for rendering in a shade somewhere between
+ * bg and fg, as determined by contrast (0 = bg, 100 = fg)
+ * If font is None, then the returned GC is allocated with
+ * font specified as "don't care". If be_nice_to_cmap
+ * is True, the returned GC is created using a 50% dither
+ * instead of a new color.
+ *
+ *
+ * GC
+ * AllocTopShadowGC(w, contrast, be_nice_to_cmap)
+ * Return a GC suitable for rendering the "top shadow" decorations of
+ * a widget. Returns a GC with foreground computed from widget's
+ * background color and contrast. If be_nice_to_cmap is True, the
+ * returned GC will use a foreground color of white. If widget depth
+ * is 1, this function will use a foreground color of black.
+ *
+ * GC
+ * AllocBotShadowGC(w, contrast, be_nice_to_cmap)
+ * Return a GC suitable for rendering the "bottom shadow" decorations
+ * of a widget. Returns a GC with foreground computed from widget's
+ * background color and contrast. If be_nice_to_cmap is True, the
+ * returned GC will use a foreground color of black.
+ *
+ * GC
+ * AllocArmGC(w, contrast, be_nice_to_cmap)
+ * Return a GC suitable for rendering the "armed" decorations of a
+ * widget. This GC would typically be used to fill in the widget's
+ * background. Returns a GC with foreground computed from widget's
+ * background color and contrast. If be_nice_to_cmap is True, the
+ * returned GC will use a foreground color of black and a 50% dither.
+ *
+ *
+ * void
+ * Draw3dBox(w, x,y,wid,hgt,s, topgc, botgc)
+ * Utility function. Draws a raised shadow box with outside dimensions
+ * as specified by x,y,wid,hgt and shadow width specified by s.
+ * A lowered shadow box may be generated by swapping topgc and botgc.
+ *
+ */
+
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xmu/Misc.h>
+
+#include "Gcs.h"
+
+ /* Color & GC allocation.
+ *
+ * Frame widgets use the following graphics contexts:
+ *
+ * Foreground tab label text drawn this way
+ * Insensitive Fg foreground color greyed out.
+ * Background frame background color
+ * Top shadow upper-left highlight around widget
+ * Bottom shadow lower-right highlight around widget
+ * Arm shadow button pressed and ready to be released
+ *
+ *
+ * GC's are defined as follows, depending on attributes and
+ * window depth:
+ *
+ * Monochrome:
+ * Foreground = foreground color attribute or BlackPixel()
+ * Grey = Foreground color + 50% dither
+ * Background = background color attribute or WhitePixel()
+ * top shadow = foreground
+ * bottom shadow = foreground
+ * arm shadow = (what?)
+ *
+ * Color, beNiceToColormap=true:
+ * Foreground = foreground color attribute or BlackPixel()
+ * Grey = Foreground color + 50% dither
+ * Background = background color attribute or WhitePixel()
+ * top shadow = white
+ * bottom shadow = black
+ * arm shadow = (what?)
+ *
+ * Color, beNiceToColormap=false:
+ * Foreground = foreground color attribute or BlackPixel()
+ * Grey = (foreground color + background color)/2
+ * Background = background color attribute or WhitePixel()
+ * top shadow = background * 1.2
+ * bottom shadow = background * .6
+ * arm shadow = background * .8
+ *
+ * Special cases:
+ * If background is white, ??
+ * if background is black, ??
+ *
+ *
+ * If the widget's background is solid white or solid black,
+ * this code just picks some numbers. (The choice is designed
+ * to be compatibile with ThreeD interface.)
+ */
+
+
+
+#if XtSpecificationRelease < 5
+
+static GC XtAllocateGC(Widget, int, u_long, XGCValues *, u_long, u_long) ;
+
+#endif
+
+
+#if NeedFunctionPrototypes
+static Pixmap getDitherPixmap(Widget, int contrast) ;
+#else
+static Pixmap getDitherPixmap() ;
+#endif
+
+
+ /* return a GC with the specified foreground and optional font */
+
+GC
+AllocFgGC(Widget w, Pixel fg, Font font)
+{
+ XGCValues values ;
+ u_long vmask, dcmask ;
+
+ values.foreground = fg ;
+ values.font = font ;
+
+ if( font != None ) {
+ vmask = GCForeground|GCFont ;
+ dcmask = GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode|GCBackground ;
+ } else {
+ vmask = GCForeground ;
+ dcmask = GCFont|GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode|GCBackground ;
+ }
+
+ return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
+}
+
+
+ /* return gc with widget background color as the foreground */
+
+GC
+AllocBackgroundGC(Widget w, Font font)
+{
+ return AllocFgGC(w, w->core.background_pixel, font) ;
+}
+
+
+ /* Allocate an "inactive" GC. Color is grey (possibly via
+ * dither pattern).
+ */
+
+GC
+AllocGreyGC(Widget w, Pixel fg, Font font, int contrast, Bool be_nice_to_cmap)
+{
+ return AllocShadeGC(w, fg, w->core.background_pixel,
+ font, contrast, be_nice_to_cmap) ;
+}
+
+
+ /* Allocate a GC somewhere between two colors. */
+
+GC
+AllocShadeGC(Widget w, Pixel fg, Pixel bg, Font font,
+ int contrast, Bool be_nice_to_cmap)
+{
+ XGCValues values ;
+ u_long vmask, dcmask ;
+
+ values.foreground = fg ;
+ values.background = bg ;
+ values.font = font ;
+
+ if( font != None ) {
+ vmask = GCForeground|GCFont ;
+ dcmask = GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode ;
+ } else {
+ vmask = GCForeground ;
+ dcmask = GCFont|GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode ;
+ }
+
+ if( be_nice_to_cmap || w->core.depth == 1)
+ {
+ if( contrast <= 5 )
+ values.foreground = bg ;
+ else if( contrast >= 95 )
+ values.foreground = fg ;
+ else {
+ vmask |= GCBackground|GCStipple|GCFillStyle ;
+ values.fill_style = FillOpaqueStippled ;
+ values.stipple = getDitherPixmap(w, contrast) ;
+ }
+
+ return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
+ }
+ else
+ {
+ dcmask |= GCBackground ;
+ values.foreground = AllocGreyPixel(w, fg, bg, contrast) ;
+ return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
+ }
+}
+
+ /* return top-shadow gc. */
+
+GC
+AllocTopShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
+{
+ Screen *scr = XtScreen (w);
+ XGCValues values ;
+
+ if( w->core.depth == 1 )
+ values.foreground = BlackPixelOfScreen(scr) ;
+ else if( be_nice_to_cmap )
+ values.foreground = WhitePixelOfScreen(scr) ;
+ else
+ values.foreground = AllocShadowPixel(w, 100+contrast) ;
+
+ return XtAllocateGC(w, w->core.depth,
+ GCForeground, &values,
+ 0L,
+ GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
+ GCDashOffset|GCDashList|GCArcMode) ;
+}
+
+ /* return bottom-shadow gc. */
+
+GC
+AllocBotShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
+{
+ Screen *scr = XtScreen (w);
+ XGCValues values ;
+
+ if( w->core.depth == 1 || be_nice_to_cmap )
+ values.foreground = BlackPixelOfScreen(scr) ;
+ else
+ values.foreground = AllocShadowPixel(w, 100-contrast) ;
+
+ return XtAllocateGC(w, w->core.depth,
+ GCForeground, &values,
+ 0L,
+ GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
+ GCDashOffset|GCDashList|GCArcMode) ;
+}
+
+ /* return arm-shadow gc. */
+
+GC
+AllocArmGC(Widget w, int contrast, Bool be_nice_to_cmap)
+{
+ Screen *scr = XtScreen (w);
+ XGCValues values ;
+#ifndef USE_XMU_STIPPLE
+ Screen *screen = XtScreen((Widget)w);
+ Display *display = XtDisplay((Widget)w);
+ int pixmap_width = 2, pixmap_height = 2;
+ static unsigned char pixmap_bits[] = {
+ 0x02, 0x01,
+ };
+#endif
+
+ /* Not clear exactly what we should do here. Take a look at
+ * Xaw3d to see what they do.
+ */
+
+ if( w->core.depth == 1 || be_nice_to_cmap )
+ {
+ values.background = w->core.background_pixel ;
+ if( values.background == BlackPixelOfScreen(scr) )
+ values.foreground = WhitePixelOfScreen(scr) ;
+ else
+ values.foreground = BlackPixelOfScreen(scr) ;
+ values.fill_style = FillStippled ;
+#ifdef USE_XMU_STIPPLE
+ values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1);
+#else
+ values.stipple = XCreatePixmapFromBitmapData (display,
+ RootWindowOfScreen(screen),
+ (char *)pixmap_bits,
+ pixmap_width, pixmap_height,
+ 1L, 0L, 1);
+#endif
+
+
+ return XtAllocateGC(w, w->core.depth,
+ GCForeground|GCBackground|GCStipple|GCFillStyle,
+ &values, 0L,
+ GCFont|GCSubwindowMode|GCGraphicsExposures|
+ GCDashOffset|GCDashList|GCArcMode) ;
+ }
+ else {
+ values.foreground = AllocShadowPixel(w, 100-contrast) ;
+ return XtAllocateGC(w, w->core.depth,
+ GCForeground, &values,
+ 0L,
+ GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
+ GCDashOffset|GCDashList|GCArcMode) ;
+ }
+}
+
+
+Pixel
+AllocShadowPixel(Widget w, int scale)
+{
+ XColor get_c, set_c ;
+ Display *dpy = XtDisplay(w) ;
+ Screen *scr = XtScreen(w) ;
+ Colormap cmap ;
+ Pixel maxColor ;
+
+ cmap = w->core.colormap ;
+
+ get_c.pixel = w->core.background_pixel ;
+ if( get_c.pixel == WhitePixelOfScreen(scr) ||
+ get_c.pixel == BlackPixelOfScreen(scr) )
+ {
+ /* what we *ought* to do is choose gray75 as the base color,
+ * or perhaps gray83. Instead, we choose colors that are
+ * the same as ThreeD would choose.
+ */
+ if( scale > 100 ) scale = 200 - scale ;
+ set_c.red = set_c.green = set_c.blue = 65535*scale/100 ;
+ }
+ else
+ {
+ XQueryColor(dpy, cmap, &get_c) ;
+ /* adjust scale so that brightest component does not
+ * exceed 65535; otherwise hue would change.
+ */
+ if( scale > 100 ) {
+ maxColor = Max(get_c.red, Max(get_c.green, get_c.blue)) ;
+ if( scale*maxColor > 65535*100 )
+ scale = 65535*100/maxColor ;
+ }
+ set_c.red = scale * get_c.red / 100 ;
+ set_c.green = scale * get_c.green / 100 ;
+ set_c.blue = scale * get_c.blue / 100 ;
+ }
+ set_c.flags = DoRed | DoGreen | DoBlue ;
+ if( XAllocColor(dpy, cmap, &set_c) )
+ return set_c.pixel ;
+ else if( scale > 100 )
+ return WhitePixelOfScreen(scr) ;
+ else
+ return BlackPixelOfScreen(scr) ;
+}
+
+
+ /* Allocate a pixel partway between foreground and background */
+
+
+Pixel
+AllocGreyPixel(Widget w, Pixel fg, Pixel bg, int scale)
+{
+ XColor get_cf, get_cb ;
+ Display *dpy = XtDisplay(w) ;
+ Colormap cmap ;
+
+ cmap = w->core.colormap ;
+
+ get_cf.pixel = fg ;
+ get_cb.pixel = bg ;
+
+ XQueryColor(dpy, cmap, &get_cf) ;
+ XQueryColor(dpy, cmap, &get_cb) ;
+
+ return AllocGreyPixelC(w, &get_cf, &get_cb, scale) ;
+}
+
+
+
+ /* Allocate a pixel partway between foreground and background */
+
+
+Pixel
+AllocGreyPixelC(Widget w, XColor *fg, XColor *bg, int scale)
+{
+ XColor set_c ;
+ Display *dpy = XtDisplay(w) ;
+ int r,g,b ;
+ Colormap cmap = w->core.colormap ;
+
+ r = (fg->red * scale + bg->red * (100-scale)) / 100 ;
+ g = (fg->green * scale + bg->green * (100-scale)) / 100 ;
+ b = (fg->blue * scale + bg->blue * (100-scale)) / 100 ;
+
+ if( scale > 100 || scale < 0 ) /* look out for overflow */
+ {
+ int minc, maxc ;
+ maxc = Max(r, Max(g,b)) ;
+ minc = Min(r, Min(g,b)) ;
+ if( maxc > 65535 )
+ {
+ maxc /= 16 ;
+ r = r*(65535/16) / maxc ;
+ g = g*(65535/16) / maxc ;
+ b = b*(65535/16) / maxc ;
+ }
+ if( minc < 0 )
+ {
+ r = Max(r,0) ;
+ g = Max(g,0) ;
+ b = Max(b,0) ;
+ }
+ }
+
+ set_c.red = r ; set_c.green = g ; set_c.blue = b ;
+ set_c.flags = DoRed | DoGreen | DoBlue ;
+ (void)XAllocColor(dpy, cmap, &set_c) ;
+ return set_c.pixel ;
+}
+
+
+
+
+
+ /* draw a 3-d box */
+
+void
+Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s, GC topgc, GC botgc)
+{
+ Display *dpy = XtDisplay(w) ;
+ Window win = XtWindow(w) ;
+
+ if( s == 0 ) return ;
+
+ if( s == 1 ) {
+ XDrawLine(dpy,win,botgc, x,y+hgt-1, x+wid-1,y+hgt-1) ;
+ XDrawLine(dpy,win,botgc, x+wid-1,y, x+wid-1,y+hgt-1) ;
+ XDrawLine(dpy,win,topgc, x,y, x,y+hgt-1) ;
+ XDrawLine(dpy,win,topgc, x,y, x+wid-1,y) ;
+ }
+ else
+ {
+ XPoint pts[6] ;
+
+ /* bottom-right shadow */
+ pts[0].x = x ; pts[0].y = y + hgt ;
+ pts[1].x = s ; pts[1].y = -s ;
+ pts[2].x = wid-2*s ; pts[2].y = 0 ;
+ pts[3].x = 0 ; pts[3].y = -(hgt-2*s) ;
+ pts[4].x = s ; pts[4].y = -s ;
+ pts[5].x = 0 ; pts[5].y = hgt ;
+ XFillPolygon(dpy,win,botgc, pts,6, Nonconvex,CoordModePrevious) ;
+
+ /* top-left shadow */
+ pts[0].x = x ; pts[0].y = y ;
+ pts[1].x = wid ; pts[1].y = 0 ;
+ pts[2].x = -s ; pts[2].y = s ;
+ pts[3].x = -wid+2*s ; pts[3].y = 0 ;
+ pts[4].x = 0 ; pts[4].y = hgt-2*s ;
+ pts[5].x = -s ; pts[5].y = s ;
+ XFillPolygon(dpy,win,topgc, pts,6, Nonconvex,CoordModePrevious) ;
+ }
+}
+
+#if XtSpecificationRelease < 5
+
+static GC
+XtAllocateGC(Widget w, int depth, u_long mask, XGCValues *values,
+ u_long dynamic, du_long ontcare)
+{
+ return XtGetGC(w, mask, values) ;
+}
+#endif
+
+
+static u_char screen0[2] = {0,0} ;
+static u_char screen25[2] = {0,0xaa} ;
+static u_char screen75[2] = {0xaa,0xff} ;
+static u_char screen100[2] = {0xff,0xff} ;
+
+static Pixmap
+getDitherPixmap(Widget w, int contrast)
+{
+ Display *dpy = XtDisplay(w) ;
+ Window win = XtWindow(w) ;
+#ifndef USE_XMU_STIPPLE
+ Screen *screen = XtScreen((Widget)w);
+ Display *display = XtDisplay((Widget)w);
+ int pixmap_width = 2, pixmap_height = 2;
+ static unsigned char pixmap_bits[] = {
+ 0x02, 0x01,
+ };
+#endif
+
+ if( contrast <= 5 )
+ return XCreateBitmapFromData(dpy,win, (char *)screen0, 2,2) ;
+ else if( contrast <= 37 )
+ return XCreateBitmapFromData(dpy,win, (char *)screen25, 2,2) ;
+ else if( contrast <= 62 )
+#ifdef USE_XMU_STIPPLE
+ return XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ;
+#else
+ return XCreatePixmapFromBitmapData (display,
+ RootWindowOfScreen(screen),
+ (char *)pixmap_bits,
+ pixmap_width, pixmap_height,
+ 1L, 0L, 1);
+#endif
+ else if( contrast <= 95 )
+ return XCreateBitmapFromData(dpy,win, (char *)screen75, 2,2) ;
+ else
+ return XCreateBitmapFromData(dpy,win, (char *)screen100, 2,2) ;
+}
diff --git a/vendor/x11iraf/obm/ObmW/Gcs.h b/vendor/x11iraf/obm/ObmW/Gcs.h
new file mode 100644
index 00000000..93a8982b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gcs.h
@@ -0,0 +1,121 @@
+#ifndef GCS_H
+#define GCS_H
+
+/* Overview of functions provided here:
+ *
+ * AllocFgGC()
+ * Given a foreground pixel & a font, return an appropriate GC
+ *
+ * AllocBackgroundGC()
+ * Given a widget, return a GC for painting the background color
+ *
+ * AllocShadeGC()
+ * Given foreground, background, a contrast value & be_nice_to_colormap
+ * flag, return a GC suitable for rendering in an intermediate color,
+ * as determined by constrast. May return a dither pattern or a
+ * solid color, as appropriate.
+ *
+ * Contrast 0 = background color, 100 = foreground color. It is legal
+ * for contrast to be more than 100 or less than 0.
+ *
+ * AllocGreyGC()
+ * Given widget, foreground, font, contrast & be_nice_to_colormap,
+ * return a shade GC (see above) based on foreground and widget
+ * background.
+ *
+ * AllocTopShadowGC()
+ * Given widget, contrast & be_nice_to_colormap, return a GC suitable
+ * for rendering the top shadow.
+ *
+ * Contrast 0 = use background pixel. Contrast > 0 = use brighter
+ * colors.
+ *
+ * AllocBotShadowGC()
+ * Given widget, contrast & be_nice_to_colormap, return a GC suitable
+ * for rendering the bottom shadow.
+ *
+ * Contrast 0 = use background pixel. Contrast > 0 = use darker
+ * colors.
+ *
+ * AllocArmShadowGC()
+ * Given widget, contrast & be_nice_to_colormap, return a GC suitable
+ * for rendering the "armed" shadow.
+ *
+ * Contrast 0 = use background pixel. Contrast > 0 = use darker
+ * colors.
+ *
+ * AllocShadowPixel()
+ * Given a widget & scale factor, allocate & return a color darker
+ * or lighter than the background pixel, as determined by scale.
+ *
+ * Scale 100 = use background pixel. Scale > 100 = brighter color,
+ * Scale < 100 = darker color.
+ *
+ * AllocGreyPixel()
+ * Given two pixel values and scale factor, allocate & return a
+ * pixel value between them, according to scale.
+ *
+ * Scale == 0: background color
+ * Scale == 100: foreground color
+ * 0<Scale<100: intermediate color
+ * Scale > 100: more foreground
+ * Scale < 0: more background
+ *
+ *
+ * AllocGreyPixelC()
+ * Given two color values and scale factor, allocate & return a
+ * pixel value between them, according to scale.
+ *
+ * Scale == 0: background color
+ * Scale == 100: foreground color
+ * 0<Scale<100: intermediate color
+ * Scale > 100: more foreground
+ * Scale < 0: more background
+ *
+ * Draw3dBox()
+ * Given box dimensions, shadow width, top shadow GC & bottom shadow GC,
+ * draw a 3-d box.
+ */
+
+#if NeedFunctionPrototypes
+
+extern GC AllocFgGC( Widget w, Pixel fg, Font font) ;
+extern GC AllocBackgroundGC( Widget w, Font font) ;
+extern GC AllocShadeGC( Widget w, Pixel fg, Pixel bg, Font,
+ int contrast, Bool ) ;
+extern GC AllocGreyGC( Widget w, Pixel fg, Font, int, Bool ) ;
+extern GC AllocTopShadowGC( Widget w, int contrast, int ) ;
+extern GC AllocBotShadowGC( Widget w, int contrast, int ) ;
+extern GC AllocArmGC( Widget w, int contrast, int) ;
+extern Pixel AllocShadowPixel(Widget, int scale) ;
+extern Pixel AllocGreyPixel(Widget, Pixel fg, Pixel bg, int scale) ;
+extern Pixel AllocGreyPixelC(Widget, XColor *fg, XColor *bg, int scale) ;
+extern void Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s,
+ GC topgc, GC botgc) ;
+
+#if XtSpecificationRelease < 5
+extern GC XtAllocateGC(Widget, int depth, u_long mask,
+ XGCValues *, u_long dynamic, u_long dontcare) ;
+#endif
+
+#else
+
+extern GC AllocFgGC() ;
+extern GC AllocBackgroundGC() ;
+extern GC AllocShadeGC() ;
+extern GC AllocGreyGC() ;
+extern GC AllocTopShadowGC() ;
+extern GC AllocBotShadowGC() ;
+extern GC AllocArmGC() ;
+extern Pixel AllocShadowPixel() ;
+extern Pixel AllocGreyPixel() ;
+extern Pixel AllocGreyPixelC() ;
+extern void Draw3dBox() ;
+
+#if XtSpecificationRelease < 5
+extern GC XtAllocateGC() ;
+#endif
+
+#endif
+
+#endif /* GCS_H */
diff --git a/vendor/x11iraf/obm/ObmW/Group.c b/vendor/x11iraf/obm/ObmW/Group.c
new file mode 100644
index 00000000..f34005ea
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Group.c
@@ -0,0 +1,383 @@
+/* Generated by wbuild from "Group.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Toggle.h"
+#include <stdio.h>
+#include <X11/Xmu/Converters.h>
+#include "Converters.h"
+#include "GroupP.h"
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void class_initialize(
+#if NeedFunctionPrototypes
+void
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void insert_child(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void make_textgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void on_cb(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void off_cb(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void set_toggles(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define done(type, value) do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ }while (0 )
+
+
+static Boolean cvtStringToSelectionType(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+static Boolean cvtSelectionTypeToString(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+/*ARGSUSED*/static void make_textgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfGroupWidget)self)->xfwfGroup.textgc != NULL) XtReleaseGC(self, ((XfwfGroupWidget)self)->xfwfGroup.textgc);
+ values.background = ((XfwfGroupWidget)self)->core.background_pixel;
+ values.foreground = ((XfwfGroupWidget)self)->xfwfGroup.foreground;
+ values.font = ((XfwfGroupWidget)self)->xfwfGroup.font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ ((XfwfGroupWidget)self)->xfwfGroup.textgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void on_cb(toggle,client_data,call_data)Widget toggle;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = XtParent(toggle);
+ Cardinal toggle_ord = (Cardinal) client_data;
+ Cardinal t, i, bits = sizeof(((XfwfGroupWidget)self)->xfwfGroup.selection) * 8;
+
+ switch (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle) {
+ case XfwfMultipleSelection:
+ if (toggle_ord < bits) ((XfwfGroupWidget)self)->xfwfGroup.selection |= 1L << toggle_ord;
+ break;
+ case XfwfSingleSelection:
+ case XfwfOneSelection:
+ if (((XfwfGroupWidget)self)->xfwfGroup.selection != -1L)
+ for (t = 0, i = 0; i < ((XfwfGroupWidget)self)->composite.num_children; i++)
+ if (XtIsSubclass(((XfwfGroupWidget)self)->composite.children[i], xfwfToggleWidgetClass)) {
+ if (((XfwfGroupWidget)self)->xfwfGroup.selection == t) {
+ XtVaSetValues(((XfwfGroupWidget)self)->composite.children[i], XtNon, False, NULL);
+ break;
+ }
+ t++;
+ }
+ ((XfwfGroupWidget)self)->xfwfGroup.selection = toggle_ord;
+ break;
+ default: ;
+ }
+ XtCallCallbackList(self, ((XfwfGroupWidget)self)->xfwfGroup.activate, (XtPointer) ((XfwfGroupWidget)self)->xfwfGroup.selection);
+}
+/*ARGSUSED*/static void off_cb(toggle,client_data,call_data)Widget toggle;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = XtParent(toggle);
+ Cardinal toggle_ord = (Cardinal) client_data;
+ Cardinal t, i, bits = sizeof(((XfwfGroupWidget)self)->xfwfGroup.selection) * 8;
+
+ switch (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle) {
+ case XfwfOneSelection:
+ XtVaSetValues(toggle, XtNon, True, NULL); /* Undo */
+ break;
+ case XfwfSingleSelection:
+ ((XfwfGroupWidget)self)->xfwfGroup.selection = -1L; /* Nothing selected */
+ break;
+ case XfwfMultipleSelection:
+ if (toggle_ord < bits) ((XfwfGroupWidget)self)->xfwfGroup.selection &= ~(1L << toggle_ord);
+ break;
+ default: ;
+ }
+ XtCallCallbackList(self, ((XfwfGroupWidget)self)->xfwfGroup.activate, (XtPointer) ((XfwfGroupWidget)self)->xfwfGroup.selection);
+}
+/*ARGSUSED*/static void set_toggles(self)Widget self;
+{
+ Cardinal i, t;
+
+ for (t = 0, i = 0; i < ((XfwfGroupWidget)self)->composite.num_children; i++)
+ if (XtIsSubclass(((XfwfGroupWidget)self)->composite.children[i], xfwfToggleWidgetClass)) {
+ switch (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle) {
+ case XfwfNoSelection:
+ break;
+ case XfwfSingleSelection:
+ case XfwfOneSelection:
+ XtVaSetValues(((XfwfGroupWidget)self)->composite.children[i], XtNon, t == ((XfwfGroupWidget)self)->xfwfGroup.selection, NULL);
+ break;
+ case XfwfMultipleSelection:
+ XtVaSetValues(((XfwfGroupWidget)self)->composite.children[i],
+ XtNon, (((XfwfGroupWidget)self)->xfwfGroup.selection & (1L<<t)) != 0, NULL);
+ break;
+ }
+ t++;
+ }
+}
+/*ARGSUSED*/static Boolean cvtStringToSelectionType(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToSelectionType", "wrongParameters",
+ "XtToolkitError",
+ "String to SelectionType conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "no") == 0)
+ done(SelectionType, XfwfNoSelection);
+ if (XmuCompareISOLatin1(s, "none") == 0)
+ done(SelectionType, XfwfNoSelection);
+ if (XmuCompareISOLatin1(s, "single") == 0)
+ done(SelectionType, XfwfSingleSelection);
+ if (XmuCompareISOLatin1(s, "one") == 0)
+ done(SelectionType, XfwfOneSelection);
+ if (XmuCompareISOLatin1(s, "multi") == 0)
+ done(SelectionType, XfwfMultipleSelection);
+ if (XmuCompareISOLatin1(s, "multiple") == 0)
+ done(SelectionType, XfwfMultipleSelection);
+
+ XtDisplayStringConversionWarning(display, s, XtRSelectionType);
+ done(SelectionType, XfwfSingleSelection);
+}
+/*ARGSUSED*/static Boolean cvtSelectionTypeToString(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ char s[30];
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToSelectionStyle", "wrongParameters",
+ "XtToolkitError",
+ "String to SelectionStyle conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*((SelectionType*) from->addr)) {
+ case XfwfNoSelection: done(String, "none");
+ case XfwfSingleSelection: done(String, "single");
+ case XfwfOneSelection: done(String, "one");
+ case XfwfMultipleSelection: done(String, "multiple");
+ }
+ XtDisplayStringConversionWarning(display, s, XtRSelectionType);
+ done(String, "none");
+}
+
+static XtResource resources[] = {
+{XtNlabel,XtCLabel,XtRString,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.label),XtOffsetOf(XfwfGroupRec,xfwfGroup.label),XtRImmediate,(XtPointer)NULL },
+{XtNfont,XtCFont,XtRFontStruct,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.font),XtOffsetOf(XfwfGroupRec,xfwfGroup.font),XtRString,(XtPointer)XtDefaultFont },
+{XtNforeground,XtCForeground,XtRPixel,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.foreground),XtOffsetOf(XfwfGroupRec,xfwfGroup.foreground),XtRString,(XtPointer)XtDefaultForeground },
+{XtNselectionStyle,XtCSelectionStyle,XtRSelectionType,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.selectionStyle),XtOffsetOf(XfwfGroupRec,xfwfGroup.selectionStyle),XtRImmediate,(XtPointer)XfwfSingleSelection },
+{XtNselection,XtCSelection,XtRLong,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.selection),XtOffsetOf(XfwfGroupRec,xfwfGroup.selection),XtRImmediate,(XtPointer)0 },
+{XtNactivate,XtCActivate,XtRCallback,sizeof(((XfwfGroupRec*)NULL)->xfwfGroup.activate),XtOffsetOf(XfwfGroupRec,xfwfGroup.activate),XtRImmediate,(XtPointer)NULL },
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfGroupRec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfGroupRec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfChiseled },
+{XtNinnerOffset,XtCInnerOffset,XtRDimension,sizeof(((XfwfGroupRec*)NULL)->xfwfFrame.innerOffset),XtOffsetOf(XfwfGroupRec,xfwfFrame.innerOffset),XtRImmediate,(XtPointer)3 },
+};
+
+XfwfGroupClassRec xfwfGroupClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfRowColClassRec,
+"Group",
+sizeof(XfwfGroupRec),
+class_initialize,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+NULL,
+0,
+resources,
+8,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+insert_child,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfRowCol_class part */
+XtInherit_layout,
+},
+{ /* XfwfGroup_class part */
+0
+},
+};
+WidgetClass xfwfGroupWidgetClass = (WidgetClass) &xfwfGroupClassRec;
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfGroupWidgetClass c = (XfwfGroupWidgetClass) class;
+ XfwfGroupWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfGroupWidgetClass) return;
+ super = (XfwfGroupWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void class_initialize()
+{
+ XtAddConverter(XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
+ XtSetTypeConverter(XtRLong, XtRString, XfwfCvtLongToString,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRString, XtRSelectionType, cvtStringToSelectionType,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRSelectionType, XtRString, cvtSelectionTypeToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfGroupWidget)self)->xfwfGroup.toggle_ord = 0;
+ ((XfwfGroupWidget)self)->xfwfGroup.textgc = NULL;
+ make_textgc(self);
+ if (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle == XfwfOneSelection && ((XfwfGroupWidget)self)->xfwfGroup.selection == -1L) {
+ XtWarning
+ ("Illegal combination of selectionStyle and selection resources");
+ ((XfwfGroupWidget)self)->xfwfGroup.selection = 0;
+ }
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redraw = False;
+
+ if (((XfwfGroupWidget)old)->xfwfGroup.label != ((XfwfGroupWidget)self)->xfwfGroup.label) {
+ XtFree(((XfwfGroupWidget)old)->xfwfGroup.label);
+ ((XfwfGroupWidget)self)->xfwfGroup.label = XtNewString(((XfwfGroupWidget)self)->xfwfGroup.label);
+ need_redraw = True;
+ }
+ if (((XfwfGroupWidget)self)->xfwfGroup.font != ((XfwfGroupWidget)old)->xfwfGroup.font) {
+ make_textgc(self);
+ if (((XfwfGroupWidget)self)->xfwfGroup.label != NULL) need_redraw = True;
+ }
+ if (((XfwfGroupWidget)old)->xfwfGroup.selection != ((XfwfGroupWidget)self)->xfwfGroup.selection
+ || ((XfwfGroupWidget)old)->xfwfGroup.selectionStyle != ((XfwfGroupWidget)self)->xfwfGroup.selectionStyle) {
+ if (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle == XfwfOneSelection && ((XfwfGroupWidget)self)->xfwfGroup.selection == -1L)
+ ((XfwfGroupWidget)self)->xfwfGroup.selection = 0;
+ set_toggles(self);
+ }
+ return need_redraw;
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Dimension w, h;
+ Position x, y;
+
+ if (! XtIsRealized(self)) return;
+ xfwfRowColClassRec.core_class.expose(self, event, region);
+ ((XfwfGroupWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ XDrawImageString(XtDisplay(self), XtWindow(self), ((XfwfGroupWidget)self)->xfwfGroup.textgc, x + 3,
+ y - ((XfwfGroupWidget)self)->xfwfFrame.innerOffset, ((XfwfGroupWidget)self)->xfwfGroup.label, strlen(((XfwfGroupWidget)self)->xfwfGroup.label));
+}
+/*ARGSUSED*/static void insert_child(child)Widget child;
+{ Widget self = XtParent(child); {
+ xfwfRowColClassRec.composite_class.insert_child(child);
+ if (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle != XfwfNoSelection
+ && XtIsSubclass(child, xfwfToggleWidgetClass)) {
+ XtAddCallback(child, XtNonCallback, on_cb, (XtPointer) ((XfwfGroupWidget)self)->xfwfGroup.toggle_ord);
+ XtAddCallback(child, XtNoffCallback, off_cb, (XtPointer) ((XfwfGroupWidget)self)->xfwfGroup.toggle_ord);
+ switch (((XfwfGroupWidget)self)->xfwfGroup.selectionStyle) {
+ case XfwfOneSelection:
+ case XfwfSingleSelection:
+ XtVaSetValues(child, XtNon, ((XfwfGroupWidget)self)->xfwfGroup.toggle_ord == ((XfwfGroupWidget)self)->xfwfGroup.selection, NULL);
+ break;
+ case XfwfMultipleSelection:
+ XtVaSetValues(child, XtNon,
+ (((XfwfGroupWidget)self)->xfwfGroup.selection & (1L<<((XfwfGroupWidget)self)->xfwfGroup.toggle_ord)) != 0, NULL);
+ break;
+ default: ;
+ }
+ ((XfwfGroupWidget)self)->xfwfGroup.toggle_ord++;
+ }
+}
+}
diff --git a/vendor/x11iraf/obm/ObmW/Group.h b/vendor/x11iraf/obm/ObmW/Group.h
new file mode 100644
index 00000000..d63bae37
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Group.h
@@ -0,0 +1,74 @@
+/* Generated by wbuild from "Group.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfGroup_H_
+#define _XfwfGroup_H_
+#include "RowCol.h"
+typedef enum {
+ XfwfNoSelection, XfwfSingleSelection,
+ XfwfOneSelection, XfwfMultipleSelection } SelectionType;
+
+#ifndef XtNlabel
+#define XtNlabel "label"
+#endif
+#ifndef XtCLabel
+#define XtCLabel "Label"
+#endif
+#ifndef XtRString
+#define XtRString "String"
+#endif
+
+#ifndef XtNfont
+#define XtNfont "font"
+#endif
+#ifndef XtCFont
+#define XtCFont "Font"
+#endif
+#ifndef XtRFontStruct
+#define XtRFontStruct "FontStruct"
+#endif
+
+#ifndef XtNforeground
+#define XtNforeground "foreground"
+#endif
+#ifndef XtCForeground
+#define XtCForeground "Foreground"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNselectionStyle
+#define XtNselectionStyle "selectionStyle"
+#endif
+#ifndef XtCSelectionStyle
+#define XtCSelectionStyle "SelectionStyle"
+#endif
+#ifndef XtRSelectionType
+#define XtRSelectionType "SelectionType"
+#endif
+
+#ifndef XtNselection
+#define XtNselection "selection"
+#endif
+#ifndef XtCSelection
+#define XtCSelection "Selection"
+#endif
+#ifndef XtRLong
+#define XtRLong "Long"
+#endif
+
+#ifndef XtNactivate
+#define XtNactivate "activate"
+#endif
+#ifndef XtCActivate
+#define XtCActivate "Activate"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+typedef struct _XfwfGroupClassRec *XfwfGroupWidgetClass;
+typedef struct _XfwfGroupRec *XfwfGroupWidget;
+externalref WidgetClass xfwfGroupWidgetClass;
+#endif /*_XfwfGroup_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Group.man b/vendor/x11iraf/obm/ObmW/Group.man
new file mode 100644
index 00000000..7d3900bf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Group.man
@@ -0,0 +1,723 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfGroup
+.SH DESCRIPTION
+The Group widget is a subclass of RowCol, which means that it
+arranges its children in rows and columns. (See the RowCol widget for
+the resources that influence the layout.) The Group widget adds two
+things to the capabilities already present in RowCol, namely a label
+in the upper left hand corner and the ability to make a number of
+Toggle buttons act as radio buttons.
+
+The label is a short, one line piece of text, that is displayed over
+the border in the top left corner. The border is interupted at that
+point. Since this works best with `ledged' or `chiseled' border
+types, the default border is \fIXfwfChiseled\fP.
+
+The special support for radio buttons works as follows: when a child
+is added the Group widget checks if it is of class \fIXfwfToggle\fP or a
+subclass thereof. If so, the Group widget installs a callback in it.
+When the toggle button is then activated, the Group widget determines
+which other buttons need to be turned off. All toggle buttons are
+given an implicit number. The first one to be added is number 0.
+
+There are three selection styles, settable through the
+\fIselectionStyle\fP resource:
+
+1) `single' (\fIXfwfSingleSelection\fP) means that at most one of the
+toggle buttons may be on, but it is possible that they are all off.
+When one of the buttons is turned on, all others are turned off
+automatically. The resource \fIselection\fP holds the number of the button
+that is on, or -1 if they are all off.
+
+2) `one' (\fIXfwfOneSelection\fP) means that at all times exactly one
+button is turned on. It is not possible to turn buttons off, except by
+toggling another one to on. The resource \fIselection\fP holds the number
+of the button that is currently on.
+
+3) `multi' or `multiple' (\fIXfwfMultipleSelection\fP) means that any
+number of buttons may be on. No buttons are turned off automatically.
+The resource \fIselection\fP has one bit set for each button that is on.
+Thus, if buttons 1, 4 and 5 are on, the value of \fIselection\fP is (1<<1
++ 1<<4 + 1<<5 =) 0x62. Note that this limits the number of buttons
+that is recorded in \fIselection\fP to the first 32. It is still possible
+to have more buttons, but the application will then have to use
+callbacks or other means to keep track of the toggle buttons.
+
+4) `none' (\fIXfwfNoSelection\fP) turns off any special handling of toggle
+buttons. The value of the \fIselection\fP resource is undefined.
+
+Applications may of course install callbacks on the toggle buttons,
+but a simpler way is to attach to the \fIactivateCallback\fP of the Group
+widget itself, or use no callback at all and simply inspect the
+\fIselection\fP resource when needed.
+
+It is recommended that application visually differentiate between
+selection styles. One way would be to use different graphics in the
+toggle buttons, e.g., the Motif convention that radiobuttons have an
+empty or colored diamond, and non-exclusive toggles a square.
+Suitable icons are already defined by the Common widget.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfGroup
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNselectionStyle XtCSelectionStyle SelectionType XfwfSingleSelection
+XtNselection XtCSelection Long 0
+XtNactivate XtCActivate Callback NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNlabel"
+The label must be a single line. It is displayed superimposed on the
+frame, in the upper lefthand corner. Currently, it must be simple
+string in a single font.
+
+
+
+.hi
+
+.nf
+String label = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNfont"
+The font for the label is set with \fIfont\fP.
+
+
+
+.hi
+
+.nf
+<FontStruct> XFontStruct * font = <String>XtDefaultFont
+.fi
+
+.eh
+
+.TP
+.I "XtNforeground"
+The foreground color is the color used to draw the text.
+
+
+
+.hi
+
+.nf
+Pixel foreground = <String>XtDefaultForeground
+.fi
+
+.eh
+
+.TP
+.I "XtNselectionStyle"
+The \fIselectionStyle\fP resource determines how the Group widget treats
+the child widgets that are of class \fIXfwfToggle\fP or a subclass
+thereof. The possible values are \fIXfwfNoSelection\fP,
+\fIXfwfSingleSelection\fP (default), \fIXfwfOneSelection\fP and
+\fIXfwfMultipleSelection\fP. The meaning is as explained above. There is a
+converter from strings, that recognizes the strings `no', `none',
+`single', `one', `multi', and `multiple', in upper or lower case.
+
+
+
+.hi
+
+.nf
+SelectionType selectionStyle = XfwfSingleSelection
+.fi
+
+.eh
+
+.TP
+.I "XtNselection"
+The resource \fIselection\fP holds the state of the toggle buttons (if
+any). If \fIselectionType = XfwfSingleSelection\fP or \fIXfwfOneSelection\fP,
+it holds the number of the buttons that is currently on, or -1 if they
+are all off. If \fIselectionType = XfwfMultipleSelection\fP, it is a
+bitmap with one bit set for each button that is on. (See the
+introduction above for more information.)
+
+The value can also be set (e.g., through \fIXtSetValues\fP); the result is
+that the corresponding toggle buttons will be turned on or off.
+
+
+
+.hi
+
+.nf
+long selection = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNactivate"
+The callback \fIactivate\fP can be used by applications that want to be
+informed of any change to the state of the toggle buttons as soon as
+it happens. Other applications can simply use \fIXtGetValues\fP to get the
+value of the \fIselection\fP resource. The callback will be called with
+the value of \fIselection\fP as \fIcall_data\fP argument.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList activate = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNframeType"
+The default border type is different from that of its superclass
+RowCol. It is set to \fIXfwfChiseled\fP because that is the conventional
+border type around radio buttons, and because it looks better when
+there is a label superimposed on it.
+
+
+
+.hi
+
+.nf
+FrameType frameType = XfwfChiseled
+.fi
+
+.eh
+
+.TP
+.I "XtNinnerOffset"
+The default value for \fIinnerOffset\fP is set to 3 pixels, which makes
+it a little bit more likely that the descenders of the label will stay
+visible.
+
+
+
+.hi
+
+.nf
+ innerOffset = 3
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfRowCol
+Name Class Type Default
+XtNstoreByRow XtCStoreByRow Boolean True
+XtNrows XtCRows Int 0
+XtNcolumns XtCColumns Int 0
+XtNalignment XtCAlignment Alignment XfwfTopLeft
+XtNshrinkToFit XtCShrinkToFit Boolean False
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The \fISelectionType\fP type is exported to the public header file.
+
+
+
+.nf
+
+.B type
+ SelectionType = enum {
+ XfwfNoSelection, XfwfSingleSelection,
+ XfwfOneSelection, XfwfMultipleSelection }
+.fi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <Xfwf/Toggle.h>
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Xmu/Converters.h>
+.fi
+
+.nf
+
+.B incl
+ <Xfwf/Converters.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The GC is used for the text.
+
+
+
+.nf
+GC textgc
+.fi
+
+The private variable \fItoggle_ord\fP holds the number that will be
+assigned to the next child that is a toggle button. The first toggle
+will be number 0.
+
+
+
+.nf
+Cardinal toggle_ord
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The type converter from String to SelectionType is installed here.
+
+.nf
+class_initialize()
+{
+ XtAddConverter(XtRString, XtRLong, XmuCvtStringToLong, NULL, 0);
+ XtSetTypeConverter(XtRLong, XtRString, XfwfCvtLongToString,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRString, XtRSelectionType, cvtStringToSelectionType,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter(XtRSelectionType, XtRString, cvtSelectionTypeToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+.fi
+
+The \fIinitialize\fP method initializes the private variables.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $toggle_ord = 0;
+ $textgc = NULL;
+ make_textgc($);
+ if ($selectionStyle == XfwfOneSelection $selection == -1L) {
+ XtWarning
+ ("Illegal combination of selectionStyle and selection resources");
+ $selection = 0;
+ }
+}
+.fi
+
+The \fIset_values\fP method has to deal with changes in \fIlabel\fP, \fIfont\fP,
+\fIselectionType\fP or \fIselection\fP. A change in \fIselection\fP or
+\fIselectionType\fP means that all toggle buttons must be set to on or off
+according to the new values.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redraw = False;
+
+ if ($old$label != $label) {
+ XtFree($old$label);
+ $label = XtNewString($label);
+ need_redraw = True;
+ }
+ if ($font != $old$font) {
+ make_textgc($);
+ if ($label != NULL) need_redraw = True;
+ }
+ if ($old$selection != $selection
+ || $old$selectionStyle != $selectionStyle) {
+ if ($selectionStyle == XfwfOneSelection $selection == -1L)
+ $selection = 0;
+ set_toggles($);
+ }
+ return need_redraw;
+}
+.fi
+
+The \fIexpose\fP method first calls the \fIexpose\fP method of its
+superclass -- which basically just draws the frame -- and then adds
+the label to it.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Dimension w, h;
+ Position x, y;
+
+ if (! XtIsRealized($)) return;
+ #expose($, event, region);
+ $compute_inside($, x, y, w, h);
+ XDrawImageString(XtDisplay($), XtWindow($), $textgc, x + 3,
+ y - $innerOffset, $label, strlen($label));
+}
+.fi
+
+When a child is added, the Group widget checks to see if it is a
+Toggle button. If it is, and the \fIselectionStyle\fP resource is not
+\fIXfwfNoSelection\fP, then the toggle button is assigned a number and two
+callbacks are installed in it. The callbacks' task is to record any
+changes in the state of the togle button in the Group widget's
+\fIselection\fP resource and also to make sure that no more and no fewer
+buttons are turned on then is allowed by the \fIselectionStyle\fP.
+
+It doesn't matter whether the new child is managed or not: any child
+that is (a subclass of) an XfwfToggle button gets two callbacks and a
+number.
+
+The \fIon\fP resource of the new child is also set in accordance with the
+current value of the Group's \fIselection\fP resource.
+
+.nf
+insert_child(Widget child)
+{
+ #insert_child(child);
+ if ($selectionStyle != XfwfNoSelection
+ XtIsSubclass(child, xfwfToggleWidgetClass)) {
+ XtAddCallback(child, XtNonCallback, on_cb, (XtPointer) $toggle_ord);
+ XtAddCallback(child, XtNoffCallback, off_cb, (XtPointer) $toggle_ord);
+ switch ($selectionStyle) {
+ case XfwfOneSelection:
+ case XfwfSingleSelection:
+ XtVaSetValues(child, XtNon, $toggle_ord == $selection, NULL);
+ break;
+ case XfwfMultipleSelection:
+ XtVaSetValues(child, XtNon,
+ ($selection (1L<<$toggle_ord)) != 0, NULL);
+ break;
+ default: ;
+ }
+ $toggle_ord++;
+ }
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The \fImake_textgc\fP routine creates the GC for the text.
+
+.nf
+make_textgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($textgc != NULL) XtReleaseGC($, $textgc);
+ values.background = $background_pixel;
+ values.foreground = $foreground;
+ values.font = $font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ $textgc = XtGetGC($, mask, values);
+}
+.fi
+
+The task of the \fIon_cb\fP callback function is to record the changed
+state of the toggle button and maybe turn off other toggle buttons.
+When the new value of \fIselection\fP is computed, the \fIactivate\fP
+callbacks are called.
+
+.nf
+on_cb(Widget toggle, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = XtParent(toggle);
+ Cardinal toggle_ord = (Cardinal) client_data;
+ Cardinal t, i, bits = sizeof($selection) * 8;
+
+ switch ($selectionStyle) {
+ case XfwfMultipleSelection:
+ if (toggle_ord < bits) $selection |= 1L << toggle_ord;
+ break;
+ case XfwfSingleSelection:
+ case XfwfOneSelection:
+ if ($selection != -1L)
+ for (t = 0, i = 0; i < $num_children; i++)
+ if (XtIsSubclass($children[i], xfwfToggleWidgetClass)) {
+ if ($selection == t) {
+ XtVaSetValues($children[i], XtNon, False, NULL);
+ break;
+ }
+ t++;
+ }
+ $selection = toggle_ord;
+ break;
+ default: ;
+ }
+ XtCallCallbackList($, $activate, (XtPointer) $selection);
+}
+.fi
+
+The task of the \fIoff_cb\fP callback function is to update the
+\fIselection\fP resource and check if turning off the toggle button is
+allowed. If the \fIselectionStyle\fP is \fIXfwfOneSelection\fP, toggles cannot
+be turned off, except by turning on another one.
+
+.nf
+off_cb(Widget toggle, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = XtParent(toggle);
+ Cardinal toggle_ord = (Cardinal) client_data;
+ Cardinal t, i, bits = sizeof($selection) * 8;
+
+ switch ($selectionStyle) {
+ case XfwfOneSelection:
+ XtVaSetValues(toggle, XtNon, True, NULL); /* Undo */
+ break;
+ case XfwfSingleSelection:
+ $selection = -1L; /* Nothing selected */
+ break;
+ case XfwfMultipleSelection:
+ if (toggle_ord < bits) $selection = ~(1L << toggle_ord);
+ break;
+ default: ;
+ }
+ XtCallCallbackList($, $activate, (XtPointer) $selection);
+}
+.fi
+
+The function \fIset_toggles\fP is used when the \fIselection\fP resource or
+the \fIselectionStyle\fP resource changes. It inspects all child widgets
+in turn and turns toggles on or off according to the values of these
+two resources.
+
+.nf
+set_toggles($)
+{
+ Cardinal i, t;
+
+ for (t = 0, i = 0; i < $num_children; i++)
+ if (XtIsSubclass($children[i], xfwfToggleWidgetClass)) {
+ switch ($selectionStyle) {
+ case XfwfNoSelection:
+ break;
+ case XfwfSingleSelection:
+ case XfwfOneSelection:
+ XtVaSetValues($children[i], XtNon, t == $selection, NULL);
+ break;
+ case XfwfMultipleSelection:
+ XtVaSetValues($children[i],
+ XtNon, ($selection (1L<<t)) != 0, NULL);
+ break;
+ }
+ t++;
+ }
+}
+.fi
+
+\fIcvtStringToSelectionType\fP converts the strings `no', `none',
+`single', `one', `multi' and `multiple'. Case doesn't matter.
+
+\fBdef\fP done(type, value) =
+do {
+ if (to->addr != NULL) {
+ if (to->size < sizeof(type)) {
+ to->size = sizeof(type);
+ return False;
+ }
+ *(type*)(to->addr) = (value);
+ } else {
+ static type static_val;
+ static_val = (value);
+ to->addr = (XtPointer)static_val;
+ }
+ to->size = sizeof(type);
+ return True;
+ }while (0 )
+
+.nf
+Boolean cvtStringToSelectionType(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToSelectionType", "wrongParameters",
+ "XtToolkitError",
+ "String to SelectionType conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "no") == 0)
+ done(SelectionType, XfwfNoSelection);
+ if (XmuCompareISOLatin1(s, "none") == 0)
+ done(SelectionType, XfwfNoSelection);
+ if (XmuCompareISOLatin1(s, "single") == 0)
+ done(SelectionType, XfwfSingleSelection);
+ if (XmuCompareISOLatin1(s, "one") == 0)
+ done(SelectionType, XfwfOneSelection);
+ if (XmuCompareISOLatin1(s, "multi") == 0)
+ done(SelectionType, XfwfMultipleSelection);
+ if (XmuCompareISOLatin1(s, "multiple") == 0)
+ done(SelectionType, XfwfMultipleSelection);
+
+ XtDisplayStringConversionWarning(display, s, XtRSelectionType);
+ done(SelectionType, XfwfSingleSelection);
+}
+.fi
+
+A converter in the opposite direction.
+
+.nf
+Boolean cvtSelectionTypeToString(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ char s[30];
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToSelectionStyle", "wrongParameters",
+ "XtToolkitError",
+ "String to SelectionStyle conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*((SelectionType*) from->addr)) {
+ case XfwfNoSelection: done(String, "none");
+ case XfwfSingleSelection: done(String, "single");
+ case XfwfOneSelection: done(String, "one");
+ case XfwfMultipleSelection: done(String, "multiple");
+ }
+ XtDisplayStringConversionWarning(display, s, XtRSelectionType);
+ done(String, "none");
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/GroupP.h b/vendor/x11iraf/obm/ObmW/GroupP.h
new file mode 100644
index 00000000..842131b4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GroupP.h
@@ -0,0 +1,48 @@
+/* Generated by wbuild from "Group.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfGroupP_H_
+#define _XfwfGroupP_H_
+#include "RowColP.h"
+#include "Group.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfGroupClassPart;
+typedef struct _XfwfGroupClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfRowColClassPart xfwfRowCol_class;
+XfwfGroupClassPart xfwfGroup_class;
+} XfwfGroupClassRec;
+
+typedef struct {
+/* resources */
+String label;
+XFontStruct * font;
+Pixel foreground;
+SelectionType selectionStyle;
+long selection;
+XtCallbackList activate;
+/* private state */
+GC textgc;
+Cardinal toggle_ord;
+} XfwfGroupPart;
+
+typedef struct _XfwfGroupRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfRowColPart xfwfRowCol;
+XfwfGroupPart xfwfGroup;
+} XfwfGroupRec;
+
+externalref XfwfGroupClassRec xfwfGroupClassRec;
+
+#endif /* _XfwfGroupP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c
new file mode 100644
index 00000000..03748e0e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c
@@ -0,0 +1,13283 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+
+#define DEBUG_GTERM 1
+#define DEBUG_TRACE 1
+#define DBG_TRACE 1
+#define DEBUG_VISUAL 1
+/*
+*/
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+#define CacheXImage 0 /* MF004 */
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNuseGlobalCmap, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useGlobalCmap), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), invalidate_cmap();
+static void gm_rotate_indicator(); /* MF020 */
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+static Pixel ColorNameToPixel ();
+
+/* Global Colormap declarations.
+ */
+#define CMAPNAME_SIZE 160
+
+static char global_cmapname[CMAPNAME_SIZE];
+static Pixel global_cmap[MAX_SZCMAP];
+static XColor global_color[MAX_SZCMAP];
+static int global_ncolors;
+static int global_mincolors;
+static int SetGlobalCmap(), ParseGlobalCmap();
+static int GetMaxCmapColors();
+static int GetGlobalColors();
+static void SetGlobalColors();
+
+
+static void NewCachedXImage(); /* MF004 */
+static void DestroyCachedXImage(); /* MF004 */
+static XImage *GetCachedXImage(); /* MF004 */
+
+
+static char *dbg_wSize(); /* debug utils */
+static char *dbg_visStr();
+
+extern double atof();
+
+
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ XVisualInfo info; /* Deep Frame */
+ XStandardColormap std, *stdcmaps;
+ int nstdcmaps;
+ XColor colors[MAX_SZCMAP];
+ char property[128];
+ char names[10][15];
+
+
+ for (i=0 ; i < MAX_SZCMAP; i++)
+ memset (&colors[i], 0, sizeof(XColor));
+
+
+/*
+memset (w, 0, sizeof(GtermWidget));
+*/
+ strcpy(names[0],"black");
+ strcpy(names[1],"white");
+ strcpy(names[2],"red");
+ strcpy(names[3],"green");
+ strcpy(names[4],"blue");
+ strcpy(names[5],"cyan");
+ strcpy(names[6],"yellow");
+ strcpy(names[7],"magenta");
+ strcpy(names[8],"purple");
+ strcpy(names[9],"darkslategray"); /* Deep Frame */
+
+
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ w->gterm.w_depth = DefaultDepth (display, DefaultScreen(display));
+ w->gterm.w_visual_class =
+ DefaultVisual (display, DefaultScreen(display))->class;
+
+
+ /* Deep Frame */
+
+ /* Check if default visual is Pseudo color 8. If so, continue, else
+ * force a Pseudo 8 visual and new StandardColorMap.
+ */
+ if (XMatchVisualInfo(display, DefaultScreen(display), 8, PseudoColor,
+ &info)) {
+
+ /* reset some gterm and core values to reflect the new visual */
+ w->core.depth = info.depth;
+ w->gterm.visual = info.visual;
+ w->gterm.forcePseudo8 = True;
+
+ /* Find the Standard Color Map */
+
+ /* calculate cmap name */
+ /* if default, try to extract name from 'default[n:m,name]' */
+printf ("Gterm.initialize(Pseudo8): cmapName = '%s'\n", w->gterm.cmapName);
+ if (!strncmp(w->gterm.cmapName,"default",7)) {
+ char *p;
+
+ if (p=strstr(w->gterm.cmapName,"[")) {
+ if (p=strstr(p,",")) {
+ strcpy(global_cmapname,++p);
+ if (p=strstr(global_cmapname,"]")) {
+ *p='\0'; /* cut off the last ']' */
+ strcpy(w->gterm.cmapName,global_cmapname);
+ }
+ }
+ }
+ }
+
+ /* if that didn't work, give it a name
+ if (!strncmp(w->gterm.cmapName,"default",7))
+ strcpy(w->gterm.cmapName,"ForcePseudo");
+ */
+printf ("Gterm.initialize 2(Pseudo8): cmapName = '%s'\n", w->gterm.cmapName);
+
+ /* create atom */
+ sprintf(property, "GT_%s", w->gterm.cmapName);
+ w->gterm.cmapAtom = XInternAtom (display, property, False);
+
+ w->core.colormap=0;
+ if (XGetRGBColormaps (display, w->gterm.root, &stdcmaps, &nstdcmaps,
+ w->gterm.cmapAtom)) {
+ if (stdcmaps[0].colormap && stdcmaps[0].visualid==info.visualid) {
+ w->core.colormap = stdcmaps[0].colormap;
+ w->gterm.base_pixel = stdcmaps[0].base_pixel;
+ }
+ }
+printf ("Gterm.intialize(Pseudo8): colormap = %d\n", w->core.colormap);
+
+ /* create Standard Color Map */
+ if (!w->core.colormap && info.visual) {
+ w->core.colormap = XCreateColormap (display, w->gterm.root,
+ info.visual, AllocAll);
+
+ /* Set the Static Colors */
+printf ("Gterm.intialize(Pseudo8): setting static colors\n");
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ colors[i].pixel = i;
+ XParseColor(display, w->core.colormap, names[i], &colors[i]);
+ }
+ XStoreColors (display, w->core.colormap, colors, SZ_STATIC_CMAP);
+
+ /* save Standard Color Map */
+ std.colormap = w->core.colormap;
+ std.red_max = 1;
+ std.red_mult = 0;
+ std.green_max = std.green_mult = 0;
+ std.blue_max = std.blue_mult = 0;
+ std.base_pixel = w->gterm.base_pixel;
+ std.visualid = info.visualid;
+ std.killid = 0;
+ XSetRGBColormaps (display, w->gterm.root, &std, 1,
+ w->gterm.cmapAtom);
+ XSetCloseDownMode (display, RetainPermanent);
+ }
+
+ /* Fix Color Related Resources */
+
+ w->gterm.dialogBgColor =
+ ColorNameToPixel (w, w->gterm.dialogBgColorStr);
+ w->gterm.dialogFgColor =
+ ColorNameToPixel (w, w->gterm.dialogFgColorStr);
+
+ w->gterm.idleCursorBgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorBgColorStr);
+ w->gterm.idleCursorFgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorFgColorStr);
+
+ w->gterm.busyCursorBgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorBgColorStr);
+ w->gterm.busyCursorFgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorFgColorStr);
+
+ w->gterm.ginmodeCursorBgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorBgColorStr);
+ w->gterm.ginmodeCursorFgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorFgColorStr);
+ w->gterm.crosshairCursorColor =
+ ColorNameToPixel (w, w->gterm.crosshairCursorColorStr);
+
+ w->gterm.color0 = ColorNameToPixel (w, w->gterm.color0Str);
+ w->gterm.color1 = ColorNameToPixel (w, w->gterm.color1Str);
+ w->gterm.color2 = ColorNameToPixel (w, w->gterm.color2Str);
+ w->gterm.color3 = ColorNameToPixel (w, w->gterm.color3Str);
+ w->gterm.color4 = ColorNameToPixel (w, w->gterm.color4Str);
+ w->gterm.color5 = ColorNameToPixel (w, w->gterm.color5Str);
+ w->gterm.color6 = ColorNameToPixel (w, w->gterm.color6Str);
+ w->gterm.color7 = ColorNameToPixel (w, w->gterm.color7Str);
+ w->gterm.color8 = ColorNameToPixel (w, w->gterm.color8Str);
+ w->gterm.color9 = ColorNameToPixel (w, w->gterm.color9Str);
+
+ w->gterm.gm_fillColor =
+ ColorNameToPixel (w, w->gterm.gm_fillColorStr);
+ w->gterm.gm_fillBgColor =
+ ColorNameToPixel (w, w->gterm.gm_fillBgColorStr);
+
+ w->gterm.gm_highlightColor =
+ ColorNameToPixel (w, w->gterm.gm_highlightColorStr);
+
+ w->gterm.gm_cursorFgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorFgColorStr);
+ w->gterm.gm_cursorBgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorBgColorStr);
+
+ w->gterm.gm_LineLineColor =
+ ColorNameToPixel (w, w->gterm.gm_LineLineColorStr);
+ w->gterm.gm_LineKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_LineKnotColorStr);
+
+ w->gterm.gm_TextLineColor =
+ ColorNameToPixel (w, w->gterm.gm_TextLineColorStr);
+ w->gterm.gm_TextColor =
+ ColorNameToPixel (w, w->gterm.gm_TextColorStr);
+ w->gterm.gm_TextBgColor =
+ ColorNameToPixel (w, w->gterm.gm_TextBgColorStr);
+
+ w->gterm.gm_RectLineColor =
+ ColorNameToPixel (w, w->gterm.gm_RectLineColorStr);
+ w->gterm.gm_RectKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_RectKnotColorStr);
+
+ w->gterm.gm_BoxLineColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxLineColorStr);
+ w->gterm.gm_BoxKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxKnotColorStr);
+
+ w->gterm.gm_CircleLineColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleLineColorStr);
+ w->gterm.gm_CircleKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleKnotColorStr);
+
+ w->gterm.gm_EllipseLineColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseLineColorStr);
+ w->gterm.gm_EllipseKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseKnotColorStr);
+
+ w->gterm.gm_PgonLineColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonLineColorStr);
+ w->gterm.gm_PgonKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonKnotColorStr);
+
+ /* let gterm know what we have done */
+ /* will be reset later on, but put here for clarity */
+ w->gterm.useDefaultCM = False;
+ w->gterm.useGlobalCmap = False;
+ w->gterm.haveColormap = True;
+ w->gterm.cmapInitialize = False;
+
+
+ } else {
+ XVisualInfo *vp, template;
+ int nvis;
+
+ memset (&template, 0, sizeof (template));
+ template.class = TrueColor;
+
+ vp = XGetVisualInfo (display, VisualClassMask, &template, &nvis);
+
+fprintf (stderr, "NO 8-bit PSEUDO FOUND.....USING TRUECOLOR\n");
+fprintf (stderr, "nvis=%d defDepth=%d\n", nvis, w->gterm.w_depth);
+
+
+
+
+
+ w->gterm.useDefaultCM = 1;
+ w->gterm.haveColormap = 0;
+
+ w->gterm.forcePseudo8 = False;
+ }
+
+printf ("Gterm.intialize: forcePseudo8 = %d\n\n", w->gterm.forcePseudo8);
+ /* Deep Frame */
+
+
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map. */
+/*
+*/
+ pp = &w->gterm.color0;
+ w->gterm.cmap = (Pixel *)XtCalloc(MAX_SZCMAP, sizeof(Pixel));
+ w->gterm.color = (XColor *)XtCalloc(MAX_SZCMAP, sizeof(XColor));
+
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+
+/*
+fprintf(stderr, "Gterm.initialize: iomap[] and cmap[]\n");
+for (i=0; i < 256; i++)
+ fprintf(stderr, "%3d: %3d %3d\n", i, w->gterm.iomap[i], w->gterm.cmap[i]);
+*/
+
+ /* if we have not yet allocated any colors ... The SetGlobalCmap()
+ ** function returns zero when useGlobalCmap is disabled, but it also
+ ** allocates the gterm.cmap and gterm.color pointers in this case.
+ */
+ if (SetGlobalCmap(w) == 0) {
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors(display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ } else {
+ /* in the case of a default colormap, we might already have color
+ * cells.
+ */
+ w->gterm.ncolors = GetGlobalColors ();
+ }
+ w->gterm.useDefaultCM = ParseGlobalCmap (w);
+
+printf ("Gterm.intialize: ncolors=%d useDefaultCM=%d\n",
+ w->gterm.ncolors, w->gterm.useDefaultCM);
+
+
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+ w->gterm.n_wmWindows = 0; /* MF012 */
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,"Gterm.intialize: Clearing pixmaps and drawables ....");
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+ if (DBG_TRACE)
+ fprintf (stderr,"done.\n");
+
+ /* Get special cursors. */
+ if (DBG_TRACE)
+ fprintf (stderr,"Gterm.intialize: Getting cursors ....");
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+ /* MF030 */
+
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+ /* MF030 */
+
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color); /* MF030 */
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+ if (DBG_TRACE)
+ fprintf (stderr,"done.\n");
+
+
+
+ /* Make sure we have all the fonts we need. */
+ if (DBG_TRACE)
+ fprintf (stderr,"Gterm.intialize: Intiializing fonts ....");
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+ if (DBG_TRACE) fprintf (stderr,"done.\n");
+
+
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+
+ /* Deep Frame
+ set_default_color_index (w);
+ Deep Frame */
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Initialize[%s] RETURNING\n\n", dbg_wSize(w));
+}
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+ GC gc;
+
+
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Realize[%s] ENTER:\n", dbg_wSize(w));
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ /* Create graphics window. */ /* Deep Frame */
+ if (w->gterm.forcePseudo8) /* force Pseudo 8 visual */
+ XtCreateWindow (gw, InputOutput, w->gterm.visual, *valueMask, attrs);
+
+ else /* Default Visual is Pseudo */
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent, *valueMask,
+ attrs); /* Deep Frame */
+
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+
+ /* Deep Frame */
+ /* Define GC here, so that we have a Drawable at the proper depth */
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+/* XSetGraphicsExposures (w->gterm.display, gc, 0); /* MF029 */
+
+ /* Get expose GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ w->gterm.exposeGC = gc;
+/* XSetGraphicsExposures (w->gterm.display, gc, 0); /* MF029 */
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.dialogBgColor);
+ XSetForeground (w->gterm.display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (w->gterm.display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (w->gterm.display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ set_default_color_index (w);
+ if (w->gterm.forcePseudo8) {
+ XInstallColormap (w->gterm.display, w->core.colormap);
+ request_colormap_focus (w);
+ }
+ /* Deep Frame */
+
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Realize[%s] DONE:\n", dbg_wSize(w));
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Destroy[%s] ENTER:\n", dbg_wSize(w));
+
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (w); /* MF008 */
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Destroy[%s] DONE:\n", dbg_wSize(w));
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+ if (!w || !XtIsRealized(gw))
+ return;
+
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Resize[%s] ENTER:\n", dbg_wSize(w));
+
+
+ /* Create new pixmap.
+ */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap. */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap. */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window. */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap. */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size. */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size. */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ }
+
+ /* Mark gterm widget ready for further client input. */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+
+
+ if (DEBUG_TRACE) {
+ fprintf (stderr, "Resize[%s] DONE:\n", dbg_wSize(w));
+ }
+}
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!w || !XtIsRealized (gw))
+ return;
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Redisplay[%s]: ENTER\n", dbg_wSize(w));
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+
+ if (DEBUG_TRACE)
+ fprintf (stderr, "Redisplay[%s] DONE:\n", dbg_wSize(w));
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+ /* Deep Frame */
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap &&
+ !w->gterm.forcePseudo8) {
+
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+ request_colormap_focus (w);
+ }
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+/*printf ("HandleLeaveWindow....");*/
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+/*printf ("restoring focus....");*/
+ restore_colormap_focus (w);
+ }
+/*printf ("\n");*/
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++ || raster == 0) { /* MF041 */
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ XSync (display, False);
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ if (w->gterm.cursor_type != GtGinmodeCursor) /* MF032 */
+ return;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap)
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ Otherwise the cursor movement keystrokes scale incorrectly and quickly move
+ to (0,0).
+ mx->xoffset = mx->yoffset = mx->scale = 0;
+ [DCT] This doesn't look entirely right as it disables logical coords for
+ the screen. Leave as is until this can be studied more carefully.
+ */
+
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+
+ /* Deep Frame */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.window,
+ 0, NULL);
+ /* Deep Frame */
+
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
+
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window. */
+fprintf(stderr, "GtRasterInit: Init PIXMAPRASTER (%d x %d) pixmap=0x%x\n",
+w->core.width, w->core.height, w->gterm.window);
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ w->gterm.nrasters++;
+fprintf(stderr, "GtRasterInit: w->gterm.nrasters = %d\n", w->gterm.nrasters);
+
+ /* Free any previously allocated colormap cells. */
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors - SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+fprintf(stderr, "GtRasterInit: After Init Mappings...Returning\n");
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+ } else
+ wa = w->gterm.wa;
+
+fprintf(stderr, "GtAssignRaster: Assigning PIXMAPRASTER\n");
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ /* Only rasters of depth 8 bits are currently supported. */
+fprintf (stderr, "GtCreateRaster: raster=%d type=%d (%d x %d x %d)\n",
+ raster, type, width, height, depth);
+
+ if (depth && depth != 8)
+{
+fprintf (stderr, "GtCreateRaster: DEPTH != 8\n\n\n\n\n\n");
+ return (ERR);
+}
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+
+/* 24-BIT: For the moment, disable caching. We'll need to come back to
+** this and fix up all the cache usage in the same way. Note the call to
+** XFillRectangle() below triggers an X error.
+cache = 0;
+*/
+
+/* 24-BIT: */
+
+
+fprintf(stderr,"GtCreateRaster: CACHE: %d (%dx%dx%d)\n",
+ cache, width, height, depth);
+fprintf(stderr,"GtCreateRaster: Creating %s: %d\n",
+ (cache ? "PIXMAPRASTER" : "IMAGERASTER"), raster);
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, RasterDepth);
+ if (rp->r.pixmap == (Pixmap)NULL)
+ goto ximage;
+/* 24-BIT
+ XFillRectangle (w->gterm.display, rp->r.pixmap, w->gterm.clearGC,
+ 0, 0, width, height);
+ 24-BIT */
+
+ } else {
+ /* Create an XImage. */
+ximage:
+ rp->type = ImageRaster;
+
+ /* Get pixel storage.
+ npix = width * height;
+ */
+ npix = width * height * (depth / 8); /* 24-bit */
+
+ if ((data = (uchar *) XtMalloc(npix)) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+ }
+
+ w->gterm.nrasters++;
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = RasterDepth;
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+ int bytes_per_line, i;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+ int *rgb; /* rgb-mode pixel pointer */
+ XWindowAttributes wa;
+ unsigned int *ras = NULL;
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePixels[%s] ENTER....nbits=%d\n",
+ dbg_wSize(w), nbits);
+
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ fprintf (stderr, "GtWritePixels: Error getting window attrs\n");
+ return (ERR);
+ }
+ } else
+ wa = w->gterm.wa;
+
+#ifdef DEBUG_VISUAL
+ fprintf (stderr, "GtWritePixels: depth=%d RasterDepth= %d class=%s\n",
+ wa.depth, RasterDepth, dbg_visStr(wa.visual->class));
+#endif
+
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Doing PixmapRaster[%s]....depth=%d\n",
+ dbg_wSize(w), wa.depth);
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+
+ if (wa.depth == ColormapDepth) {
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Creating 8-bit ximage\n");
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+ } else if (wa.depth == RGBDepth) {
+ int i, j, p, pv;
+
+ ras = (unsigned int *) XtMalloc (nx * ny * sizeof(int));
+ memset (ras, 0, (nx * ny * sizeof (int)) );
+ for (i=0; i < ny; i++) {
+ for (j=0; j < nx; j++) {
+ p = i * nx + j; /* get index */
+ pv = data[p];
+ ras[p] = (pv << 16) | (pv << 8) | pv ;
+ }
+ }
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Creating 24-bit ximage\n");
+/*
+ ximage = XCreateImage (w->gterm.display, NULL, RGBDepth,
+ ZPixmap, 0, (char *)ras, nx, ny, 8, 0);
+*/
+ ximage = XCreateImage (w->gterm.display, NULL, RGBDepth,
+ ZPixmap, 0, (char *)ras, nx, ny, 32, 0);
+
+ } else {
+ fprintf (stderr, "GtWritePixels: Unsupported raster depth\n");
+ return (ERR);
+ }
+
+ if (raster == 0 && w->gterm.pixmap) {
+
+ if (DBG_TRACE)
+ fprintf(stderr, "(raster == 0 && w->gterm.pixmap)\n");
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ if (wa.depth != ColormapDepth)
+ XtFree ((char *)ras);
+
+ XCopyArea (display, w->gterm.pixmap, rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+
+ } else {
+ if (DBG_TRACE)
+ fprintf(stderr, "raster=0 else....\n");
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+ }
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+fprintf(stderr, "GtWritePix: Doing ImageRaster....bytes_per_line=%d\n",
+ rp->r.ximage->bytes_per_line);
+fprintf(stderr, "GtWritePix: Doing ImageRaster....depth=%d\n",
+ rp->r.ximage->depth);
+/*
+*/
+
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ ip = pixels;
+
+ if (wa.depth == ColormapDepth) {
+fprintf(stderr, "Doing ColormapDepth....writing to ximage\n");
+ int min=256, max=0;
+ int min1=256, max1=0;
+
+
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map
+ * is dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation woudl also make it
+ * easy to add support later for image depths other than 8 bit.
+ * Doing the conversion to display pixels here is however simpler
+ * and more efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; ) {
+ *op++ = (cmap[*ip++] & 0377);
+if (*ip < min) min = *ip; if (cmap[*ip] < min1) min1 = cmap[*ip];
+if (*ip > max) max = *ip; if (cmap[*ip] > max1) max1 = cmap[*ip];
+ }
+ lp += bytes_per_line;
+ }
+fprintf (stderr, "CMAP MINMAX: %d %d -- %d %d\n", min, max, min1, max1);
+
+ } else if (wa.depth == RGBDepth) {
+ int pv;
+ int min=256, max=0;
+ int min1=256, max1=0;
+
+fprintf(stderr, "Doing RGBDepth....writing to ximage\n");
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; ) {
+if (*ip < min) min = *ip; if (cmap[*ip] < min1) min1 = cmap[*ip];
+if (*ip > max) max = *ip; if (cmap[*ip] > max1) max1 = cmap[*ip];
+ /*
+ *op++ = (*ip++ & 0377);
+ */
+ *op++ = (cmap[*ip++] & 0377);
+ }
+ lp += bytes_per_line;
+ }
+fprintf (stderr, "RGB MINMAX: pixel: %d %d -- cmap: %d %d bpl: %d\n",
+ min, max, min1, max1, bytes_per_line);
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePixels[%s] LEAVING....\n", dbg_wSize(w));
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage. */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ? w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + y * bytes_per_line + x;
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; ) {
+ *op++ = cmap[*ip++];
+ }
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store)
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny, /* MF006 */
+ RasterDepth) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (w, i); /* MF005 */
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ dst, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny, /* MF006 */
+ RasterDepth) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n, use_wa = 1;
+ unsigned long plane_masks[1];
+ int req, need;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (ERR);
+
+/*
+fprintf (stderr, "GtWriteColormap: entry.....\n\n");
+fprintf (stderr, "GtWriteColormap: map=%d first=%d nelem=%d\n", map, first, nelem);
+*/
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+ /* See if the colormap already exists. */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it. */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap. */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ if (nelem >= 0) {
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+ }
+
+/*
+fprintf (stderr, "GtWriteColormap: map=%d == modifying colormap\n", map);
+*/
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache. */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+/*
+fprintf (stderr, "GtWriteColormap: w=0x%x w->gterm=0x%x defined=%d\n",
+ w, &w->gterm, w->gterm.wa_defined);
+*/
+ if (w->gterm.w_depth == 0 && w->gterm.w_visual_class == 0) {
+/*
+fprintf (stderr, "GtWriteColormap: doing XGetWindowAttributes\n\n");
+*/
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+
+ if (wa.depth == 1)
+ goto unitary;
+ } else
+ use_wa = 0;
+
+
+/*
+ switch (wa.visual->class) {
+fprintf (stderr, "GtWriteColormap: before switch\n\n");
+*/
+ switch ((use_wa ? wa.visual->class : w->gterm.w_visual_class)) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp))
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ Colormap colormap;
+ long timeval, time();
+ int ncolors, shadow;
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow * 1000))) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+unitary:
+ if ((first+nelem) > MAX_SZCMAP) {
+ fprintf (stderr, "GtWriteColormap: Error first=%d nelem=%d\n",
+ first, nelem);
+ break;
+ }
+ for (i = first; i < first+nelem; i++) {
+ w->gterm.cmap[i] = i;
+ cp = &w->gterm.color[i];
+ cp->pixel = i;
+ cp->red = r[i+first];
+ cp->green = g[i+first];
+ cp->blue = b[i+first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+ break;
+ }
+
+fprintf (stderr, "GtWriteColormap: leaving\n");
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+ register int i;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++)
+ if (first+i < w->gterm.ncolors) {
+ cp = &w->gterm.color[first+i];
+ r[i] = cp->red;
+ g[i] = cp->green;
+ b[i] = (ushort)cp->blue;
+ } else
+ break;
+
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap. */
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ } else {
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ * is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ /* Load the colormap into the display. */
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+ /* If the colormap we loaded to the display was the display colormap,
+ * restore the original unscaled colors in the gterm descriptor so that
+ * we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0)
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+
+ return (OK);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+ }
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ struct mapping sv_mp, p_mp; /* MF007 */
+ int status;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+fprintf(stderr, "GtCopyRaster() -- \n");
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ int dummy_rop; /* MF011 */
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+fprintf (stderr, "GtSetMapping - ENTER\n");
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return (OK);
+ } else if (!mp->enabled) {
+ return (OK);
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return (OK);
+
+ if (rop & R_RefreshNone)
+ return (OK);
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &dummy_rop, /* MF011 */
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+
+fprintf (stderr, "GtSetMapping - LEAVING\n");
+ return (OK);
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+fprintf(stderr, "GtRefreshMapping() -- \n");
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+ if (w->gterm.haveColormap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+ /* Get custom colormap.
+ */
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+
+ /* Free the XVisualInfo struct. */
+ if (vi)
+ XFree ((void *)vi); /* MF040 */
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+{ printf ("get_colormap ... requesting focus...\n");
+ request_colormap_focus (w);
+}
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++)
+ for (j=0, v = ip->pixel; j < n; j++)
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++)
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap,
+ colors, op - colors);
+
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+}
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Compute the intersection of the modified region of the source raster
+ * with the rectangular region of the source raster affected by the given
+ * mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect. */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ /* Perform the refresh operation. */
+fprintf(stderr, "refresh_source() -- \n");
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+ Pixmap pixmap; /* MF004 */
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap;
+ XRectangle r;
+
+
+
+fprintf(stderr, "ENTERING refresh_destination, x,y = %d,%d nx,ny = %d,%d\n",
+ x1,y1,nx,ny);
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ if (DEBUG_TRACE)
+ fprintf(stderr, "\nENTER refresh_destination\n");
+
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (!sr->type || !dr->type)
+ return (ERR);
+ if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0)
+ return (ERR);
+ if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters)
+ return (ERR);
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+
+ if (clip && dr->type == PixmapRaster) {
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ }
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+fprintf(stderr, "refresh_destination -- pixmap copy src=dst=0\n");
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination -- spec_case 0\n");
+
+ if (w->gterm.w_depth == ColormapDepth) {
+ XCopyArea (display, w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ ;
+ XSetClipMask (display, w->gterm.exposeGC, None);
+ XCopyArea (display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ ;
+ }
+ } else {
+
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination -- spec_case 1 (d=%d)\n",
+ w->gterm.w_depth);
+
+ if (w->gterm.w_depth == ColormapDepth) {
+fprintf(stderr, "refresh_destination -- doing ColormapDepth\n");
+ XCopyArea (display, sr->r.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display, sr->r.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ } else {
+fprintf(stderr, "refresh_destination -- doing TruecolorDepth\n");
+ ;
+ XSetClipMask (display, w->gterm.exposeGC, None);
+ XCopyArea (display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ ;
+ }
+ }
+
+fprintf(stderr, "refresh_destination -- spec_case: pixmap copy no scaling\n");
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+fprintf(stderr, "refresh_destination -- source type is PixmapRaster\n");
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ if (CacheXImage) { /* MF004 */
+ pixmap = (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap;
+ xin = GetCachedXImage (w, pixmap, sr->width, sr->height);
+ if (xin == NULL) {
+ xin = XGetImage (display, pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ } else
+ NewCachedXImage (w, xin, pixmap, sr->width, sr->height);
+ }
+ } else { /* MF004 */
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } /* MF004 */
+
+ } else {
+ /* Source is an ximage. */
+fprintf(stderr, "refresh_destination -- src type is XImage (sr->r.ximage)\n");
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ if (w->gterm.w_depth == ColormapDepth) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+fprintf(stderr, "3 refresh_destination -- transient 24 XPutImage\n");
+ render24 (w, xin_lp, xin->data, sx, sy, dx, dy, dnx, dny);
+ }
+ } else {
+ if (w->gterm.w_depth == ColormapDepth) {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ } else {
+fprintf(stderr, "3 refresh_destination -- 24 XPutImage\n");
+ render24 (w, xin->data, xin, sx, sy, dx, dy, dnx, dny);
+ ;
+ }
+ }
+
+fprintf(stderr, "refresh_destination -- spec_case: ximage to output pixmap w/ no scaling\n");
+ goto done;
+ }
+
+ /* Get output ximage. */
+ if (dr->type == ImageRaster) {
+fprintf(stderr, "refresh_destination -- dest type is XImage (dr->r.ximage)\n");
+ xout = dr->r.ximage;
+ ox = dx; oy = dy;
+ } else {
+ uchar *data = (uchar *) XtMalloc (dnx * dny);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+fprintf(stderr, "refresh_destination -- creating 8-bit ximage....\n");
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0; oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl + sx;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination. */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ if (w->gterm.w_depth == ColormapDepth) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+fprintf(stderr, "2a refresh_destination -- 24-bit XPutImage\n");
+ render24 (w, xout_lp, xout, ox, oy, dx, dy, dnx, dny);
+ ;
+ }
+ } else {
+ if (w->gterm.w_depth == ColormapDepth) {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ } else {
+fprintf(stderr, "3a refresh_destination -- 24-bit XPutImage\n");
+ }
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin)
+ XDestroyImage (xin);
+ if (delxout)
+ XDestroyImage (xout);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ /* Execute any mappings defined on the raster just updated. */
+fprintf(stderr, "refresh_destination -- doing mappings status=%d\n",status);
+ if (0 &&status == OK) {
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+fprintf(stderr, "LEAVING refresh_destination, status=%d\n",status);
+ return (status);
+}
+
+bob() { int i = 0; fprintf (stderr, "Hi from Bob\n"); }
+
+
+render24 (w, data, xout, sx, sy, dx, dy, dnx, dny)
+GtermWidget w;
+uchar *data;
+XImage *xout;
+int sx, sy, dx, dy, dnx, dny;
+{
+ Display *display = w->gterm.display;
+ Visual *visual = (Visual *) DefaultVisual(display,DefaultScreen(display));
+ unsigned long rp, gp, bp, rmask, gmask, bmask, xcol;
+ int border, bperline, bperpix;
+ XImage *scr = (XImage *) NULL;
+ uchar *val, *pp, pv;
+ uchar *pix = (uchar *) XtMalloc (512 * 512 * 4);
+ int i, j, nx = xout->width, ny=xout->height;
+
+ int first, nelem, maxelem;
+ unsigned short r[256], g[256], b[256];
+ unsigned short rs[256], gs[256], bs[256], iomap[256];
+
+ static int pmin=256, pmax=0;
+ static int rmin=256, rmax=0, rpix;
+ static int gmin=256, gmax=0, gpix;
+ static int bmin=256, bmax=0, bpix;
+
+
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "render24: sx/sy=%d/%d dx/dy=%d/%d dnx/dny=%d/%d\n",
+ sx, sy, dx, dy, dnx, dny);
+ }
+
+
+ /* Query and read the current colormap. */
+/*
+ GtQueryColormap (w, 0, &first, &nelem, &maxelem);
+ GtReadColormap (w, 0, first, nelem, r,g,b);
+
+{
+ int k;
+
+ for (k=0; k < 256; k++)
+ fprintf(stderr, "%3d : %3d %3d %3d\t%3d %3d %3d\n",
+ k, r[k]>>8, g[k]>>8, b[k]>>8,
+ w->gterm.iomap[k], w->gterm.cmap_in[k], w->gterm.cmap_out[k]);
+ fprintf(stderr, "first=%d nelem=%d ncolors=%d maxelem=%d\n",
+ first, nelem, w->gterm.ncolors, maxelem);
+ fprintf(stderr, "maxColors=%d basePixel=%d static=%d max=%d\n",
+ w->gterm.maxColors, w->gterm.base_pixel, SZ_STATIC_CMAP, MAX_SZCMAP);
+}
+*/
+
+/* scr = XCreateImage (display, NULL, RGBDepth,
+ ZPixmap, 0, (char *) NULL, nx, ny, 8, 0);
+*/
+nx = dnx;
+ny = dny;
+ scr = XCreateImage (display, NULL, RGBDepth,
+ ZPixmap, 0, (char *) NULL, nx, ny, 32, 0);
+ scr->data = (char *)pix;
+
+ bperline = scr->bytes_per_line;
+ bperpix = scr->bits_per_pixel;
+ border = scr->byte_order;
+
+ nelem = GtReadColormap (w, 0, 0, MAX_SZCMAP, rs,gs,bs);
+ GtReadIomap (w, iomap, 0, MAX_SZCMAP);
+
+
+ /* Create the colormap.
+ */
+ for (i=0; i < nelem; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8);
+ g[i] = (gs[j] >> 8);
+ b[i] = (bs[j] >> 8);
+ }
+ for (i=nelem; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8);
+ g[i] = (gs[j] >> 8);
+ b[i] = (bs[j] >> 8);
+ }
+
+/*
+{
+ int k;
+
+ for (k=0; k < 256; k++)
+ fprintf(stderr, "%3d : %3d %3d %3d\t%3d %3d %3d\n",
+ k, r[k], g[k], b[k],
+ w->gterm.iomap[k], w->gterm.cmap_in[k], w->gterm.cmap_out[k]);
+ fprintf(stderr, "nelem=%d ncolors=%d maxelem=%d\n",
+ nelem, w->gterm.ncolors, MAX_SZCMAP);
+}
+*/
+
+ val = data;
+ pp = pix;
+ if (scr->byte_order == MSBFirst) {
+ /* MSB First systems (e.g. MacPPC/Sun) */
+ for (i=0; i < ny; i++) {
+ for (j=0; j < nx; j++, val++) {
+ pv = (int) GtGetClientPixel (w, *val);
+
+ *pp++ = 0;
+ *pp++ = (uchar) ((b[pv] >> 8) & 0377);
+ *pp++ = (uchar) ((g[pv] >> 8) & 0377);
+ *pp++ = (uchar) ((r[pv] >> 8) & 0377);
+ }
+ }
+ } else if (scr->byte_order == LSBFirst) {
+ /* LSB First systems (e.g. MacIntel/Linux) */
+ for (i=0; i < ny; i++) {
+ for (j=0; j < nx; j++, val++) {
+/*
+ pv = (int) GtGetClientPixel (w, *val);
+
+ *pp++ = (uchar) ((r[pv] >> 8) & 0xFF);
+ *pp++ = (uchar) ((g[pv] >> 8) & 0xFF);
+ *pp++ = (uchar) ((b[pv] >> 8) & 0xFF);
+ *pp++ = 0;
+*/
+
+
+ pv = (int) *val;
+if (pv > pmax) pmax = pv;
+if (pv < pmin) pmin = pv;
+rpix = (uchar) r[pv];
+gpix = (uchar) g[pv];
+bpix = (uchar) b[pv];
+
+ *pp++ = (uchar) ((r[pv]) & 0xFF);
+ *pp++ = (uchar) ((g[pv]) & 0xFF);
+ *pp++ = (uchar) ((b[pv]) & 0xFF);
+ *pp++ = 0;
+
+if (rpix > rmax) rmax = rpix; if (rpix < rmin) rmin = rpix;
+if (gpix > gmax) gmax = gpix; if (gpix < gmin) gmin = gpix;
+if (bpix > bmax) bmax = bpix; if (bpix < bmin) bmin = bpix;
+ }
+ }
+ }
+
+ /*
+ */
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, scr,
+ sx, sy, dx, dy, dnx, dny);
+
+
+fprintf (stderr, "pmin/pmax = %d/%d r: %d/%d g: %d/%d b: %d/%d\n",
+ pmin, pmax, rmin, rmax, gmin, gmax, bmin, bmax);
+
+ XDestroyImage (scr);
+ /*
+ XtFree (pix);
+ */
+}
+
+
+/*
+* Find highest one bit set.
+* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
+* High order bit is 31 (or 63 in _LP64 kernel).
+*/
+int
+highbit(unsigned long i)
+{
+ register int h = 1;
+ if (i == 0)
+ return (0);
+#ifdef _LP64
+ if (i & 0xffffffff00000000ul) {
+ h += 32; i >>= 32;
+}
+#endif
+ if (i & 0xffff0000) {
+ h += 16; i >>= 16;
+ }
+ if (i & 0xff00) {
+ h += 8; i >>= 8;
+ }
+ if (i & 0xf0) {
+ h += 4; i >>= 4;
+ }
+ if (i & 0xc) {
+ h += 2; i >>= 2;
+ }
+ if (i & 0x2) {
+ h += 1;
+ }
+ return (h);
+}
+
+
+/*
+* Find lowest one bit set.
+* Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
+* Low order bit is 0.
+*/
+int
+lowbit(unsigned long i)
+{
+ register int h = 1;
+
+ if (i == 0)
+ return (0);
+
+#ifdef _LP64
+ if (!(i & 0xffffffff)) {
+ h += 32; i >>= 32;
+ }
+#endif
+ if (!(i & 0xffff)) {
+ h += 16; i >>= 16;
+ }
+ if (!(i & 0xff)) {
+ h += 8; i >>= 8;
+ }
+ if (!(i & 0xf)) {
+ h += 4; i >>= 4;
+ }
+ if (!(i & 0x3)) {
+ h += 2; i >>= 2;
+ }
+ if (!(i & 0x1)) {
+ h += 1;
+ }
+ return (h);
+}
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++)
+ op[i] = ip[xmap[i]];
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+
+ op = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+
+ /* Why are the case statements below necessary, doesn't the
+ * default case do the same thing regardless of what nx is? MJF
+ */
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Discard the temporary mapping.
+ free_mapping (w, &p_mp);
+ */
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+/* gc = XCreateGC (display, w->gterm.root, 0, NULL); */
+ gc = XCreateGC (display, w->gterm.window, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+/* gc = XCreateGC (display, w->gterm.root, 0, NULL); */
+ gc = XCreateGC (display, w->gterm.window, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.type = MotionNotify; /* MF009 */
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle: /* MF022 */
+ gm->rotangle = gm_getfloat (value, type) * (M_PI / (double) 180.0);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ gm->rotIndicator = gm_getint (value, type);
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle: /* MF022 */
+ if (gm_putfloat(((double)180.0/M_PI)*(gm->rotangle),value,type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ if (gm_putint (gm->rotIndicator, value, type) == ERR)
+ return (ERR);
+ break;
+
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip, *pp;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts != gm->npoints) { /* MF013 */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* If we're defining the vertices of a 'poly' marker update the
+ * pgon[] array with the new set of points. Polygons are initialized
+ * with a unit rectangle and since vertices can't be set as an attribute
+ * the must be set with a setVertices call so we need to update the
+ * structure here.
+ */
+ if (gm->type == Gm_Polygon) { /* MF018 */
+
+ if (gm->pgon) /* MF018 */
+ XtFree ((char *)gm->pgon);
+ gm->pgon = (DPoint *) XtCalloc (first+npts+1, sizeof(DPoint));
+
+ /* Copy the point data to the polygon array. */
+ op = &gm->points[0];
+ pp = &gm->pgon[0];
+ for (i=0; i< gm->npoints; i++, pp++, op++) {
+ pp->x = (double)op->x - gm->x;
+ pp->y = (double)op->y - gm->y;
+ }
+ gm->points[first+npts] = gm->points[0]; /* Close the polygon. */
+
+ gm->npoints = gm->pgon_npts = first + npts + 1;
+ gm->rotangle = 0.0; /* reset rotation angle */
+ gm->flags |= Gm_Modified; /* marker has been modified */
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ /* In the case of a poly object don't return the closing segment. */
+ if (gm->type == Gm_Polygon) /* MF027 */
+ --nout;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else if (strcmp (attribute, GmRotIndicator) == 0) /* MF020 */
+ return (Ga_RotIndicator);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) { /* MF022 */
+ double rot = (gm->rotangle * ((double)180.0 / M_PI));
+ double new_rot = (new_gm->rotangle * ((double)180.0 / M_PI));
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", rot); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_rot); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+
+ /* Convert back to radians.... */
+ new_gm->rotangle *= (M_PI / (double)180.0); /* MF022 */
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ params[i], (XtArgVal)params[i+1], XtRString); /* MF010 */
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+ int ox = x, oy = y;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+
+ /* V1.1 These eqns have the effect of allowing a marker to be grabbed by
+ * any corner but doing so resets the rotation angle the first time the
+ * marker is rotated.
+
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);*/
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ /* V1.1
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ double alpha = atan2 ((double)gm->height, (double)gm->width);
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ /*npts = (gm->npoints - 1) / 4;*/
+ npts = gm->npoints / 4; /* MF028 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+/* gm->npoints = GM_NPTSCIRCLE + 1;*/
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+/* double theta = -(gm->rotangle);*/
+ double theta = (gm->rotangle); /* MF019 */
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+/* theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));*/
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4 + 1; /* MF017 */
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double alpha, beta, rx, ry;
+ double theta = atan2 ((double)(gm->y - y), (double)(x - gm->x));/* MF019 */
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x); /* angle btw origin & selected vertex */
+ beta = atan2 (ry, rx); /* angle btw origin & cursor position */
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+ int use_old_method = 0;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+
+ ptop = p + (gm->npoints - 1); /* MF014 */
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (abs(d1 + d2 - seglen) < e_dist) { /* MF028 */
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ break;
+ case Gm_Circle:
+ d1 = sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ if (d1 < gm->width) {
+ if (what) what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+ break;
+ }
+
+ if (use_old_method) {
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ } else {
+ float xp[64], yp[64];
+ int i;
+
+ for (i=0, p=gm->points, ncrossings=0; p <= ptop; p++, i++) {
+ xp[i] = (float) p->x;
+ yp[i] = (float) p->y;
+ }
+ ncrossings = point_in_poly (gm->npoints, xp, yp, (float)x, (float)y);
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+point_in_poly (npol, xp, yp, x, y)
+int npol;
+float *xp, *yp, x, y;
+{
+ int i, j, c = 0;
+
+ for (i = 0, j = npol-1; i < npol; j = i++) {
+ if ((((yp[i] <= y) && (y < yp[j])) ||
+ ((yp[j] <= y) && (y < yp[i]))) &&
+ (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
+
+ c = !c;
+ }
+ return c;
+}
+
+
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_rotate_indicator -- Draw a line indicating the rotation angle.
+ */
+static void
+gm_rotate_indicator (gm, function) /* MF020 */
+Marker gm;
+int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!gm->rotIndicator)
+ return ;
+
+ if (function == GXxor) {
+ if (gm->type == Gm_Polygon ||
+ gm->type == Gm_Ellipse ||
+ gm->type == Gm_Box ||
+ gm->type == Gm_Rectangle) {
+ int x, y, x2, y2;
+ double ar, cos_rotangle, sin_rotangle;
+ double alpha = atan2 ((double)gm->height,(double)gm->width);
+
+ cos_rotangle = cos ((double)(-gm->rotangle - alpha));
+ sin_rotangle = sin ((double)(-gm->rotangle - alpha));
+ ar = (double) gm->height / (double) gm->width;
+ x = (int) (ar * (gm->width / 2));
+ y = (int) (ar * (gm->height / 2));
+ x2 = x * cos_rotangle - y * sin_rotangle + gm->x;
+ y2 = x * sin_rotangle + y * cos_rotangle + gm->y;
+
+ XDrawLine (display, window, gc, gm->x, gm->y, x2, y2);
+ }
+ } else {
+ ; /* no-op at present */
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
+
+
+static XImage *cached_ximage = NULL; /* MF004 BEGIN */
+
+/* GetCachedXImage --
+ */
+static XImage *
+GetCachedXImage (w, pixmap, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((cached_ximage != NULL)) {
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ return (cached_ximage);
+ }
+ }
+ return(NULL);
+}
+
+
+/* DestroyCachedXImage --
+ */
+static void
+DestroyCachedXImage ()
+{
+ if (cached_ximage != NULL) {
+ XDestroyImage (cached_ximage);
+ cached_ximage = NULL;
+ }
+}
+
+
+/* NewCachedXImage --
+ */
+static void
+NewCachedXImage (w, xin, pixmap, width, height)
+ GtermWidget w;
+ XImage *xin;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ DestroyCachedXImage();
+ cached_ximage = xin;
+ }
+} /* MF004 END */
+
+
+/*
+ * This routine will search the STATIC colors of w->core.colormap to find an
+ * exact match for the color name. If no match is found, the foreground is
+ * returned.
+ */
+
+static Pixel
+ColorNameToPixel (w, str)
+GtermWidget w;
+String str;
+{
+ int i;
+ XColor color;
+ XColor cmap[SZ_STATIC_CMAP];
+
+ /* Find what colors are available... */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ memset (&cmap[i], 0, sizeof(XColor));
+ cmap[i].pixel = i;
+ }
+
+ XQueryColors(w->gterm.display, w->core.colormap, cmap, SZ_STATIC_CMAP);
+
+ /* ...and find a match */
+ if (XParseColor(w->gterm.display, w->core.colormap, str, &color)) {
+ for (i=0; i<SZ_STATIC_CMAP; i++) {
+ if ((color.red==cmap[i].red) &&
+ (color.green==cmap[i].green) &&
+ (color.blue==cmap[i].blue)) {
+ return i;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+/* Global Colormap routines.
+ */
+static int SetGlobalCmap(w)
+ GtermWidget w;
+{
+ static int init=0;
+
+ if( !init ){
+ strcpy(global_cmapname, XtNcmapName);
+ global_ncolors = 0;
+ global_mincolors = 0;
+ init = 1;
+ }
+ if( !w->gterm.useGlobalCmap ){
+ w->gterm.cmap = (Pixel *)XtCalloc(MAX_SZCMAP, sizeof(Pixel));
+ w->gterm.color = (XColor *)XtCalloc(MAX_SZCMAP, sizeof(XColor));
+ return(0);
+ }
+ else{
+ w->gterm.cmap = global_cmap;
+ w->gterm.color = global_color;
+ return(global_ncolors);
+ }
+}
+
+static int ParseGlobalCmap(w)
+ GtermWidget w;
+{
+ char *s;
+ char *t;
+ char *cmapname;
+ int colors;
+ int usedefault=0;
+
+ /* process a directive such as "default[n:m,name]", where
+ * n = min number of colors that must be allocated or else
+ * use a private map called "name". m is the max colors to
+ * allocate (same as maxColors). Either or both can be omitted
+ */
+ cmapname = w->gterm.cmapName;
+ if( !strncmp (cmapname, "default", 7) ){
+ usedefault = 1;
+ if( (s=strchr(cmapname,'[')) != NULL ){
+ /* skip open bracket */
+ s++;
+ /* get min number of colors */
+ global_mincolors = strtol(s, &t, 10);
+ /* for n:m syntax, get max colors */
+ if( *t == ':' ){
+ s = ++t;
+ colors = strtol(s, &t, 10);
+ if( colors > 0 )
+ w->gterm.maxColors = colors;
+ }
+ /* look for default name */
+ if( *t == ',' ){
+ t++;
+ }
+ s = t;
+ /* this is the new name of the cmap -- but it can't be "default"! */
+ if( (strncmp(s, "default", 7)) && (*s != ']') ){
+ strcpy(global_cmapname, s);
+ /* null out closing bracket */
+ if( (s = strchr(global_cmapname, ']')) != NULL )
+ *s = '\0';
+ }
+ /* now make sure we can grab the min number of colors,
+ or else set up to use a private color map */
+ colors = GetMaxCmapColors(w);
+ if( colors < global_mincolors ){
+ usedefault = 0;
+ w->gterm.haveColormap = 0;
+ strcpy(w->gterm.cmapName, global_cmapname);
+ }
+ else{
+ w->gterm.maxColors = min(w->gterm.maxColors, colors);
+ }
+ }
+ }
+ return(usedefault);
+}
+
+/*
+ *
+ * GetMaxCmapColors -- try to determine how many colors we can alloc in the
+ * default colormap. We do this now in order set maxColors to this number,
+ * to avoid the situation where a larger colormap is used that repeats
+ * the actually-allocated colormap -- very ugly ...
+ *
+ */
+static int GetMaxCmapColors(w)
+ Widget w;
+{
+ register int n;
+ unsigned long plane_masks[1];
+ int req;
+ int first, nelem, maxelem;
+ Pixel cmap[MAX_SZCMAP];
+ Display *dpy;
+ Colormap colormap;
+ Visual *visual;
+ int screen;
+
+ dpy = XtDisplay(w);
+ screen = XDefaultScreen(dpy);
+ visual = XDefaultVisual(dpy, screen);
+ colormap = XDefaultColormap(dpy, screen);
+
+ /* make sure we have the right sort of visual */
+ if( (visual->class != PseudoColor) && (visual->class != GrayScale) )
+ return(0);
+
+ /* get current colormap specs */
+ GtQueryColormap (w, 0, &first, &nelem, &maxelem);
+ /* try to alloc the max size colormap */
+ if ( maxelem > 0) {
+ req = min(MAX_SZCMAP, maxelem);
+ for (n=0; req > 0 && n < maxelem; ){
+ if (XAllocColorCells (dpy, colormap,
+ False, plane_masks, 0, &cmap[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+ }
+ /* just wondering ... don't really need this */
+ XFreeColors (dpy, colormap, cmap, n, 0);
+printf ("GetMaxCmapColors returning = %d\n", n);
+ return(n);
+ }
+ else {
+printf ("GetMaxCmapColors returning = 0\n");
+ return(0);
+ }
+}
+
+static int GetGlobalColors()
+{
+printf ("GetGlobalColors returning = %d\n", global_ncolors);
+ return(global_ncolors);
+}
+
+static void SetGlobalColors(n)
+ int n;
+{
+ global_ncolors = n;
+}
+
+
+
+
+
+
+static char *dbg_wSize (GtermWidget w)
+{
+ static char b[32];
+
+ bzero (b, 32);
+ sprintf (b, "%dx%dx%d", w->core.width, w->core.height, w->core.depth);
+ return (b);
+}
+
+
+static char *dbg_visStr (int class)
+{
+ switch (class) {
+ case StaticGray: return ( "StaticGray" );
+ case StaticColor: return ( "StaticColor" );
+ case GrayScale: return ( "GrayScale" );
+ case PseudoColor: return ( "PseudoColor" );
+ case TrueColor: return ( "TrueColor" );
+ default: return ( "unknown" );
+ }
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG
new file mode 100644
index 00000000..981f0d61
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG
@@ -0,0 +1,11897 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), invalidate_cmap();
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+
+extern double atof();
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map. */
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ /* Get special cursors. */
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+
+ /* Make sure we have all the fonts we need. */
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ set_default_color_index (w);
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+}
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+ XVisualInfo rvinfo, *vinfo = (XVisualInfo *) NULL;
+ Visual *ourVisual = (Visual *) NULL;
+ int i, nvis;
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ /* Create graphics window. We first look for an 8-Bit PseudoColor
+ * visual to use, otherwise we fail. (MJF 8/22/97)
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attrs);
+ */
+ vinfo = XGetVisualInfo (w->gterm.display, 0L, &rvinfo, &nvis);
+ for (i=0; i < nvis; i++)
+ if (vinfo[i].depth == 8 && vinfo[i].class == PseudoColor)
+ ourVisual = vinfo[i].visual;
+ if (ourVisual)
+ XtCreateWindow (gw, InputOutput, ourVisual, *valueMask, attrs);
+ else {
+ fprintf (stderr, "No 8-bit PseudoColor visual found.\n");
+ exit(1);
+ }
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (gw);
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ /* Create new pixmap. */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap. */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap. */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window. */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap. */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size. */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size. */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ }
+
+ /* Mark gterm widget ready for further client input. */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+}
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!XtIsRealized (gw))
+ return;
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+ request_colormap_focus (w);
+ }
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+ restore_colormap_focus (w);
+ }
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++) {
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap)
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+ mx->xoffset = mx->yoffset = 0;
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+*/
+ mx->scale = 0;
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
+
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window. */
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ w->gterm.nrasters++;
+
+ /* Free any previously allocated colormap cells. */
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors - SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ /* Only rasters of depth 8 bits are currently supported. */
+ if (depth && depth != 8)
+ return (ERR);
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, RasterDepth);
+ if (rp->r.pixmap == (Pixmap)NULL)
+ goto ximage;
+ XFillRectangle (w->gterm.display, rp->r.pixmap, w->gterm.clearGC,
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage. */
+ximage:
+ rp->type = ImageRaster;
+
+ /* Get pixel storage. */
+ npix = width * height;
+ if ((data = (uchar *) XtMalloc (npix)) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+ }
+
+ w->gterm.nrasters++;
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = RasterDepth;
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+ int bytes_per_line, i;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+ if (raster == 0 && w->gterm.pixmap) {
+
+ /* ### Someone (Mike?) added this code for some reason, but it
+ * does not appear to be valid. This code already writes to the
+ * backing store (gterm.pixmap) so use_backing_store should not
+ * be required. Also blindly using only the first mapping context
+ * and ignoring any others cannot be correct. There is code
+ * below which executes any mappings defined on the raster.
+ * In general this requires scaling, not a simple XCopyArea.
+ *
+ * DrawContext dx = get_draw_context (w);
+ * register MappingContext mx;
+ * mx = &dx->mapContext[0];
+ */
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ /* ### (cont'd)
+ * if (mx->use_backing_store)
+ * XCopyArea (display, w->gterm.pixmap, mx->pixmap,
+ * w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ */
+
+ XCopyArea (display, w->gterm.pixmap, rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ } else
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map is
+ * dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation woudl also make it easy
+ * to add support later for image depths other than 8 bit. Doing the
+ * conversion to display pixels here is however simpler and more
+ * efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage. */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ? w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + y * bytes_per_line + x;
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; )
+ *op++ = cmap[*ip++];
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store)
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (i);
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ dst, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n;
+ unsigned long plane_masks[1];
+ int req, need;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+ /* See if the colormap already exists. */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it. */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap. */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache. */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+ } else
+ wa = w->gterm.wa;
+
+ if (wa.depth == 1)
+ goto unitary;
+
+ switch (wa.visual->class) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp))
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ Colormap colormap;
+ long timeval, time();
+ int ncolors, shadow;
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow))) {
+
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+unitary:
+ for (i = first; i < first+nelem; i++) {
+ w->gterm.cmap[i] = i;
+ cp = &w->gterm.color[i];
+ cp->pixel = i;
+ cp->red = r[i+first];
+ cp->green = g[i+first];
+ cp->blue = b[i+first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+ break;
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+ register int i;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++)
+ if (first+i < w->gterm.ncolors) {
+ cp = &w->gterm.color[first+i];
+ r[i] = cp->red;
+ g[i] = cp->green;
+ b[i] = cp->blue;
+ } else
+ break;
+
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap. */
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ } else {
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ * is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ /* Load the colormap into the display. */
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+ /* If the colormap we loaded to the display was the display colormap,
+ * restore the original unscaled colors in the gterm descriptor so that
+ * we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0)
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+
+ return (OK);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+ }
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ Mapping sv_mp, p_mp;
+ int status;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return;
+ } else if (!mp->enabled) {
+ return;
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return;
+
+ if (rop & R_RefreshNone)
+ return;
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &rop,
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+ if (w->gterm.haveColormap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+ /* Get custom colormap.
+ */
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+ request_colormap_focus (w);
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++)
+ for (j=0, v = ip->pixel; j < n; j++)
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++)
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap,
+ colors, op - colors);
+
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+}
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Compute the intersection of the modified region of the source raster
+ * with the rectangular region of the source raster affected by the given
+ * mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect. */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap;
+ XRectangle r;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (!sr->type || !dr->type)
+ return (ERR);
+ if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0)
+ return (ERR);
+ if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters)
+ return (ERR);
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XCopyArea (display, w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XCopyArea (display, sr->r.pixmap, dr->r.pixmap, w->gterm.exposeGC,
+ sx, sy, snx, sny, dx, dy);
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display, sr->r.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+
+ } else {
+ /* Source is an ximage. */
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ goto done;
+ }
+
+ /* Get output ximage. */
+ if (dr->type == ImageRaster) {
+ xout = dr->r.ximage;
+ ox = dx; oy = dy;
+ } else {
+ uchar *data = (uchar *) XtMalloc (dnx * dny);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0; oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination. */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin)
+ XDestroyImage (xin);
+ if (delxout)
+ XDestroyImage (xout);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++)
+ op[i] = ip[xmap[i]];
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle:
+ gm->rotangle = gm_getfloat (value, type);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle:
+ if (gm_putfloat (gm->rotangle, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts > gm->npoints) {
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) {
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", gm->rotangle); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_gm->rotangle); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ (XtArgVal)params[i], (XtArgVal)params[i+1], XtRString);
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta = -(gm->rotangle);
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double scale, alpha, beta, rx, ry;
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x);
+ beta = atan2 (ry, rx);
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+ ptop = p + gm->npoints;
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (d1 + d2 - seglen < e_dist) {
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ }
+
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h
new file mode 100644
index 00000000..a8a4cb48
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h
@@ -0,0 +1,306 @@
+#ifndef _Gterm_h
+#define _Gterm_h
+
+/* Parameters:
+(this is not yet updated for xgterm - the rest of this file is)
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel White
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ foreground Foreground Pixel Black
+ height Height Dimension 240
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reverseVideo ReverseVideo Boolean False
+ width Width Dimension 320
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * Resource definitions.
+ */
+#define XtCInt "Int"
+
+#define XtNalphaFont1 "alphaFont1"
+#define XtNalphaFont2 "alphaFont2"
+#define XtNalphaFont3 "alphaFont3"
+#define XtNalphaFont4 "alphaFont4"
+#define XtNalphaFont5 "alphaFont5"
+#define XtNalphaFont6 "alphaFont6"
+#define XtNalphaFont7 "alphaFont7"
+#define XtNalphaFont8 "alphaFont8"
+
+#define XtNdialogFont1 "dialogFont1"
+#define XtNdialogFont2 "dialogFont2"
+#define XtNdialogFont3 "dialogFont3"
+#define XtNdialogFont4 "dialogFont4"
+#define XtNdialogFont5 "dialogFont5"
+#define XtNdialogFont6 "dialogFont6"
+#define XtNdialogFont7 "dialogFont7"
+#define XtNdialogFont8 "dialogFont8"
+
+#define XtNdialogBgColor "dialogBgColor"
+#define XtNdialogFgColor "dialogFgColor"
+#define XtNidleCursorBgColor "idleCursorBgColor"
+#define XtNidleCursorFgColor "idleCursorFgColor"
+#define XtNbusyCursorBgColor "busyCursorBgColor"
+#define XtNbusyCursorFgColor "busyCursorFgColor"
+#define XtNginmodeCursorBgColor "ginmodeCursorBgColor"
+#define XtNginmodeCursorFgColor "ginmodeCursorFgColor"
+#define XtNginmodeBlinkInterval "ginmodeBlinkInterval"
+#define XtNcrosshairCursorColor "crosshairCursorColor"
+
+#define XtNidleCursor "idleCursor"
+#define XtNbusyCursor "busyCursor"
+#define XtNginmodeCursor "ginmodeCursor"
+#define XtNwarpCursor "warpCursor"
+#define XtNraiseWindow "raiseWindow"
+#define XtNdeiconifyWindow "deiconifyWindow"
+#define XtNuseTimers "useTimers"
+
+#define XtNcolor0 "color0"
+#define XtNcolor1 "color1"
+#define XtNcolor2 "color2"
+#define XtNcolor3 "color3"
+#define XtNcolor4 "color4"
+#define XtNcolor5 "color5"
+#define XtNcolor6 "color6"
+#define XtNcolor7 "color7"
+#define XtNcolor8 "color8"
+#define XtNcolor9 "color9"
+
+#define XtNcmapName "cmapName"
+#define XtNuseGlobalCmap "useGlobalCmap"
+#define XtNcmapInitialize "cmapInitialize"
+#define XtNcopyOnResize "copyOnResize"
+#define XtNbasePixel "basePixel"
+#define XtNcmapUpdate "cmapUpdate"
+#define XtNcmapShadow "cmapShadow"
+#define XtNcmapInterpolate "cmapInterpolate"
+#define XtNmaxRasters "maxRasters"
+#define XtNcacheRasters "cacheRasters"
+#define XtNmaxMappings "maxMappings"
+#define XtNmaxColors "maxColors"
+
+#define XtNmarkerTranslations "markerTranslations"
+#define XtNdefaultMarker "defaultMarker"
+#define XtNnearEdge "nearEdge"
+#define XtNnearVertex "nearVertex"
+#define XtNmarkerLineWidth "markerLineWidth"
+#define XtNmarkerLineStyle "markerLineStyle"
+#define XtNmarkerFill "markerFill"
+#define XtNmarkerFillColor "markerFillColor"
+#define XtNmarkerFillBgColor "markerFillBgColor"
+#define XtNmarkerFillStyle "markerFillStyle"
+#define XtNxorFill "xorFill"
+#define XtNxorFillColor "xorFillColor"
+#define XtNxorFillBgColor "xorFillBgColor"
+#define XtNmarkerHighlightWidth "markerHighlightWidth"
+#define XtNmarkerHighlightColor "markerHighlightColor"
+#define XtNmarkerCursorFgColor "markerCursorFgColor"
+#define XtNmarkerCursorBgColor "markerCursorBgColor"
+#define XtNmarkerLineLineColor "markerLineLineColor"
+#define XtNmarkerLineKnotColor "markerLineKnotColor"
+#define XtNmarkerLineKnotSize "markerLineKnotSize"
+#define XtNmarkerTextLineColor "markerTextLineColor"
+#define XtNmarkerTextColor "markerTextColor"
+#define XtNmarkerTextBgColor "markerTextBgColor"
+#define XtNmarkerTextBorder "markerTextBorder"
+#define XtNmarkerTextFont "markerTextFont"
+#define XtNmarkerTextString "markerTextString"
+#define XtNmarkerRectLineColor "markerRectLineColor"
+#define XtNmarkerRectKnotColor "markerRectKnotColor"
+#define XtNmarkerRectKnotSize "markerRectKnotSize"
+#define XtNmarkerBoxLineColor "markerBoxLineColor"
+#define XtNmarkerBoxKnotColor "markerBoxKnotColor"
+#define XtNmarkerBoxKnotSize "markerBoxKnotSize"
+#define XtNmarkerCircleLineColor "markerCircleLineColor"
+#define XtNmarkerCircleKnotColor "markerCircleKnotColor"
+#define XtNmarkerCircleKnotSize "markerCircleKnotSize"
+#define XtNmarkerEllipseLineColor "markerEllipseLineColor"
+#define XtNmarkerEllipseKnotColor "markerEllipseKnotColor"
+#define XtNmarkerEllipseKnotSize "markerEllipseKnotSize"
+#define XtNmarkerPgonLineColor "markerPgonLineColor"
+#define XtNmarkerPgonKnotColor "markerPgonKnotColor"
+#define XtNmarkerPgonKnotSize "markerPgonKnotSize"
+
+
+/* Deep Frame Definitions */
+#define XtNdialogBgColorStr "dialogBgColorStr"
+#define XtNdialogFgColorStr "dialogFgColorStr"
+#define XtNidleCursorBgColorStr "idleCursorBgColorStr"
+#define XtNidleCursorFgColorStr "idleCursorFgColorStr"
+#define XtNbusyCursorBgColorStr "busyCursorBgColorStr"
+#define XtNbusyCursorFgColorStr "busyCursorFgColorStr"
+#define XtNginmodeCursorBgColorStr "ginmodeCursorBgColorStr"
+#define XtNginmodeCursorFgColorStr "ginmodeCursorFgColorStr"
+#define XtNcrosshairCursorColorStr "crosshairCursorColorStr"
+
+#define XtNcolor0Str "color0Str"
+#define XtNcolor1Str "color1Str"
+#define XtNcolor2Str "color2Str"
+#define XtNcolor3Str "color3Str"
+#define XtNcolor4Str "color4Str"
+#define XtNcolor5Str "color5Str"
+#define XtNcolor6Str "color6Str"
+#define XtNcolor7Str "color7Str"
+#define XtNcolor8Str "color8Str"
+#define XtNcolor9Str "color9Str"
+
+#define XtNmarkerFillColorStr "markerFillColorStr"
+#define XtNmarkerFillBgColorStr "markerFillBgColorStr"
+
+#define XtNmarkerHighlightColorStr "markerHighlightColorStr"
+#define XtNmarkerCursorFgColorStr "markerCursorFgColorStr"
+#define XtNmarkerCursorBgColorStr "markerCursorBgColorStr"
+
+#define XtNmarkerLineLineColorStr "markerLineLineColorStr"
+#define XtNmarkerLineKnotColorStr "markerLineKnotColorStr"
+
+#define XtNmarkerTextLineColorStr "markerTextLineColorStr"
+#define XtNmarkerTextColorStr "markerTextColorStr"
+#define XtNmarkerTextBgColorStr "markerTextBgColorStr"
+
+#define XtNmarkerRectLineColorStr "markerRectLineColorStr"
+#define XtNmarkerRectKnotColorStr "markerRectKnotColorStr"
+
+#define XtNmarkerBoxLineColorStr "markerBoxLineColorStr"
+#define XtNmarkerBoxKnotColorStr "markerBoxKnotColorStr"
+
+#define XtNmarkerCircleLineColorStr "markerCircleLineColorStr"
+#define XtNmarkerCircleKnotColorStr "markerCircleKnotColorStr"
+
+#define XtNmarkerEllipseLineColorStr "markerEllipseLineColorStr"
+#define XtNmarkerEllipseKnotColorStr "markerEllipseKnotColorStr"
+
+#define XtNmarkerPgonLineColorStr "markerPgonLineColorStr"
+#define XtNmarkerPgonKnotColorStr "markerPgonKnotColorStr"
+
+#define XtNmarkerPointLineColorStr "markerPointLineColorStr"
+#define XtNmarkerPointKnotColorStr "markerPointKnotColorStr"
+/* Deep Frame Definitions */
+
+
+
+/*
+ * Gterm widget flags.
+ */
+#define GtSet 1 /* drawing mode */
+#define GtClear 2
+#define GtInvert 3
+
+#define GtOutline 1 /* line styles */
+#define GtPoint 2
+#define GtSolid 3
+#define GtDashed 4
+#define GtDotted 5
+#define GtDashDot 6
+#define GtDash3Dot 7
+
+#define GtNoCursor 0 /* cursor types */
+#define GtGinmodeCursor 1
+#define GtBusyCursor 2
+#define GtIdleCursor 3
+
+#define GtDefault 0 /* raster types */
+#define GtClient 1
+#define GtServer 2
+
+#define GtPixel 0 /* coordinate types */
+#define GtNDC 1
+
+#define GtMap 0 /* mapping direction */
+#define GtUnmap 1
+
+#define GtWindow 0 /* drawable types */
+#define GtWidget 1
+
+#define R_OpcodeMask 0000017 /* rasterop definitions */
+#define R_Transient 0000020
+#define R_RefreshAll 0000040
+#define R_RefreshNone 0000100
+#define R_MFMask 0777000
+
+#define MF_NEAREST 0001000 /* antialiasing functions */
+#define MF_BILINEAR 0002000
+#define MF_AREA 0004000
+#define MF_BLKAVG 0010000
+#define MF_BOXCAR 0020000
+#define MF_LOWPASS 0040000
+#define MF_GAUSSIAN 0100000
+
+#define GmText "text" /* graphics marker types */
+#define GmLine "line"
+#define GmPolyline "polyline"
+#define GmRectangle "rectangle"
+#define GmBox "box"
+#define GmCircle "circle"
+#define GmEllipse "ellipse"
+#define GmPolygon "polygon"
+
+#define Gm_Text 1 /* integer codes for above */
+#define Gm_Line 2
+#define Gm_Polyline 3
+#define Gm_Rectangle 4
+#define Gm_Box 5
+#define Gm_Circle 6
+#define Gm_Ellipse 7
+#define Gm_Polygon 8
+#define Gm_NTypes 8
+
+#define GmType "type" /* marker attributes */
+#define GmActivated "activated"
+#define GmVisible "visible"
+#define GmSensitive "sensitive"
+#define GmAutoRedraw "autoRedraw"
+#define GmTranslations "translations"
+#define GmX "x"
+#define GmY "y"
+#define GmWidth "width"
+#define GmHeight "height"
+#define GmRotangle "rotangle"
+#define GmHighlightColor "highlightColor"
+#define GmLineColor "lineColor"
+#define GmLineWidth "lineWidth"
+#define GmLineStyle "lineStyle"
+#define GmKnotColor "knotColor"
+#define GmKnotSize "knotSize"
+#define GmFill "fill"
+#define GmFillColor "fillColor"
+#define GmFillBgColor "fillBgColor"
+#define GmFillPattern "fillPattern"
+#define GmFillStyle "fillStyle"
+#define GmTextColor "textColor"
+#define GmTextBgColor "textBgColor"
+#define GmTextBorder "textBorder"
+#define GmImageText "imageText"
+#define GmFont "font"
+#define GmRotIndicator "rotIndicator" /* MF020 */
+
+#define GmEvNotify 00001 /* marker callback events */
+#define GmEvMoveResize 00002
+#define GmEvModify 00004
+#define GmEvRedraw 00010
+#define GmEvDestroy 00020
+#define GmEvInput 00040
+#define GmEvFocusIn 00100
+#define GmEvFocusOut 00200
+#define GmEvConstraint 00400
+
+/* Double version of XPoint. */
+struct dPoint {
+ double x;
+ double y;
+};
+typedef struct dPoint DPoint;
+
+typedef struct _GtermRec *GtermWidget;
+typedef struct _GtermClassRec *GtermWidgetClass;
+
+extern WidgetClass gtermWidgetClass;
+
+#endif /* _Gterm_h */
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h b/vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h
new file mode 100644
index 00000000..12d11cd9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h
@@ -0,0 +1,587 @@
+#ifndef _GtermP_h
+#define _GtermP_h
+
+#include "Gterm.h"
+
+/*
+ * GtermP -- Private definitions for the Gterm graphics widget.
+ */
+
+#define DEF_WIDTH 640
+#define DEF_HEIGHT 480
+#define MAX_RASTERS 512
+#define MAX_MAPPINGS 32
+#define SZ_NUMBER 64
+#define SZ_STATIC_CMAP 10 /* bg+fg+NColors */
+#define MAX_SZCMAP 256 /* max size colormap */
+#define DEF_MAXCOLORS 216 /* max dynamic colors */
+#define MAX_WMWIN 32 /* max WM colormaps */
+#define MAX_REGIONS 64 /* setMapping regions */
+#define MAX_AUXTRANS 8 /* auxiliary translations */
+#define DEF_BASEPIXEL 38 /* base of custom colormap */
+#define DEF_CMAPUPDATE 60 /* seconds */
+#define DEF_CMAPSHADOW 10 /* seconds */
+#define DEF_COPYONRESIZE True /* copy pixmap on resize */
+#define DEF_WARPCURSOR False /* enable warp cursor */
+#define DEF_RAISEWINDOW False /* enable raise window */
+#define DEF_DEICONIFYWINDOW False /* enable deiconfify window */
+#define DEF_USETIMERS True /* ok to use timers */
+#define MAX_DRAW 64 /* max mappings for a draw */
+#define MAX_POINTS 4096 /* max points in polyline */
+#define GM_MAXVERTICES 64 /* max GM points w/o malloc */
+#define GM_NPTSCIRCLE 48 /* npoints circle or ellipse */
+#define GM_MAXCALLBACKS 16 /* max GM callbacks */
+#define GM_UPDATE 30 /* marker update interval */
+#define MAXNDC 32767 /* GKI/NDC scale factor */
+#define V_DIST 4 /* Close to vertex, pixels */
+#define E_DIST 1 /* Close to edge, pixels */
+
+
+#define RasterDepth 8
+#define ColormapDepth 8
+#define RGBDepth 24
+
+#define NAlphaFonts 8
+#define NDialogFonts 8
+#define NColors 8
+
+typedef void (*GmVMethod)();
+typedef int (*GmIMethod)();
+#define uchar unsigned char
+#define ushort unsigned short
+
+/* Raster definitions. */
+#define ImageRaster 1
+#define PixmapRaster 2
+
+struct raster {
+ int type;
+ int delete;
+ int width, height;
+ union {
+ Pixmap pixmap;
+ XImage *ximage;
+ } r;
+};
+
+/* Colormap structure. */
+struct colormap {
+ int map;
+ int ncells;
+ struct colormap *next;
+ unsigned short r[MAX_SZCMAP];
+ unsigned short g[MAX_SZCMAP];
+ unsigned short b[MAX_SZCMAP];
+};
+
+/* mapExtent - Range of dst pixels affected by a src pixel. */
+typedef struct {
+ Position lo;
+ Position hi;
+} mapExtent, *MapExtent;
+
+/* Mappings map a source to a destination. A src or dst of zero refers to
+ * the window, a nonzero value is the raster number.
+ */
+struct mapping {
+ int mapping; /* mapping number */
+ int enabled; /* update destination */
+ int defined; /* mapping is defined */
+ int updated; /* internal params ready */
+ int refresh; /* refresh entire dest */
+ int rop; /* rasterop */
+ int src; /* source rect */
+ int st;
+ int sx, sy;
+ int snx, sny;
+ int dst; /* destination rect */
+ int dt;
+ int dx, dy;
+ int dnx, dny;
+ int scaling; /* internal parameters */
+ float xscale, yscale;
+ mapExtent *x_extent, *y_extent;
+ int *x_srcpix, *y_srcpix;
+ float *x_src, *y_src;
+ uchar *mapdata;
+ int datalen;
+ struct mapping *prev; /* previous in stack order */
+ struct mapping *next; /* next in stack order */
+};
+
+#define M_NOSCALING 0
+#define M_ZOOM 1
+#define M_INTZOOM 2
+#define M_DEZOOM 3
+
+/* The drawing context defines what happens when a drawing operation (e.g.
+ * polyline) takes place. In the simplest case (raster=0) one simply draws
+ * into the display window with no transformation or clipping. When a
+ * raster provides the drawing context, the graphics are drawn once for each
+ * active mapping defined on the raster, using the scaling and drawable
+ * defined by the mapping.
+ */
+struct drawContext {
+ int valid;
+ int raster;
+ struct raster *rp;
+ int nmappings;
+ struct mappingContext {
+ int mapping;
+ struct mapping *mp;
+ int scale;
+ float xoffset, xscale;
+ float yoffset, yscale;
+ int use_backing_store;
+ Pixmap pixmap;
+ GC drawGC;
+ int GC_private;
+ } mapContext[MAX_DRAW];
+};
+
+/* Graphics Markers. A marker is an active graphics object displayed on
+ * top of a drawing to mark a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state.
+ */
+
+/* Callback descriptor. */
+struct markerCallback {
+ int events;
+ GmIMethod func;
+ XtPointer client_data;
+};
+
+/* Marker selection. */
+struct markerSelection {
+ int type;
+ int vertex;
+};
+
+/* Main Marker descriptor. */
+struct marker {
+ GtermWidget w; /* backpointer to widget */
+ int type; /* marker type */
+ int flags; /* bitflags */
+ int x, y; /* position */
+ int width, height; /* size */
+ double rotangle; /* orientation */
+ XtTranslations translations; /* marker translations */
+ XRectangle old_rect; /* old bounding box */
+ Region old_region; /* old screen region */
+ XRectangle cur_rect; /* current bounding box */
+ Region cur_region; /* current screen region */
+ Time time; /* time of last marker edit */
+ struct marker *next; /* next marker */
+ struct marker *prev; /* previous marker */
+ struct marker *parent; /* set if copy */
+
+ int lineColor, lineWidth, lineStyle; /* marker attributes */
+ int highlightColor;
+ int knotColor, knotSize;
+ int fill, fillStyle;
+ int fillColor, fillBgColor;
+ Pixmap fillPattern;
+ int imageText, textBorder;
+ int textColor, textBgColor;
+ int rotIndicator; /* MF020 */
+ XFontStruct *font;
+
+ int npoints; /* marker data */
+ XPoint *points;
+ XPoint point_data[GM_MAXVERTICES+1];
+ struct dPoint *pgon;
+ int pgon_npts;
+ char *text;
+
+ GmIMethod select; /* class methods */
+ GmVMethod markpos;
+ GmVMethod redraw;
+ GmVMethod update;
+ GmVMethod addPt;
+ GmVMethod deletePt;
+ GmVMethod movePt;
+ GmVMethod move;
+ GmVMethod resize;
+ GmVMethod rotate;
+
+ int ncallbacks; /* callbacks */
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ XtIntervalId focus_id;
+ int constraints;
+};
+
+/* Graphics marker bitflags. */
+#define Gm_Activated 000001
+#define Gm_Visible 000002
+#define Gm_Sensitive 000004
+#define Gm_AutoRedraw 000010
+#define Gm_PgonInit 000020
+#define Gm_Smooth 000040
+#define Gm_Modified 000100
+#define Gm_BeingDestroyed 000200
+
+/* Attribute value type codes. */
+#define Gt_Bool 1
+#define Gt_Int 2
+#define Gt_DFloatP 3
+#define Gt_Pointer 4
+#define Gt_String 5
+
+/* Attribute name codes. */
+#define Ga_Type 1
+#define Ga_Activated 2
+#define Ga_Visible 3
+#define Ga_Sensitive 4
+#define Ga_AutoRedraw 5
+#define Ga_Translations 6
+#define Ga_X 7
+#define Ga_Y 8
+#define Ga_Width 9
+#define Ga_Height 10
+#define Ga_Rotangle 11
+#define Ga_HighlightColor 12
+#define Ga_LineColor 13
+#define Ga_LineWidth 14
+#define Ga_LineStyle 15
+#define Ga_KnotColor 16
+#define Ga_KnotSize 17
+#define Ga_Fill 18
+#define Ga_FillColor 19
+#define Ga_FillBgColor 20
+#define Ga_FillPattern 21
+#define Ga_FillStyle 22
+#define Ga_TextColor 23
+#define Ga_TextBgColor 24
+#define Ga_TextBorder 25
+#define Ga_ImageText 26
+#define Ga_Font 27
+#define Ga_Text 28
+#define Ga_RotIndicator 29 /* MF020 */
+
+/* Bitflags for selected attributes. */
+#define Gb_X 00001
+#define Gb_Y 00002
+#define Gb_Width 00004
+#define Gb_Height 00010
+#define Gb_Rotangle 00020
+
+/* Codes for marker selection types. */
+#define Ge_Marker 1
+#define Ge_Point 2
+#define Ge_Edge 3
+
+/* Auxiliary translation tables. */
+#define T_replace 0
+#define T_augment 1
+#define T_override 2
+
+typedef struct raster *Raster;
+typedef struct mapping *Mapping;
+typedef struct drawContext *DrawContext;
+typedef struct mappingContext *MappingContext;
+typedef struct marker *Marker;
+typedef struct markerSelection gmSelection;
+typedef struct markerSelection *GmSelection;
+
+
+/* Gterm callbacks. */
+typedef void (*GtCallbackProc)();
+struct gtCallback {
+ GtCallbackProc proc;
+ XtPointer client_data;
+ struct gtCallback *next;
+};
+typedef struct gtCallback GtCallback;
+
+
+/* Main Gterm widget instance descriptor.
+ */
+typedef struct {
+ /* resources */
+ XFontStruct *alphaFont1; /* graphics fonts */
+ XFontStruct *alphaFont2;
+ XFontStruct *alphaFont3;
+ XFontStruct *alphaFont4;
+ XFontStruct *alphaFont5;
+ XFontStruct *alphaFont6;
+ XFontStruct *alphaFont7;
+ XFontStruct *alphaFont8;
+
+ XFontStruct *dialogFont1; /* dialog fonts */
+ XFontStruct *dialogFont2;
+ XFontStruct *dialogFont3;
+ XFontStruct *dialogFont4;
+ XFontStruct *dialogFont5;
+ XFontStruct *dialogFont6;
+ XFontStruct *dialogFont7;
+ XFontStruct *dialogFont8;
+
+ Pixel dialogBgColor; /* default colors */
+ Pixel dialogFgColor;
+ Pixel idleCursorBgColor;
+ Pixel idleCursorFgColor;
+ Pixel busyCursorBgColor;
+ Pixel busyCursorFgColor;
+ Pixel ginmodeCursorBgColor;
+ Pixel ginmodeCursorFgColor;
+ int ginmodeBlinkInterval;
+ XColor ginmodeColors[2];
+ Pixel crosshairCursorColor;
+ String idleCursor;
+ String busyCursor;
+ String ginmodeCursor;
+ Boolean warpCursor;
+ Boolean raiseWindow;
+ Boolean deiconifyWindow;
+ Boolean useTimers;
+
+ Pixel color0;
+ Pixel color1;
+ Pixel color2;
+ Pixel color3;
+ Pixel color4;
+ Pixel color5;
+ Pixel color6;
+ Pixel color7;
+ Pixel color8;
+ Pixel color9;
+
+ String cacheRasters;
+ int maxRasters; /* raster display stuff */
+ int maxMappings;
+ int maxColors;
+
+ /* private state */
+ Display *display;
+ Screen *screen;
+ Window window;
+ Window root;
+
+ int w_depth; /* screen depth and visual */
+ int w_visual_class;
+
+ int raster; /* used for drawing context */
+ int delay; /* wait for display */
+ Pixmap pixmap; /* used to refresh window */
+ Pixmap d_pixmap; /* used to erase dialog area */
+ int d_saved; /* set when d_pixmap filled */
+ GC clearGC; /* clear pixmap */
+ GC exposeGC; /* copy pixmap to window */
+ GC drawGC; /* graphics drawing */
+ GC dialogGC; /* dialog box */
+ GC cursorGC; /* crosshair cursor */
+ int cursor_type; /* type of cursor to display */
+ Cursor cursor; /* current cursor */
+ int full_crosshair; /* crosshair enabled */
+ int preserve_screen; /* cursor preserves screen */
+ int preserve_valid; /* saved data is valid */
+ Cursor idle_cursor; /* application is idle */
+ Cursor busy_cursor; /* application is busy */
+ Cursor ginmode_cursor; /* graphics input mode */
+ Cursor crosshair_cursor; /* graphics input mode */
+ int cursor_drawn; /* crosshair cursor drawn */
+ int cur_x, cur_y; /* crosshair cursor coords */
+ int old_width, old_height; /* size before resize */
+ int save_root; /* root window of saved cur */
+ int save_x, save_y; /* saved cursor location */
+ int last_x, last_y; /* x,y of last event */
+ int interactive; /* set if cursor read */
+ int char_size; /* not used */
+ int data_level; /* draw or erase graphics */
+ int line_style; /* solid or patterned line */
+ int line_width; /* width of line in pixels */
+ int fill_type; /* not used */
+ int color_index; /* current color index */
+ int xres, yres; /* tek logical resolution */
+ int d_xoff, d_yoff; /* dialog area offset */
+ int d_height; /* dialog area height */
+ int optcols, optrows; /* optimum screen size, chars */
+ int alpha_font; /* current alpha font index */
+ int dialog_font; /* current dialog font index */
+
+ int ncolors; /* current cmap size */
+ int haveColormap; /* colormap initialized */
+ Boolean copyOnResize; /* copy old pixmap on resize */
+ int useDefaultCM; /* use default colormap */
+ Pixel base_pixel; /* used for custom colormap */
+ String cmapName; /* private colormap name */
+ Boolean useGlobalCmap; /* use global data struct? */
+ Boolean cmapInitialize; /* forcibly install colormap */
+ Atom cmapAtom; /* atom for cmap property */
+ int cmapShadow; /* update default colormap */
+ Time cmapLastShadow; /* time of last update */
+ Boolean cmapInterpolate; /* interpolate colormap */
+ int cmapUpdate; /* update interval, seconds */
+ Time cmapLastUpdate; /* time of last update */
+
+ Pixel *cmap; /* map color number to pixval */
+ XColor *color; /* RGB color assignments */
+
+ ushort iomap[MAX_SZCMAP]; /* client i/o color map */
+ Pixel cmap_in[MAX_SZCMAP]; /* umap and cmap combined */
+ Pixel cmap_out[MAX_SZCMAP]; /* umap and cmap combined */
+ int cmap_in_valid; /* set when cmap_in computed */
+ int cmap_out_valid; /* set when cmap_out computed */
+ struct colormap *colormaps; /* list of client colormaps */
+ Window wmTop; /* top level window */
+ Window wmWindows[MAX_WMWIN]; /* custom colormap windows */
+ int n_wmWindows; /* number of WM windows */
+ int in_window; /* pointer is in window */
+ XWindowAttributes wa; /* window attributes */
+ int wa_defined; /* set when above is defined */
+
+
+ /* Deep Frame */
+ Visual* visual; /* ptr to non-default visual */
+ int forcePseudo8; /* force use of Pseudo 8 vis */
+ /* Deep Frame */
+
+
+ XFontStruct *alpha_fonts[NAlphaFonts]; /* alpha font index */
+ XFontStruct *dialog_fonts[NDialogFonts];/* dialog font index */
+
+ GtCallback *resetCallback; /* client setGterm callbacks */
+ GtCallback *resizeCallback; /* client resize callback */
+ GtCallback *inputCallback; /* client event input cb */
+
+ Raster rasters; /* raster descriptors */
+ int nrasters; /* number of alloced rasters */
+ Mapping mappings; /* mapping descriptors */
+ int nmappings; /* number of mappings */
+ Mapping mp_head; /* head of mapping list */
+ Mapping mp_tail; /* tail of mapping list */
+ struct drawContext draw; /* drawing context */
+
+ /* Markers */
+ Marker gm_head; /* head of marker list */
+ Marker gm_tail; /* head of marker list */
+ Marker gm_create; /* set if creating marker */
+ Marker gm_active; /* marker that has focus */
+ gmSelection gm_selection; /* active portion of marker */
+ GC gm_drawGC; /* marker drawing GC */
+ GC gm_rubberGC; /* marker rubber-band GC */
+ Cursor gm_markerCursor; /* pointer in marker */
+ Cursor gm_edgeCursor; /* pointer on marker edge */
+ Cursor gm_pointCursor; /* pointer near marker point */
+ int gm_redisplay; /* redisplay needed */
+ int gm_initialized; /* set after init */
+
+ XtTranslations defTranslations; /* gterm translations */
+ XtTranslations auxTrans[MAX_AUXTRANS]; /* auxiliary translations */
+ int auxTType[MAX_AUXTRANS]; /* translation type */
+ int nauxTrans; /* number of auxilary trans */
+ String gm_translations; /* Marker translations */
+ XtTranslations gm_defTranslations; /* default marker trans */
+ Marker gm_curTranslations; /* current translations */
+ Marker gm_reqTranslations; /* requested translations */
+ XtIntervalId gm_timer_id; /* translation request timer */
+
+ String gm_defaultMarker; /* default marker type name */
+ int gm_defaultType; /* default marker type */
+ int gm_nearEdge; /* defines area near edge */
+ int gm_nearVertex; /* defines area near Vertex */
+
+ int gm_lineWidth; /* shared attributes */
+ int gm_lineStyle;
+ Boolean gm_fill;
+ Pixel gm_fillColor;
+ Pixel gm_fillBgColor;
+ int gm_fillStyle;
+ Boolean gm_xorFill; /* fill with GXxor */
+ int gm_xorFillColor; /* xor-fill color */
+ int gm_xorFillBgColor; /* xor-fill background color */
+ int gm_highlightWidth; /* highlight width, pixels */
+ int gm_highlightColor; /* highlight color */
+ Pixel gm_cursorFgColor; /* marker cursors */
+ Pixel gm_cursorBgColor; /* marker cursors */
+
+ Pixel gm_LineLineColor; /* Lines, Polylines */
+ Pixel gm_LineKnotColor;
+ int gm_LineKnotSize;
+ Pixel gm_TextLineColor; /* Text markers */
+ Pixel gm_TextColor;
+ Pixel gm_TextBgColor; /* bkg color, image text */
+ int gm_TextBorder; /* border around text */
+ XFontStruct *gm_TextFont; /* default font */
+ String gm_TextString; /* default text */
+
+ Pixel gm_RectLineColor; /* Rectangle markers */
+ Pixel gm_RectKnotColor;
+ int gm_RectKnotSize;
+ Pixel gm_BoxLineColor; /* Box markers */
+ Pixel gm_BoxKnotColor;
+ int gm_BoxKnotSize;
+ Pixel gm_CircleLineColor; /* Circle markers */
+ Pixel gm_CircleKnotColor;
+ int gm_CircleKnotSize;
+ Pixel gm_EllipseLineColor; /* Ellipse markers */
+ Pixel gm_EllipseKnotColor;
+ int gm_EllipseKnotSize;
+ Pixel gm_PgonLineColor; /* Polygon markers */
+ Pixel gm_PgonKnotColor;
+ int gm_PgonKnotSize;
+
+ /* Deep Frame */
+ String dialogBgColorStr; /* default colors */
+ String dialogFgColorStr;
+ String idleCursorBgColorStr;
+ String idleCursorFgColorStr;
+ String busyCursorBgColorStr;
+ String busyCursorFgColorStr;
+ String ginmodeCursorBgColorStr;
+ String ginmodeCursorFgColorStr;
+ String crosshairCursorColorStr;
+
+ String color0Str;
+ String color1Str;
+ String color2Str;
+ String color3Str;
+ String color4Str;
+ String color5Str;
+ String color6Str;
+ String color7Str;
+ String color8Str;
+ String color9Str;
+
+ String gm_highlightColorStr; /* highlight color */
+ String gm_fillColorStr;
+ String gm_fillBgColorStr;
+ String gm_cursorFgColorStr; /* marker cursors */
+ String gm_cursorBgColorStr;
+ String gm_LineLineColorStr; /* Lines, Polylines */
+ String gm_LineKnotColorStr;
+ String gm_TextLineColorStr; /* Text markers */
+ String gm_TextColorStr;
+ String gm_TextBgColorStr; /* bkg color, image text */
+ String gm_RectLineColorStr; /* Rectangle markers */
+ String gm_RectKnotColorStr;
+ String gm_BoxLineColorStr; /* box */
+ String gm_BoxKnotColorStr;
+ String gm_CircleLineColorStr; /* Circle markers */
+ String gm_CircleKnotColorStr;
+ String gm_EllipseLineColorStr; /* Ellipse markers */
+ String gm_EllipseKnotColorStr;
+ String gm_PgonLineColorStr; /* Polygon markers */
+ String gm_PgonKnotColorStr;
+ String gm_PointLineColorStr; /* Point markers */
+ String gm_PointKnotColorStr;
+ /* Deep Frame */
+
+} GtermPart;
+
+typedef struct _GtermRec {
+ CorePart core;
+ GtermPart gterm;
+} GtermRec;
+
+typedef struct {int dummy;} GtermClassPart;
+
+typedef struct _GtermClassRec {
+ CoreClassPart core_class;
+ GtermClassPart gterm_class;
+} GtermClassRec;
+
+extern GtermClassRec gtermClassRec;
+
+#endif /* _GtermP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.c b/vendor/x11iraf/obm/ObmW/Gterm.c
new file mode 100644
index 00000000..39118af9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.c
@@ -0,0 +1,1944 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+
+#define DBG_TRACE 0
+#define DBG_CMAPS 0
+#define DBG_IOMAP 0
+#define DBG_VERBOSE 0
+#define DBG_CM_VERB 0
+
+
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+#define CacheXImage False /* MF004 */
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.dialogBgColorStr),
+ XtRImmediate,"yellow"},
+ {XtNdialogFgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.dialogFgColorStr),
+ XtRImmediate,"black"},
+ {XtNidleCursorBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursorBgColorStr),
+ XtRImmediate,"white"},
+ {XtNidleCursorFgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursorFgColorStr),
+ XtRImmediate,"black"},
+ {XtNbusyCursorBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursorBgColorStr),
+ XtRImmediate,"white"},
+ {XtNbusyCursorFgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursorFgColorStr),
+ XtRImmediate,"black"},
+ {XtNginmodeCursorBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColorStr),
+ XtRImmediate,"black"},
+ {XtNginmodeCursorFgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColorStr),
+ XtRImmediate,"white"},
+ {XtNcrosshairCursorColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.crosshairCursorColorStr),
+ XtRImmediate,"red"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color0Str), XtRImmediate,
+ (caddr_t)"black"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color1Str), XtRImmediate,
+ (caddr_t)"white"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color2Str), XtRImmediate,
+ (caddr_t)"red"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color3Str), XtRImmediate,
+ (caddr_t)"green"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color4Str), XtRImmediate,
+ (caddr_t)"blue"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color5Str), XtRImmediate,
+ (caddr_t)"cyan"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color6Str), XtRImmediate,
+ (caddr_t)"yellow"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color7Str), XtRImmediate,
+ (caddr_t)"magenta"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color8Str), XtRImmediate,
+ (caddr_t)"purple"},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.color9Str), XtRImmediate,
+ (caddr_t)"darkslategray"},
+
+ {XtNmarkerFillColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_fillColorStr),
+ XtRImmediate,"DarkSlateGray"},
+ {XtNmarkerFillBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_fillBgColorStr), XtRImmediate,"black"},
+
+ {XtNmarkerHighlightColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_highlightColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerCursorFgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColorStr),
+ XtRImmediate,"yellow"},
+ {XtNmarkerCursorBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColorStr),
+ XtRImmediate,"black"},
+
+ {XtNmarkerLineLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_LineLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerLineKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColorStr),
+ XtRImmediate,"blue"},
+
+ {XtNmarkerTextLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerTextColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextColorStr), XtRImmediate,"yellow"},
+ {XtNmarkerTextBgColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextBgColorStr),
+ XtRImmediate,"DarkSlateGray"},
+
+ {XtNmarkerRectLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_RectLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerRectKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColorStr),
+ XtRImmediate,"blue"},
+
+ {XtNmarkerBoxLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerBoxKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColorStr), XtRImmediate,"blue"},
+
+ {XtNmarkerCircleLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerCircleKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColorStr),
+ XtRImmediate,"blue"},
+
+ {XtNmarkerEllipseLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerEllipseKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColorStr),
+ XtRImmediate,"blue"},
+
+ {XtNmarkerPgonLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerPgonKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColorStr),
+ XtRImmediate,"blue"},
+
+ {XtNmarkerPointLineColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_PointLineColorStr),
+ XtRImmediate,"green"},
+ {XtNmarkerPointKnotColorStr, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_PointKnotColorStr),
+ XtRImmediate,"blue"},
+
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNuseGlobalCmap, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useGlobalCmap), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+struct {
+ unsigned short index;
+ unsigned short r, g, b;
+ unsigned long value;
+ char *name;
+} static_colors[] = {
+ { 0, 0, 0, 0, 0x000000, "black" },/* static colors */
+ { 1, 255, 255, 255, 0xffffff, "white" },
+ { 2, 255, 0, 0, 0xff0000, "red" },
+ { 3, 0, 255, 0, 0x00ff00, "green" },
+ { 4, 0, 0, 255, 0x0000ff, "blue" },
+ { 5, 0, 255, 255, 0x00ffff, "cyan" },
+ { 6, 255, 255, 0, 0xffff00, "yellow" },
+ { 7, 255, 0, 255, 0xff00ff, "magenta" },
+ { 8, 155, 48, 255, 0xa020f0, "purple" },
+ { 9, 151, 255, 255, 0x2f4f4f, "darkslategray" },
+
+ { 202, 0, 0, 0, 0x000000, "black" },/* overlay colors */
+ { 203, 255, 255, 255, 0xffffff, "white" },
+ { 204, 255, 0, 0, 0xff0000, "red" },
+ { 205, 0, 255, 0, 0x00ff00, "green" },
+ { 206, 0, 0, 255, 0x0000ff, "blue" },
+ { 207, 255, 255, 0, 0xffff00, "yellow" },
+ { 208, 0, 255, 255, 0x00ffff, "cyan" },
+ { 209, 255, 0, 255, 0xff00ff, "magenta" },
+ { 210, 255, 127, 80, 0xff7f50, "coral" },
+ { 211, 176, 48, 96, 0xb03060, "maroon" },
+ { 212, 255, 165, 0, 0xffa500, "orange" },
+ { 213, 240, 183, 107, 0xf0e68c, "khaki" },
+ { 214, 218, 112, 214, 0xda70d6, "orchid" },
+ { 215, 64, 224, 208, 0x40e0d0, "turquoise" },
+ { 216, 238, 130, 238, 0xee82ee, "violet" },
+ { 217, 245, 222, 179, 0xf5deb3, "wheat" },
+ { 218, 0, 0, 0, 0x000000, "dummy" },
+};
+static int num_static_colors = 27;
+
+static int colormap_focus = 512;
+
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), init_global_cmap(), invalidate_cmap();
+static void initColorResources ();
+static void gm_rotate_indicator(); /* MF020 */
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+static Pixel ColorNameToPixel ();
+
+
+/* Global Colormap declarations.
+ */
+#define CMAPNAME_SIZE 160
+
+static char global_cmapname[CMAPNAME_SIZE];
+static Pixel global_cmap[MAX_SZCMAP];
+static XColor global_color[MAX_SZCMAP];
+static unsigned long global_lut[MAX_SZCMAP];
+static int global_ncolors = 0;
+static int global_nstatic = SZ_STATIC_CMAP;
+static int global_noverlay = SZ_OVERLAY_CMAP;
+static int global_mincolors = 0;
+static int valid_lut = 0;
+
+static int SetGlobalCmap();
+static int ParseGlobalCmap();
+static int GetMaxCmapColors();
+static int GetGlobalColors();
+static void SetGlobalColors();
+
+
+static void NewCachedXImage(); /* MF004 */
+static void DestroyCachedXImage(); /* MF004 */
+static XImage *GetCachedXImage(); /* MF004 */
+
+
+static char *dbg_wSize(); /* debug utils */
+static char *dbg_visStr();
+
+extern double atof();
+
+
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ XVisualInfo info; /* Deep Frame */
+ XStandardColormap std, *stdcmaps;
+ int nstdcmaps;
+ XColor colors[MAX_SZCMAP+1];
+ char property[128], cname[12];
+
+
+ for (i=0 ; i < MAX_SZCMAP; i++)
+ memset (&colors[i], 0, sizeof(XColor)); /* Deep Frame */
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ w->gterm.w_depth = DefaultDepth (display, DefaultScreen(display));
+ w->gterm.w_visual_class =
+ DefaultVisual (display, DefaultScreen(display))->class;
+
+
+ /* Deep Frame */
+
+ /* Check if default visual is Pseudo color 8. If so, continue, else
+ * force a Pseudo 8 visual and new StandardColorMap.
+ */
+ if (XMatchVisualInfo (display, DefaultScreen(display), 8, PseudoColor,
+ &info) && info.visual == DefaultVisualOfScreen(screen)) {
+
+ /* reset some gterm and core values to reflect the new visual */
+ w->core.depth = info.depth;
+ w->gterm.visual = info.visual;
+ w->gterm.forcePseudo8 = True;
+
+ /* Find the Standard Color Map */
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Gterm.initialize(Pseudo8): cmapName = '%s'\n",
+ w->gterm.cmapName);
+
+ /* calculate cmap name */
+ /* if default, try to extract name from 'default[n:m,name]' */
+
+ if (!strncmp(w->gterm.cmapName,"default",7)) {
+ char *p;
+
+ if (p=strstr(w->gterm.cmapName,"[")) {
+ if (p=strstr(p,",")) {
+ strcpy(global_cmapname,++p);
+ if (p=strstr(global_cmapname,"]")) {
+ *p='\0'; /* cut off the last ']' */
+ strcpy(w->gterm.cmapName,global_cmapname);
+ }
+ }
+ }
+ }
+
+ /* if that didn't work, give it a name
+ */
+ if (!strncmp(w->gterm.cmapName,"default",7))
+ strcpy(w->gterm.cmapName,"ForcePseudo");
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Gterm.initialize 2(Pseudo8): cmapName = '%s'\n",
+ w->gterm.cmapName);
+
+ /* create atom */
+ sprintf(property, "GT_%s", w->gterm.cmapName);
+ w->gterm.cmapAtom = XInternAtom (display, property, False);
+
+
+ w->core.colormap = 0;
+ if (XGetRGBColormaps (display, w->gterm.root, &stdcmaps, &nstdcmaps,
+ w->gterm.cmapAtom)) {
+ if (stdcmaps[0].colormap && stdcmaps[0].visualid==info.visualid) {
+ w->core.colormap = stdcmaps[0].colormap;
+ w->gterm.base_pixel = stdcmaps[0].base_pixel;
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "Gterm.intialize(Pseudo8): colormap = 0x%x base=%d\n",
+ w->core.colormap, w->gterm.base_pixel);
+
+ /* create Standard Color Map */
+ if (!w->core.colormap && info.visual) {
+ w->core.colormap = XCreateColormap (display, w->gterm.root,
+ info.visual, AllocAll);
+
+ /* Set the Static Colors */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ colors[i].pixel = i;
+ XParseColor(display, w->core.colormap,
+ static_colors[i].name, &colors[i]);
+ }
+ XStoreColors (display, w->core.colormap, colors, SZ_STATIC_CMAP);
+
+ /* save Standard Color Map */
+ std.colormap = w->core.colormap;
+ std.red_max = 1;
+ std.red_mult = 0;
+ std.green_max = std.green_mult = 0;
+ std.blue_max = std.blue_mult = 0;
+ std.base_pixel = w->gterm.base_pixel;
+ std.visualid = info.visualid;
+ std.killid = 0;
+ XSetRGBColormaps (display, w->gterm.root, &std, 1,
+ w->gterm.cmapAtom);
+ XSetCloseDownMode (display, RetainPermanent);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "Gterm.initialize(Pseudo8): defDepth=%d cmap=0x%x\n",
+ w->gterm.w_depth, w->core.colormap);
+
+ /* Let gterm know what we have done.
+ */
+ /* will be reset later on, but put here for clarity */
+ w->gterm.useDefaultCM = False;
+ w->gterm.useGlobalCmap = False;
+ w->gterm.haveColormap = True;
+ w->gterm.cmapInitialize = False;
+
+ } else {
+ XVisualInfo *vp, template;
+ int i, j, k, nvis;
+ unsigned short val;
+ float scale;
+
+
+ memset (&template, 0, sizeof (template));
+ template.class = TrueColor;
+
+ vp = XGetVisualInfo (display, VisualClassMask, &template, &nvis);
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "NO 8-bit PSEUDO FOUND.....USING TRUECOLOR\n");
+ fprintf (stderr, "nvis=%d defDepth=%d cmap=0x%x\n",
+ nvis, w->gterm.w_depth, w->core.colormap);
+ }
+
+ /* Let gterm know what we have done.
+ */
+ w->gterm.visual = vp->visual;
+ w->gterm.useDefaultCM = True;
+ w->gterm.useGlobalCmap = True;
+ w->gterm.haveColormap = True;
+ w->gterm.forcePseudo8 = False;
+ w->gterm.cmapInitialize = False;
+ w->gterm.ncolors = 200;
+ w->gterm.base_pixel = 0;
+ w->gterm.cmapName = "default";
+
+ /* Create a standard colormap of the static pixels.
+ */
+ w->gterm.color0 = ColorNameToPixel (w, w->gterm.color0Str);
+ w->gterm.color1 = ColorNameToPixel (w, w->gterm.color1Str);
+ w->gterm.color2 = ColorNameToPixel (w, w->gterm.color2Str);
+ w->gterm.color3 = ColorNameToPixel (w, w->gterm.color3Str);
+ w->gterm.color4 = ColorNameToPixel (w, w->gterm.color4Str);
+ w->gterm.color5 = ColorNameToPixel (w, w->gterm.color5Str);
+ w->gterm.color6 = ColorNameToPixel (w, w->gterm.color6Str);
+ w->gterm.color7 = ColorNameToPixel (w, w->gterm.color7Str);
+ w->gterm.color8 = ColorNameToPixel (w, w->gterm.color8Str);
+ w->gterm.color9 = ColorNameToPixel (w, w->gterm.color9Str);
+
+
+ /* Set the Static part of the colormap.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ global_cmap[i] = i;
+ colors[i].pixel = i;
+ colors[i].flags = (DoRed | DoGreen | DoBlue);
+ }
+
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ colors[i].pixel = global_color[i].pixel = static_colors[i].index;
+ colors[i].red = global_color[i].red = static_colors[i].r << 8;
+ colors[i].green = global_color[i].green = static_colors[i].g << 8;
+ colors[i].blue = global_color[i].blue = static_colors[i].b << 8;
+ }
+
+ /* Set the Dynamic part of the colormap. Here we scale the 255 levels
+ ** to the 200 levels we gets from the client.
+ */
+ scale = 255. / 200.;
+ for (i=0; i < SZ_DYNAMIC_CMAP; i++) {
+ j = SZ_STATIC_CMAP + i;
+ k = i + 1;
+ val = ((unsigned short) ((i * scale) + 0.5)) << 8;
+
+ colors[j].pixel = global_color[j].pixel = j;
+ colors[j].red = global_color[j].red = val;
+ colors[j].green = global_color[j].green = val;
+ colors[j].blue = global_color[j].blue = val;
+ }
+
+ /* Set the overlay colors in the colormap. These indices are what's
+ ** defined in the graphcap file and can be extended as needed.
+ */
+ for (i=0; i < SZ_OVERLAY_CMAP; i++) {
+ j = SZ_STATIC_CMAP + i;
+ k = static_colors[j].index + SZ_STATIC_CMAP;
+
+ colors[k].pixel = global_color[k].pixel = k;
+ colors[k].red = global_color[k].red = static_colors[j].r << 8;
+ colors[k].green = global_color[k].green = static_colors[j].g << 8;
+ colors[k].blue = global_color[k].blue = static_colors[j].b << 8;
+ }
+
+
+ /* Set the Static Colors. FIXME ******
+ if ((w->core.colormap = XCreateColormap (display, w->gterm.root,
+ vp->visual, AllocNone))) {
+
+ for (i=0; i < MAX_SZCMAP; i++) {
+ sprintf (cname,"#%02x%02x%02x",
+ global_color[i].red,
+ global_color[i].green,
+ global_color[i].blue);
+ if (!XParseColor( display, w->core.colormap, cname, &colors[i]))
+ continue;
+ colors[i].pixel = i;
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+ XStoreColors (display, w->core.colormap, colors, MAX_SZCMAP);
+ XSetWindowColormap (display, w->gterm.root, w->core.colormap );
+ }
+ */
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "Gterm.initialize (TrueColor): after colormap, cmap=0x%x\n",
+ w->core.colormap);
+ }
+ /* Deep Frame */
+
+
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map.
+ */
+ if (w->gterm.useGlobalCmap) {
+ w->gterm.cmap = (Pixel *) global_cmap;
+ w->gterm.color = (XColor *) global_color;
+ w->gterm.ncolors = SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP;
+ for (i=0; i < MAX_SZCMAP; i++)
+ w->gterm.cmap_in[i] = w->gterm.cmap_out[i] = w->gterm.iomap[i] = i;
+
+ } else {
+ pp = &w->gterm.color0;
+ w->gterm.cmap = (Pixel *) XtCalloc (MAX_SZCMAP, sizeof(Pixel));
+ w->gterm.color = (XColor *)XtCalloc (MAX_SZCMAP, sizeof(XColor));
+
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ w->gterm.color[i].red = 0;
+ w->gterm.color[i].green = 0;
+ w->gterm.color[i].blue = 0;
+ }
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors(display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+
+ init_iomap (w);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Gterm.intialize: cmap initialized\n");
+
+
+ /* if we have not yet allocated any colors ... The SetGlobalCmap()
+ ** function returns zero when useGlobalCmap is disabled, but it also
+ ** allocates the gterm.cmap and gterm.color pointers in this case.
+ */
+ if (! w->gterm.useGlobalCmap) {
+ if (SetGlobalCmap(w) == 0 && !w->gterm.useGlobalCmap) {
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color,
+ SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ } else {
+ /* in the case of a default colormap, we might already have color
+ * cells.
+ */
+ w->gterm.ncolors = GetGlobalColors ();
+ }
+ w->gterm.useDefaultCM = ParseGlobalCmap (w);
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+
+ } else
+ i = GetGlobalColors ();
+
+
+ /* Now fix up some color resources.
+ */
+ initColorResources (w);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "Gterm.intialize: ncolors=%d useDefaultCM=%d core.colormap=0x%x\n",
+ w->gterm.ncolors, w->gterm.useDefaultCM, w->core.colormap);
+
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+ w->gterm.n_wmWindows = 0; /* MF012 */
+
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ if (w->gterm.useGlobalCmap) {
+ XSetBackground (display, gc, static_colors[0].value);
+ XSetForeground (display, gc, static_colors[0].value);
+ } else {
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ }
+ w->gterm.clearGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ if (w->gterm.useGlobalCmap) {
+ XSetBackground (display, gc, static_colors[0].value);
+ XSetForeground (display, gc, static_colors[1].value);
+ } else {
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ }
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+
+ /* Get special cursors. */
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+ /* MF030 */
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+ /* MF030 */
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color); /* MF030 */
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+
+
+ /* Make sure we have all the fonts we need. */
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+
+ /* Deep Frame
+ set_default_color_index (w);
+ Deep Frame */
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+
+ if (DBG_TRACE) {
+ if (DBG_CM_VERB)
+ dbg_printCmaps(w);
+ fprintf (stderr, "Initialize[%s] RETURNING\n\n", dbg_wSize(w));
+ }
+}
+
+
+static void
+initColorResources (w)
+ GtermWidget w;
+{
+ w->gterm.color0 = ColorNameToPixel (w, w->gterm.color0Str);
+ w->gterm.color1 = ColorNameToPixel (w, w->gterm.color1Str);
+ w->gterm.color2 = ColorNameToPixel (w, w->gterm.color2Str);
+ w->gterm.color3 = ColorNameToPixel (w, w->gterm.color3Str);
+ w->gterm.color4 = ColorNameToPixel (w, w->gterm.color4Str);
+ w->gterm.color5 = ColorNameToPixel (w, w->gterm.color5Str);
+ w->gterm.color6 = ColorNameToPixel (w, w->gterm.color6Str);
+ w->gterm.color7 = ColorNameToPixel (w, w->gterm.color7Str);
+ w->gterm.color8 = ColorNameToPixel (w, w->gterm.color8Str);
+ w->gterm.color9 = ColorNameToPixel (w, w->gterm.color9Str);
+
+ w->gterm.dialogBgColor =
+ ColorNameToPixel (w, w->gterm.dialogBgColorStr);
+ w->gterm.dialogFgColor =
+ ColorNameToPixel (w, w->gterm.dialogFgColorStr);
+
+ w->gterm.idleCursorBgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorBgColorStr);
+ w->gterm.idleCursorFgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorFgColorStr);
+
+ w->gterm.busyCursorBgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorBgColorStr);
+ w->gterm.busyCursorFgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorFgColorStr);
+
+ w->gterm.ginmodeCursorBgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorBgColorStr);
+ w->gterm.ginmodeCursorFgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorFgColorStr);
+ w->gterm.crosshairCursorColor =
+ ColorNameToPixel (w, w->gterm.crosshairCursorColorStr);
+
+ w->gterm.gm_fillColor =
+ ColorNameToPixel (w, w->gterm.gm_fillColorStr);
+ w->gterm.gm_fillBgColor =
+ ColorNameToPixel (w, w->gterm.gm_fillBgColorStr);
+
+ w->gterm.gm_highlightColor =
+ ColorNameToPixel (w, w->gterm.gm_highlightColorStr);
+
+ w->gterm.gm_cursorFgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorFgColorStr);
+ w->gterm.gm_cursorBgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorBgColorStr);
+
+ w->gterm.gm_LineLineColor =
+ ColorNameToPixel (w, w->gterm.gm_LineLineColorStr);
+ w->gterm.gm_LineKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_LineKnotColorStr);
+
+ w->gterm.gm_TextLineColor =
+ ColorNameToPixel (w, w->gterm.gm_TextLineColorStr);
+ w->gterm.gm_TextColor =
+ ColorNameToPixel (w, w->gterm.gm_TextColorStr);
+ w->gterm.gm_TextBgColor =
+ ColorNameToPixel (w, w->gterm.gm_TextBgColorStr);
+
+ w->gterm.gm_RectLineColor =
+ ColorNameToPixel (w, w->gterm.gm_RectLineColorStr);
+ w->gterm.gm_RectKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_RectKnotColorStr);
+
+ w->gterm.gm_BoxLineColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxLineColorStr);
+ w->gterm.gm_BoxKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxKnotColorStr);
+
+ w->gterm.gm_CircleLineColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleLineColorStr);
+ w->gterm.gm_CircleKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleKnotColorStr);
+
+ w->gterm.gm_EllipseLineColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseLineColorStr);
+ w->gterm.gm_EllipseKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseKnotColorStr);
+
+ w->gterm.gm_PgonLineColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonLineColorStr);
+ w->gterm.gm_PgonKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonKnotColorStr);
+}
+
+
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+ GC gc;
+ Pixmap pixmap;
+
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Realize[%s] ENTER:\n", dbg_wSize(w));
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ /* Create graphics window. */ /* Deep Frame */
+ if (w->gterm.forcePseudo8) /* force Pseudo 8 visual */
+ XtCreateWindow (gw, InputOutput, w->gterm.visual, *valueMask, attrs);
+
+ else /* Default Visual is Pseudo */
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent, *valueMask,
+ attrs); /* Deep Frame */
+
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+
+ /* Deep Frame */
+ /* Define GC here, so that we have a Drawable at the proper depth */
+
+ /* Get 8-bit pixmap GC.
+ */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, w->core.height, RasterDepth);
+ gc = XCreateGC (w->gterm.display, pixmap, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.color0);
+ w->gterm.clear8GC = gc;
+
+ gc = XCreateGC (w->gterm.display, pixmap, 0, NULL);
+ w->gterm.expose8GC = gc;
+ XFreePixmap (w->gterm.display, pixmap);
+
+
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+/* XSetGraphicsExposures (w->gterm.display, gc, 0);*/ /* MF029 */
+
+ /* Get expose GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ w->gterm.exposeGC = gc;
+/* XSetGraphicsExposures (w->gterm.display, gc, 0);*/ /* MF029 */
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.dialogBgColor);
+ XSetForeground (w->gterm.display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (w->gterm.display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (w->gterm.display, w->gterm.window, 0, NULL);
+ XSetBackground (w->gterm.display, gc, w->gterm.color0);
+ XSetForeground (w->gterm.display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (w->gterm.display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Gterm.Realize: force8=%d core colormap 0x%x\n",
+ w->gterm.forcePseudo8, w->core.colormap);
+
+ set_default_color_index (w);
+ if (w->gterm.forcePseudo8) {
+ XInstallColormap (w->gterm.display, w->core.colormap);
+ request_colormap_focus (w);
+ }
+ /* Deep Frame */
+
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Realize[%s] DONE:\n", dbg_wSize(w));
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Destroy[%s] ENTER:\n", dbg_wSize(w));
+
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (w); /* MF008 */
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.clear8GC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Destroy[%s] DONE:\n", dbg_wSize(w));
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+
+ if (!w || !XtIsRealized(gw))
+ return;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Resize[%s] ENTER:\n", dbg_wSize(w));
+
+
+ /* Create new pixmap.
+ */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap.
+ */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap.
+ */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window.
+ */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font.
+ */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font.
+ */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap.
+ */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size.
+ */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size and depth.
+ */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->depth = w->core.depth;
+
+ if (rp->shadow_pixmap)
+ XFreePixmap (w->gterm.display, rp->shadow_pixmap);
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width+1, w->core.height+1, RasterDepth);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Resize: Raster 0 => %d x %d x %d\n",
+ w->core.width, w->core.height, w->core.depth);
+ }
+
+
+ /* Mark gterm widget ready for further client input.
+ */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Resize[%s] DONE:\n", dbg_wSize(w));
+}
+
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!w || !XtIsRealized (gw))
+ return;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Redisplay[%s]: ENTER\n", dbg_wSize(w));
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "Redisplay[%s] DONE:\n", dbg_wSize(w));
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+ /* Deep Frame */
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap &&
+ !w->gterm.forcePseudo8) {
+
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+ request_colormap_focus (w);
+ }
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+/*printf ("HandleLeaveWindow....");*/
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+/*printf ("restoring focus....");*/
+ restore_colormap_focus (w);
+ }
+/*printf ("\n");*/
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+
+
+#include "GtermCnv.c"
+#include "GtermGraphics.c"
+#include "GtermImaging.c"
+#include "GtermCmap.c"
+#include "GtermMapping.c"
+#include "GtermMarker.c"
+#include "GtermUtil.c"
+#include "GtermDebug.c"
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.c.ORIG b/vendor/x11iraf/obm/ObmW/Gterm.c.ORIG
new file mode 100644
index 00000000..981f0d61
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.c.ORIG
@@ -0,0 +1,11897 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), invalidate_cmap();
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+
+extern double atof();
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map. */
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ /* Get special cursors. */
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+
+ /* Make sure we have all the fonts we need. */
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ set_default_color_index (w);
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+}
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+ XVisualInfo rvinfo, *vinfo = (XVisualInfo *) NULL;
+ Visual *ourVisual = (Visual *) NULL;
+ int i, nvis;
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ /* Create graphics window. We first look for an 8-Bit PseudoColor
+ * visual to use, otherwise we fail. (MJF 8/22/97)
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attrs);
+ */
+ vinfo = XGetVisualInfo (w->gterm.display, 0L, &rvinfo, &nvis);
+ for (i=0; i < nvis; i++)
+ if (vinfo[i].depth == 8 && vinfo[i].class == PseudoColor)
+ ourVisual = vinfo[i].visual;
+ if (ourVisual)
+ XtCreateWindow (gw, InputOutput, ourVisual, *valueMask, attrs);
+ else {
+ fprintf (stderr, "No 8-bit PseudoColor visual found.\n");
+ exit(1);
+ }
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (gw);
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ /* Create new pixmap. */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap. */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap. */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window. */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap. */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size. */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size. */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ }
+
+ /* Mark gterm widget ready for further client input. */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+}
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!XtIsRealized (gw))
+ return;
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+ request_colormap_focus (w);
+ }
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+ restore_colormap_focus (w);
+ }
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++) {
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap)
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+ mx->xoffset = mx->yoffset = 0;
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+*/
+ mx->scale = 0;
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
+
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window. */
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ w->gterm.nrasters++;
+
+ /* Free any previously allocated colormap cells. */
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors - SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ /* Only rasters of depth 8 bits are currently supported. */
+ if (depth && depth != 8)
+ return (ERR);
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, RasterDepth);
+ if (rp->r.pixmap == (Pixmap)NULL)
+ goto ximage;
+ XFillRectangle (w->gterm.display, rp->r.pixmap, w->gterm.clearGC,
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage. */
+ximage:
+ rp->type = ImageRaster;
+
+ /* Get pixel storage. */
+ npix = width * height;
+ if ((data = (uchar *) XtMalloc (npix)) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+ }
+
+ w->gterm.nrasters++;
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = RasterDepth;
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+ int bytes_per_line, i;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+ if (raster == 0 && w->gterm.pixmap) {
+
+ /* ### Someone (Mike?) added this code for some reason, but it
+ * does not appear to be valid. This code already writes to the
+ * backing store (gterm.pixmap) so use_backing_store should not
+ * be required. Also blindly using only the first mapping context
+ * and ignoring any others cannot be correct. There is code
+ * below which executes any mappings defined on the raster.
+ * In general this requires scaling, not a simple XCopyArea.
+ *
+ * DrawContext dx = get_draw_context (w);
+ * register MappingContext mx;
+ * mx = &dx->mapContext[0];
+ */
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ /* ### (cont'd)
+ * if (mx->use_backing_store)
+ * XCopyArea (display, w->gterm.pixmap, mx->pixmap,
+ * w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ */
+
+ XCopyArea (display, w->gterm.pixmap, rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ } else
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map is
+ * dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation woudl also make it easy
+ * to add support later for image depths other than 8 bit. Doing the
+ * conversion to display pixels here is however simpler and more
+ * efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage. */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ? w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + y * bytes_per_line + x;
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; )
+ *op++ = cmap[*ip++];
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store)
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (i);
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ dst, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n;
+ unsigned long plane_masks[1];
+ int req, need;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+ /* See if the colormap already exists. */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it. */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap. */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache. */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+ } else
+ wa = w->gterm.wa;
+
+ if (wa.depth == 1)
+ goto unitary;
+
+ switch (wa.visual->class) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp))
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ Colormap colormap;
+ long timeval, time();
+ int ncolors, shadow;
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow))) {
+
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+unitary:
+ for (i = first; i < first+nelem; i++) {
+ w->gterm.cmap[i] = i;
+ cp = &w->gterm.color[i];
+ cp->pixel = i;
+ cp->red = r[i+first];
+ cp->green = g[i+first];
+ cp->blue = b[i+first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+ break;
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+ register int i;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++)
+ if (first+i < w->gterm.ncolors) {
+ cp = &w->gterm.color[first+i];
+ r[i] = cp->red;
+ g[i] = cp->green;
+ b[i] = cp->blue;
+ } else
+ break;
+
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap. */
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ } else {
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ * is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ /* Load the colormap into the display. */
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+ /* If the colormap we loaded to the display was the display colormap,
+ * restore the original unscaled colors in the gterm descriptor so that
+ * we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0)
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+
+ return (OK);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+ }
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ Mapping sv_mp, p_mp;
+ int status;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return;
+ } else if (!mp->enabled) {
+ return;
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return;
+
+ if (rop & R_RefreshNone)
+ return;
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &rop,
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+ if (w->gterm.haveColormap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+ /* Get custom colormap.
+ */
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+ request_colormap_focus (w);
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++)
+ for (j=0, v = ip->pixel; j < n; j++)
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++)
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap,
+ colors, op - colors);
+
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+}
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Compute the intersection of the modified region of the source raster
+ * with the rectangular region of the source raster affected by the given
+ * mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect. */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap;
+ XRectangle r;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (!sr->type || !dr->type)
+ return (ERR);
+ if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0)
+ return (ERR);
+ if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters)
+ return (ERR);
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XCopyArea (display, w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XCopyArea (display, sr->r.pixmap, dr->r.pixmap, w->gterm.exposeGC,
+ sx, sy, snx, sny, dx, dy);
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display, sr->r.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+
+ } else {
+ /* Source is an ximage. */
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ goto done;
+ }
+
+ /* Get output ximage. */
+ if (dr->type == ImageRaster) {
+ xout = dr->r.ximage;
+ ox = dx; oy = dy;
+ } else {
+ uchar *data = (uchar *) XtMalloc (dnx * dny);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0; oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination. */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin)
+ XDestroyImage (xin);
+ if (delxout)
+ XDestroyImage (xout);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++)
+ op[i] = ip[xmap[i]];
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle:
+ gm->rotangle = gm_getfloat (value, type);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle:
+ if (gm_putfloat (gm->rotangle, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts > gm->npoints) {
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) {
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", gm->rotangle); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_gm->rotangle); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ (XtArgVal)params[i], (XtArgVal)params[i+1], XtRString);
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta = -(gm->rotangle);
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double scale, alpha, beta, rx, ry;
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x);
+ beta = atan2 (ry, rx);
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+ ptop = p + gm->npoints;
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (d1 + d2 - seglen < e_dist) {
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ }
+
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Gterm.h b/vendor/x11iraf/obm/ObmW/Gterm.h
new file mode 100644
index 00000000..a8a4cb48
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm.h
@@ -0,0 +1,306 @@
+#ifndef _Gterm_h
+#define _Gterm_h
+
+/* Parameters:
+(this is not yet updated for xgterm - the rest of this file is)
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel White
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ foreground Foreground Pixel Black
+ height Height Dimension 240
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reverseVideo ReverseVideo Boolean False
+ width Width Dimension 320
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * Resource definitions.
+ */
+#define XtCInt "Int"
+
+#define XtNalphaFont1 "alphaFont1"
+#define XtNalphaFont2 "alphaFont2"
+#define XtNalphaFont3 "alphaFont3"
+#define XtNalphaFont4 "alphaFont4"
+#define XtNalphaFont5 "alphaFont5"
+#define XtNalphaFont6 "alphaFont6"
+#define XtNalphaFont7 "alphaFont7"
+#define XtNalphaFont8 "alphaFont8"
+
+#define XtNdialogFont1 "dialogFont1"
+#define XtNdialogFont2 "dialogFont2"
+#define XtNdialogFont3 "dialogFont3"
+#define XtNdialogFont4 "dialogFont4"
+#define XtNdialogFont5 "dialogFont5"
+#define XtNdialogFont6 "dialogFont6"
+#define XtNdialogFont7 "dialogFont7"
+#define XtNdialogFont8 "dialogFont8"
+
+#define XtNdialogBgColor "dialogBgColor"
+#define XtNdialogFgColor "dialogFgColor"
+#define XtNidleCursorBgColor "idleCursorBgColor"
+#define XtNidleCursorFgColor "idleCursorFgColor"
+#define XtNbusyCursorBgColor "busyCursorBgColor"
+#define XtNbusyCursorFgColor "busyCursorFgColor"
+#define XtNginmodeCursorBgColor "ginmodeCursorBgColor"
+#define XtNginmodeCursorFgColor "ginmodeCursorFgColor"
+#define XtNginmodeBlinkInterval "ginmodeBlinkInterval"
+#define XtNcrosshairCursorColor "crosshairCursorColor"
+
+#define XtNidleCursor "idleCursor"
+#define XtNbusyCursor "busyCursor"
+#define XtNginmodeCursor "ginmodeCursor"
+#define XtNwarpCursor "warpCursor"
+#define XtNraiseWindow "raiseWindow"
+#define XtNdeiconifyWindow "deiconifyWindow"
+#define XtNuseTimers "useTimers"
+
+#define XtNcolor0 "color0"
+#define XtNcolor1 "color1"
+#define XtNcolor2 "color2"
+#define XtNcolor3 "color3"
+#define XtNcolor4 "color4"
+#define XtNcolor5 "color5"
+#define XtNcolor6 "color6"
+#define XtNcolor7 "color7"
+#define XtNcolor8 "color8"
+#define XtNcolor9 "color9"
+
+#define XtNcmapName "cmapName"
+#define XtNuseGlobalCmap "useGlobalCmap"
+#define XtNcmapInitialize "cmapInitialize"
+#define XtNcopyOnResize "copyOnResize"
+#define XtNbasePixel "basePixel"
+#define XtNcmapUpdate "cmapUpdate"
+#define XtNcmapShadow "cmapShadow"
+#define XtNcmapInterpolate "cmapInterpolate"
+#define XtNmaxRasters "maxRasters"
+#define XtNcacheRasters "cacheRasters"
+#define XtNmaxMappings "maxMappings"
+#define XtNmaxColors "maxColors"
+
+#define XtNmarkerTranslations "markerTranslations"
+#define XtNdefaultMarker "defaultMarker"
+#define XtNnearEdge "nearEdge"
+#define XtNnearVertex "nearVertex"
+#define XtNmarkerLineWidth "markerLineWidth"
+#define XtNmarkerLineStyle "markerLineStyle"
+#define XtNmarkerFill "markerFill"
+#define XtNmarkerFillColor "markerFillColor"
+#define XtNmarkerFillBgColor "markerFillBgColor"
+#define XtNmarkerFillStyle "markerFillStyle"
+#define XtNxorFill "xorFill"
+#define XtNxorFillColor "xorFillColor"
+#define XtNxorFillBgColor "xorFillBgColor"
+#define XtNmarkerHighlightWidth "markerHighlightWidth"
+#define XtNmarkerHighlightColor "markerHighlightColor"
+#define XtNmarkerCursorFgColor "markerCursorFgColor"
+#define XtNmarkerCursorBgColor "markerCursorBgColor"
+#define XtNmarkerLineLineColor "markerLineLineColor"
+#define XtNmarkerLineKnotColor "markerLineKnotColor"
+#define XtNmarkerLineKnotSize "markerLineKnotSize"
+#define XtNmarkerTextLineColor "markerTextLineColor"
+#define XtNmarkerTextColor "markerTextColor"
+#define XtNmarkerTextBgColor "markerTextBgColor"
+#define XtNmarkerTextBorder "markerTextBorder"
+#define XtNmarkerTextFont "markerTextFont"
+#define XtNmarkerTextString "markerTextString"
+#define XtNmarkerRectLineColor "markerRectLineColor"
+#define XtNmarkerRectKnotColor "markerRectKnotColor"
+#define XtNmarkerRectKnotSize "markerRectKnotSize"
+#define XtNmarkerBoxLineColor "markerBoxLineColor"
+#define XtNmarkerBoxKnotColor "markerBoxKnotColor"
+#define XtNmarkerBoxKnotSize "markerBoxKnotSize"
+#define XtNmarkerCircleLineColor "markerCircleLineColor"
+#define XtNmarkerCircleKnotColor "markerCircleKnotColor"
+#define XtNmarkerCircleKnotSize "markerCircleKnotSize"
+#define XtNmarkerEllipseLineColor "markerEllipseLineColor"
+#define XtNmarkerEllipseKnotColor "markerEllipseKnotColor"
+#define XtNmarkerEllipseKnotSize "markerEllipseKnotSize"
+#define XtNmarkerPgonLineColor "markerPgonLineColor"
+#define XtNmarkerPgonKnotColor "markerPgonKnotColor"
+#define XtNmarkerPgonKnotSize "markerPgonKnotSize"
+
+
+/* Deep Frame Definitions */
+#define XtNdialogBgColorStr "dialogBgColorStr"
+#define XtNdialogFgColorStr "dialogFgColorStr"
+#define XtNidleCursorBgColorStr "idleCursorBgColorStr"
+#define XtNidleCursorFgColorStr "idleCursorFgColorStr"
+#define XtNbusyCursorBgColorStr "busyCursorBgColorStr"
+#define XtNbusyCursorFgColorStr "busyCursorFgColorStr"
+#define XtNginmodeCursorBgColorStr "ginmodeCursorBgColorStr"
+#define XtNginmodeCursorFgColorStr "ginmodeCursorFgColorStr"
+#define XtNcrosshairCursorColorStr "crosshairCursorColorStr"
+
+#define XtNcolor0Str "color0Str"
+#define XtNcolor1Str "color1Str"
+#define XtNcolor2Str "color2Str"
+#define XtNcolor3Str "color3Str"
+#define XtNcolor4Str "color4Str"
+#define XtNcolor5Str "color5Str"
+#define XtNcolor6Str "color6Str"
+#define XtNcolor7Str "color7Str"
+#define XtNcolor8Str "color8Str"
+#define XtNcolor9Str "color9Str"
+
+#define XtNmarkerFillColorStr "markerFillColorStr"
+#define XtNmarkerFillBgColorStr "markerFillBgColorStr"
+
+#define XtNmarkerHighlightColorStr "markerHighlightColorStr"
+#define XtNmarkerCursorFgColorStr "markerCursorFgColorStr"
+#define XtNmarkerCursorBgColorStr "markerCursorBgColorStr"
+
+#define XtNmarkerLineLineColorStr "markerLineLineColorStr"
+#define XtNmarkerLineKnotColorStr "markerLineKnotColorStr"
+
+#define XtNmarkerTextLineColorStr "markerTextLineColorStr"
+#define XtNmarkerTextColorStr "markerTextColorStr"
+#define XtNmarkerTextBgColorStr "markerTextBgColorStr"
+
+#define XtNmarkerRectLineColorStr "markerRectLineColorStr"
+#define XtNmarkerRectKnotColorStr "markerRectKnotColorStr"
+
+#define XtNmarkerBoxLineColorStr "markerBoxLineColorStr"
+#define XtNmarkerBoxKnotColorStr "markerBoxKnotColorStr"
+
+#define XtNmarkerCircleLineColorStr "markerCircleLineColorStr"
+#define XtNmarkerCircleKnotColorStr "markerCircleKnotColorStr"
+
+#define XtNmarkerEllipseLineColorStr "markerEllipseLineColorStr"
+#define XtNmarkerEllipseKnotColorStr "markerEllipseKnotColorStr"
+
+#define XtNmarkerPgonLineColorStr "markerPgonLineColorStr"
+#define XtNmarkerPgonKnotColorStr "markerPgonKnotColorStr"
+
+#define XtNmarkerPointLineColorStr "markerPointLineColorStr"
+#define XtNmarkerPointKnotColorStr "markerPointKnotColorStr"
+/* Deep Frame Definitions */
+
+
+
+/*
+ * Gterm widget flags.
+ */
+#define GtSet 1 /* drawing mode */
+#define GtClear 2
+#define GtInvert 3
+
+#define GtOutline 1 /* line styles */
+#define GtPoint 2
+#define GtSolid 3
+#define GtDashed 4
+#define GtDotted 5
+#define GtDashDot 6
+#define GtDash3Dot 7
+
+#define GtNoCursor 0 /* cursor types */
+#define GtGinmodeCursor 1
+#define GtBusyCursor 2
+#define GtIdleCursor 3
+
+#define GtDefault 0 /* raster types */
+#define GtClient 1
+#define GtServer 2
+
+#define GtPixel 0 /* coordinate types */
+#define GtNDC 1
+
+#define GtMap 0 /* mapping direction */
+#define GtUnmap 1
+
+#define GtWindow 0 /* drawable types */
+#define GtWidget 1
+
+#define R_OpcodeMask 0000017 /* rasterop definitions */
+#define R_Transient 0000020
+#define R_RefreshAll 0000040
+#define R_RefreshNone 0000100
+#define R_MFMask 0777000
+
+#define MF_NEAREST 0001000 /* antialiasing functions */
+#define MF_BILINEAR 0002000
+#define MF_AREA 0004000
+#define MF_BLKAVG 0010000
+#define MF_BOXCAR 0020000
+#define MF_LOWPASS 0040000
+#define MF_GAUSSIAN 0100000
+
+#define GmText "text" /* graphics marker types */
+#define GmLine "line"
+#define GmPolyline "polyline"
+#define GmRectangle "rectangle"
+#define GmBox "box"
+#define GmCircle "circle"
+#define GmEllipse "ellipse"
+#define GmPolygon "polygon"
+
+#define Gm_Text 1 /* integer codes for above */
+#define Gm_Line 2
+#define Gm_Polyline 3
+#define Gm_Rectangle 4
+#define Gm_Box 5
+#define Gm_Circle 6
+#define Gm_Ellipse 7
+#define Gm_Polygon 8
+#define Gm_NTypes 8
+
+#define GmType "type" /* marker attributes */
+#define GmActivated "activated"
+#define GmVisible "visible"
+#define GmSensitive "sensitive"
+#define GmAutoRedraw "autoRedraw"
+#define GmTranslations "translations"
+#define GmX "x"
+#define GmY "y"
+#define GmWidth "width"
+#define GmHeight "height"
+#define GmRotangle "rotangle"
+#define GmHighlightColor "highlightColor"
+#define GmLineColor "lineColor"
+#define GmLineWidth "lineWidth"
+#define GmLineStyle "lineStyle"
+#define GmKnotColor "knotColor"
+#define GmKnotSize "knotSize"
+#define GmFill "fill"
+#define GmFillColor "fillColor"
+#define GmFillBgColor "fillBgColor"
+#define GmFillPattern "fillPattern"
+#define GmFillStyle "fillStyle"
+#define GmTextColor "textColor"
+#define GmTextBgColor "textBgColor"
+#define GmTextBorder "textBorder"
+#define GmImageText "imageText"
+#define GmFont "font"
+#define GmRotIndicator "rotIndicator" /* MF020 */
+
+#define GmEvNotify 00001 /* marker callback events */
+#define GmEvMoveResize 00002
+#define GmEvModify 00004
+#define GmEvRedraw 00010
+#define GmEvDestroy 00020
+#define GmEvInput 00040
+#define GmEvFocusIn 00100
+#define GmEvFocusOut 00200
+#define GmEvConstraint 00400
+
+/* Double version of XPoint. */
+struct dPoint {
+ double x;
+ double y;
+};
+typedef struct dPoint DPoint;
+
+typedef struct _GtermRec *GtermWidget;
+typedef struct _GtermClassRec *GtermWidgetClass;
+
+extern WidgetClass gtermWidgetClass;
+
+#endif /* _Gterm_h */
diff --git a/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c
new file mode 100644
index 00000000..a3f9203a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c
@@ -0,0 +1,12188 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+#define CacheXImage 1 /* MF004 */
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), invalidate_cmap();
+static void gm_rotate_indicator(); /* MF020 */
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+
+static void NewCachedXImage(); /* MF004 */
+static void DestroyCachedXImage(); /* MF004 */
+static XImage *GetCachedXImage(); /* MF004 */
+
+extern double atof();
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map. */
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+ w->gterm.n_wmWindows = 0; /* MF012 */
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+ XSetGraphicsExposures (display, gc, 0); /* MF029 */
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ /* Get special cursors. */
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+ /* MF030 */
+
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+ /* MF030 */
+
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color); /* MF030 */
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+
+ /* Make sure we have all the fonts we need. */
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ set_default_color_index (w);
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+}
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attrs);
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (w); /* MF008 */
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ /* Create new pixmap. */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap. */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap. */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window. */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap. */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size. */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size. */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ }
+
+ /* Mark gterm widget ready for further client input. */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+}
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!XtIsRealized (gw))
+ return;
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+/*printf ("HandleEnterWindow....");*/
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+/*printf ("requesting focus....");*/
+ request_colormap_focus (w);
+ }
+/*printf ("\n");*/
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+/*printf ("HandleLeaveWindow....");*/
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+/*printf ("restoring focus....");*/
+ restore_colormap_focus (w);
+ }
+/*printf ("\n");*/
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++ || raster == 0) { /* MF041 */
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ XSync (display, False);
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ if (w->gterm.cursor_type != GtGinmodeCursor) /* MF032 */
+ return;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap)
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ Otherwise the cursor movement keystrokes scale incorrectly and quickly move
+ to (0,0).
+ mx->xoffset = mx->yoffset = mx->scale = 0;
+ [DCT] This doesn't look entirely right as it disables logical coords for
+ the screen. Leave as is until this can be studied more carefully.
+ */
+
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
+
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window. */
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ w->gterm.nrasters++;
+
+ /* Free any previously allocated colormap cells. */
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors - SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ /* Only rasters of depth 8 bits are currently supported. */
+ if (depth && depth != 8)
+ return (ERR);
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, RasterDepth);
+ if (rp->r.pixmap == (Pixmap)NULL)
+ goto ximage;
+ XFillRectangle (w->gterm.display, rp->r.pixmap, w->gterm.clearGC,
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage. */
+ximage:
+ rp->type = ImageRaster;
+
+ /* Get pixel storage. */
+ npix = width * height;
+ if ((data = (uchar *) XtMalloc (npix)) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+ }
+
+ w->gterm.nrasters++;
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = RasterDepth;
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+ int bytes_per_line, i;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+ if (raster == 0 && w->gterm.pixmap) {
+
+ /* ### Someone (Mike?) added this code for some reason, but it
+ * does not appear to be valid. This code already writes to the
+ * backing store (gterm.pixmap) so use_backing_store should not
+ * be required. Also blindly using only the first mapping context
+ * and ignoring any others cannot be correct. There is code
+ * below which executes any mappings defined on the raster.
+ * In general this requires scaling, not a simple XCopyArea.
+ *
+ * DrawContext dx = get_draw_context (w);
+ * register MappingContext mx;
+ * mx = &dx->mapContext[0];
+ */
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ /* ### (cont'd)
+ * if (mx->use_backing_store)
+ * XCopyArea (display, w->gterm.pixmap, mx->pixmap,
+ * w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ */
+
+ XCopyArea (display, w->gterm.pixmap, rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ } else
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map is
+ * dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation woudl also make it easy
+ * to add support later for image depths other than 8 bit. Doing the
+ * conversion to display pixels here is however simpler and more
+ * efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage. */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ? w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + y * bytes_per_line + x;
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; ) {
+ *op++ = cmap[*ip++];
+ }
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store)
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny, /* MF006 */
+ RasterDepth) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (w, i); /* MF005 */
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ dst, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny, /* MF006 */
+ RasterDepth) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n;
+ unsigned long plane_masks[1];
+ int req, need;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+ /* See if the colormap already exists. */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it. */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap. */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ if (nelem >= 0) {
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+ }
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache. */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+ } else
+ wa = w->gterm.wa;
+
+ if (wa.depth == 1)
+ goto unitary;
+
+ switch (wa.visual->class) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp))
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ Colormap colormap;
+ long timeval, time();
+ int ncolors, shadow;
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow * 1000))) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+unitary:
+ for (i = first; i < first+nelem; i++) {
+ w->gterm.cmap[i] = i;
+ cp = &w->gterm.color[i];
+ cp->pixel = i;
+ cp->red = r[i+first];
+ cp->green = g[i+first];
+ cp->blue = b[i+first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+ break;
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+ register int i;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++)
+ if (first+i < w->gterm.ncolors) {
+ cp = &w->gterm.color[first+i];
+ r[i] = cp->red;
+ g[i] = cp->green;
+ b[i] = (ushort)cp->blue;
+ } else
+ break;
+
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap. */
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ } else {
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ * is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ /* Load the colormap into the display. */
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+ /* If the colormap we loaded to the display was the display colormap,
+ * restore the original unscaled colors in the gterm descriptor so that
+ * we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0)
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+
+ return (OK);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+ }
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ struct mapping sv_mp, p_mp; /* MF007 */
+ int status;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ int dummy_rop; /* MF011 */
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return (OK);
+ } else if (!mp->enabled) {
+ return (OK);
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return (OK);
+
+ if (rop & R_RefreshNone)
+ return (OK);
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &dummy_rop, /* MF011 */
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+
+ return (OK);
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+ if (w->gterm.haveColormap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+ /* Get custom colormap.
+ */
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+
+ /* Free the XVisualInfo struct. */
+ if (vi)
+ XFree ((void *)vi); /* MF040 */
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+{ printf ("get_colormap ... requesting focus...\n");
+ request_colormap_focus (w);
+}
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++)
+ for (j=0, v = ip->pixel; j < n; j++)
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++)
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap,
+ colors, op - colors);
+
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+}
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Compute the intersection of the modified region of the source raster
+ * with the rectangular region of the source raster affected by the given
+ * mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect. */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+ Pixmap pixmap; /* MF004 */
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap;
+ XRectangle r;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (!sr->type || !dr->type)
+ return (ERR);
+ if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0)
+ return (ERR);
+ if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters)
+ return (ERR);
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XCopyArea (display, w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XCopyArea (display, sr->r.pixmap, dr->r.pixmap, w->gterm.exposeGC,
+ sx, sy, snx, sny, dx, dy);
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display, sr->r.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ if (CacheXImage) { /* MF004 */
+ pixmap = (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap;
+ xin = GetCachedXImage (w, pixmap, sr->width, sr->height);
+ if (xin == NULL) {
+ xin = XGetImage (display, pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ } else
+ NewCachedXImage (w, xin, pixmap, sr->width, sr->height);
+ }
+ } else { /* MF004 */
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } /* MF004 */
+
+ } else {
+ /* Source is an ximage. */
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ goto done;
+ }
+
+ /* Get output ximage. */
+ if (dr->type == ImageRaster) {
+ xout = dr->r.ximage;
+ ox = dx; oy = dy;
+ } else {
+ uchar *data = (uchar *) XtMalloc (dnx * dny);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0; oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl + sx;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination. */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin)
+ XDestroyImage (xin);
+ if (delxout)
+ XDestroyImage (xout);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++)
+ op[i] = ip[xmap[i]];
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+
+ op = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+
+ /* Why are the case statements below necessary, doesn't the
+ * default case do the same thing regardless of what nx is? MJF
+ */
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Discard the temporary mapping.
+ free_mapping (w, &p_mp);
+ */
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.type = MotionNotify; /* MF009 */
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle: /* MF022 */
+ gm->rotangle = gm_getfloat (value, type) * (M_PI / (double) 180.0);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ gm->rotIndicator = gm_getint (value, type);
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle: /* MF022 */
+ if (gm_putfloat(((double)180.0/M_PI)*(gm->rotangle),value,type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ if (gm_putint (gm->rotIndicator, value, type) == ERR)
+ return (ERR);
+ break;
+
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip, *pp;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts != gm->npoints) { /* MF013 */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* If we're defining the vertices of a 'poly' marker update the
+ * pgon[] array with the new set of points. Polygons are initialized
+ * with a unit rectangle and since vertices can't be set as an attribute
+ * the must be set with a setVertices call so we need to update the
+ * structure here.
+ */
+ if (gm->type == Gm_Polygon) { /* MF018 */
+
+ if (gm->pgon) /* MF018 */
+ XtFree ((char *)gm->pgon);
+ gm->pgon = (DPoint *) XtCalloc (first+npts+1, sizeof(DPoint));
+
+ /* Copy the point data to the polygon array. */
+ op = &gm->points[0];
+ pp = &gm->pgon[0];
+ for (i=0; i< gm->npoints; i++, pp++, op++) {
+ pp->x = (double)op->x - gm->x;
+ pp->y = (double)op->y - gm->y;
+ }
+ gm->points[first+npts] = gm->points[0]; /* Close the polygon. */
+
+ gm->npoints = gm->pgon_npts = first + npts + 1;
+ gm->rotangle = 0.0; /* reset rotation angle */
+ gm->flags |= Gm_Modified; /* marker has been modified */
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ /* In the case of a poly object don't return the closing segment. */
+ if (gm->type == Gm_Polygon) /* MF027 */
+ --nout;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else if (strcmp (attribute, GmRotIndicator) == 0) /* MF020 */
+ return (Ga_RotIndicator);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) { /* MF022 */
+ double rot = (gm->rotangle * ((double)180.0 / M_PI));
+ double new_rot = (new_gm->rotangle * ((double)180.0 / M_PI));
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", rot); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_rot); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+
+ /* Convert back to radians.... */
+ new_gm->rotangle *= (M_PI / (double)180.0); /* MF022 */
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ params[i], (XtArgVal)params[i+1], XtRString); /* MF010 */
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+ int ox = x, oy = y;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+
+ /* V1.1 These eqns have the effect of allowing a marker to be grabbed by
+ * any corner but doing so resets the rotation angle the first time the
+ * marker is rotated.
+
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);*/
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ /* V1.1
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ double alpha = atan2 ((double)gm->height, (double)gm->width);
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ /*npts = (gm->npoints - 1) / 4;*/
+ npts = gm->npoints / 4; /* MF028 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+/* gm->npoints = GM_NPTSCIRCLE + 1;*/
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+/* double theta = -(gm->rotangle);*/
+ double theta = (gm->rotangle); /* MF019 */
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+/* theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));*/
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4 + 1; /* MF017 */
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double alpha, beta, rx, ry;
+ double theta = atan2 ((double)(gm->y - y), (double)(x - gm->x));/* MF019 */
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x); /* angle btw origin & selected vertex */
+ beta = atan2 (ry, rx); /* angle btw origin & cursor position */
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+ int use_old_method = 0;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+
+ ptop = p + (gm->npoints - 1); /* MF014 */
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (abs(d1 + d2 - seglen) < e_dist) { /* MF028 */
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ break;
+ case Gm_Circle:
+ d1 = sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ if (d1 < gm->width) {
+ if (what) what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+ break;
+ }
+
+ if (use_old_method) {
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ } else {
+ float xp[64], yp[64];
+ int i;
+
+ for (i=0, p=gm->points, ncrossings=0; p <= ptop; p++, i++) {
+ xp[i] = (float) p->x;
+ yp[i] = (float) p->y;
+ }
+ ncrossings = point_in_poly (gm->npoints, xp, yp, (float)x, (float)y);
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+point_in_poly (npol, xp, yp, x, y)
+int npol;
+float *xp, *yp, x, y;
+{
+ int i, j, c = 0;
+
+ for (i = 0, j = npol-1; i < npol; j = i++) {
+ if ((((yp[i] <= y) && (y < yp[j])) ||
+ ((yp[j] <= y) && (y < yp[i]))) &&
+ (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
+
+ c = !c;
+ }
+ return c;
+}
+
+
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_rotate_indicator -- Draw a line indicating the rotation angle.
+ */
+static void
+gm_rotate_indicator (gm, function) /* MF020 */
+Marker gm;
+int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!gm->rotIndicator)
+ return ;
+
+ if (function == GXxor) {
+ if (gm->type == Gm_Polygon ||
+ gm->type == Gm_Ellipse ||
+ gm->type == Gm_Box ||
+ gm->type == Gm_Rectangle) {
+ int x, y, x2, y2;
+ double ar, cos_rotangle, sin_rotangle;
+ double alpha = atan2 ((double)gm->height,(double)gm->width);
+
+ cos_rotangle = cos ((double)(-gm->rotangle - alpha));
+ sin_rotangle = sin ((double)(-gm->rotangle - alpha));
+ ar = (double) gm->height / (double) gm->width;
+ x = (int) (ar * (gm->width / 2));
+ y = (int) (ar * (gm->height / 2));
+ x2 = x * cos_rotangle - y * sin_rotangle + gm->x;
+ y2 = x * sin_rotangle + y * cos_rotangle + gm->y;
+
+ XDrawLine (display, window, gc, gm->x, gm->y, x2, y2);
+ }
+ } else {
+ ; /* no-op at present */
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
+
+
+static XImage *cached_ximage = NULL; /* MF004 BEGIN */
+
+/* GetCachedXImage --
+ */
+static XImage *
+GetCachedXImage (w, pixmap, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((cached_ximage != NULL)) {
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ return (cached_ximage);
+ }
+ }
+ return(NULL);
+}
+
+
+/* DestroyCachedXImage --
+ */
+static void
+DestroyCachedXImage ()
+{
+ if (cached_ximage != NULL) {
+ XDestroyImage (cached_ximage);
+ cached_ximage = NULL;
+ }
+}
+
+
+/* NewCachedXImage --
+ */
+static void
+NewCachedXImage (w, xin, pixmap, width, height)
+ GtermWidget w;
+ XImage *xin;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ DestroyCachedXImage();
+ cached_ximage = xin;
+ }
+} /* MF004 END */
+
diff --git a/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG
new file mode 100644
index 00000000..981f0d61
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG
@@ -0,0 +1,11897 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/XawInit.h>
+#include "GtermP.h"
+
+/*
+ * Gterm -- Graphics terminal widget. This widget implements only the
+ * window specific graphics output and graphics window input functions.
+ * Protocol translation (e.g. Tek emulation) and i/o is done elsewhere;
+ * see for example gtermio.c.
+ */
+
+#define DefaultAlphaFont 3
+#define DefaultDialogFont 3
+#define DefaultMarkerTextFont 3
+#define ZOOM_TOL 0.0001
+
+static Dimension defXDim = DEF_WIDTH;
+static Dimension defYDim = DEF_HEIGHT;
+
+/* Default translations for Gterm window. */
+/* Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu) */
+
+static char defaultGtermTranslations[] =
+"\
+ <Btn1Down>: m_create() \n\
+ <Btn2Down>: crosshair(on) \n\
+ <Btn2Motion>: crosshair(on) \n\
+ <Btn2Up>: crosshair(off) \n\
+ <EnterWindow>: enter-window() \n\
+ <LeaveWindow>: leave-window() \n\
+ <KeyPress>: graphics-input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+/* Default translations when pointer is over a marker. */
+static char defaultMarkerTranslations[] =
+"\
+ !Shift <Btn1Motion>: m_rotateResize() \n\
+ <Btn1Motion>: m_moveResize() \n\
+ !Shift <Btn1Down>: m_raise() m_markpos() \n\
+ <Btn1Down>: m_raise() m_markposAdd() \n\
+ <Btn1Up>: m_redraw() m_destroyNull() \n\
+ <Btn2Down>: m_lower() \n\
+ <Key>BackSpace: m_deleteDestroy() \n\
+ <Key>Delete: m_deleteDestroy() \n\
+ <KeyPress>: m_input() \n\
+ <Motion>: track-cursor() \n\
+";
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.width), XtRDimension, (caddr_t)&defXDim},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ XtOffset(Widget,core.height), XtRDimension, (caddr_t)&defYDim},
+
+ {XtNalphaFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont1), XtRString, "nil2"},
+ {XtNalphaFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont2), XtRString, "5x8"},
+ {XtNalphaFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont3), XtRString, "6x10"},
+ {XtNalphaFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont4), XtRString, "7x13"},
+ {XtNalphaFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont5), XtRString, "8x13"},
+ {XtNalphaFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont6), XtRString, "9x15"},
+ {XtNalphaFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont7), XtRString, "9x15"},
+ {XtNalphaFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.alphaFont8), XtRString, "9x15"},
+
+ {XtNdialogFont1, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont1), XtRString, "nil2"},
+ {XtNdialogFont2, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont2), XtRString, "5x8"},
+ {XtNdialogFont3, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont3), XtRString, "6x13"},
+ {XtNdialogFont4, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont4), XtRString, "7x13"},
+ {XtNdialogFont5, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont5), XtRString, "8x13"},
+ {XtNdialogFont6, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont6), XtRString, "9x15"},
+ {XtNdialogFont7, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont7), XtRString, "9x15"},
+ {XtNdialogFont8, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.dialogFont8), XtRString, "9x15"},
+
+ {XtNdialogBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogBgColor), XtRString, "yellow"},
+ {XtNdialogFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.dialogFgColor), XtRString, "black"},
+ {XtNidleCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorBgColor), XtRString, "white"},
+ {XtNidleCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.idleCursorFgColor), XtRString, "black"},
+ {XtNbusyCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorBgColor), XtRString, "white"},
+ {XtNbusyCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.busyCursorFgColor), XtRString, "black"},
+ {XtNginmodeCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorBgColor), XtRString, "black"},
+ {XtNginmodeCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.ginmodeCursorFgColor), XtRString, "white"},
+ {XtNginmodeBlinkInterval, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.ginmodeBlinkInterval), XtRImmediate, 0},
+ {XtNcrosshairCursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.crosshairCursorColor), XtRString, "red"},
+
+ {XtNidleCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.idleCursor), XtRString, "plus"},
+ {XtNbusyCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.busyCursor), XtRString, "watch"},
+ {XtNginmodeCursor, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.ginmodeCursor), XtRString, "full_crosshair"},
+ {XtNwarpCursor, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.warpCursor), XtRImmediate,
+ (caddr_t)DEF_WARPCURSOR},
+ {XtNraiseWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.raiseWindow), XtRImmediate,
+ (caddr_t)DEF_RAISEWINDOW},
+ {XtNdeiconifyWindow, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.deiconifyWindow), XtRImmediate,
+ (caddr_t)DEF_DEICONIFYWINDOW},
+ {XtNuseTimers, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.useTimers), XtRImmediate,
+ (caddr_t)DEF_USETIMERS},
+
+ {XtNcolor0, XtCBackground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color0), XtRString, "black"},
+ {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color1), XtRString, "white"},
+ {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color2), XtRString, "red"},
+ {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color3), XtRString, "green"},
+ {XtNcolor4, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color4), XtRString, "blue"},
+ {XtNcolor5, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color5), XtRString, "cyan"},
+ {XtNcolor6, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color6), XtRString, "yellow"},
+ {XtNcolor7, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color7), XtRString, "magenta"},
+ {XtNcolor8, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color8), XtRString, "purple"},
+ {XtNcolor9, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.color9), XtRString, "darkslategray"},
+
+ {XtNcopyOnResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.copyOnResize), XtRImmediate,
+ (caddr_t)DEF_COPYONRESIZE},
+ {XtNcmapName, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cmapName), XtRImmediate,
+ (caddr_t)"default"},
+ {XtNcmapInitialize, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInitialize), XtRImmediate,
+ (caddr_t)FALSE},
+ {XtNbasePixel, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.base_pixel), XtRImmediate,
+ (caddr_t)DEF_BASEPIXEL},
+ {XtNcmapUpdate, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapUpdate), XtRImmediate,
+ (caddr_t)DEF_CMAPUPDATE},
+ {XtNcmapShadow, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.cmapShadow), XtRImmediate,
+ (caddr_t)DEF_CMAPSHADOW},
+ {XtNcmapInterpolate, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.cmapInterpolate), XtRImmediate,
+ (caddr_t)True},
+ {XtNcacheRasters, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.cacheRasters), XtRImmediate,
+ (caddr_t)"whenNeeded"},
+ {XtNmaxRasters, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxRasters), XtRImmediate,
+ (caddr_t)MAX_RASTERS},
+ {XtNmaxMappings, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxMappings), XtRImmediate,
+ (caddr_t)MAX_MAPPINGS},
+ {XtNmaxColors, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.maxColors), XtRImmediate,
+ (caddr_t)DEF_MAXCOLORS},
+
+ {XtNmarkerTranslations, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_translations), XtRImmediate,
+ (caddr_t)defaultMarkerTranslations},
+ {XtNdefaultMarker, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_defaultMarker), XtRImmediate,
+ (caddr_t)"rectangle"},
+ {XtNnearEdge, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearEdge), XtRImmediate,
+ (caddr_t)E_DIST},
+ {XtNnearVertex, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_nearVertex), XtRImmediate,
+ (caddr_t)V_DIST},
+
+ {XtNmarkerLineWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineWidth), XtRImmediate,
+ (caddr_t)1},
+ {XtNmarkerLineStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_lineStyle), XtRImmediate,
+ (caddr_t)LineSolid},
+ {XtNmarkerFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_fill), XtRImmediate,
+ (caddr_t)False},
+ {XtNmarkerFillColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerFillBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_fillBgColor), XtRString,
+ "black"},
+ {XtNmarkerFillStyle, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_fillStyle), XtRImmediate,
+ (caddr_t)FillSolid},
+ {XtNxorFill, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(GtermWidget,gterm.gm_xorFill), XtRImmediate,
+ (caddr_t)False},
+ {XtNxorFillColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillColor), XtRImmediate,
+ (caddr_t)2},
+ {XtNxorFillBgColor, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_xorFillBgColor), XtRImmediate,
+ (caddr_t)255},
+ {XtNmarkerHighlightWidth, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_highlightWidth), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerHighlightColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_highlightColor), XtRString,
+ "green"},
+ {XtNmarkerCursorFgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorFgColor), XtRString,
+ "yellow"},
+ {XtNmarkerCursorBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_cursorBgColor), XtRString,
+ "black"},
+
+ {XtNmarkerLineLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineLineColor), XtRString,
+ "green"},
+ {XtNmarkerLineKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_LineKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerLineKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_LineKnotSize), XtRImmediate,
+ (caddr_t)5},
+
+ {XtNmarkerTextLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextLineColor), XtRString,
+ "green"},
+ {XtNmarkerTextColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextColor), XtRString,
+ "yellow"},
+ {XtNmarkerTextBgColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_TextBgColor), XtRString,
+ "SlateGray"},
+ {XtNmarkerTextBorder, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_TextBorder), XtRImmediate,
+ (caddr_t)2},
+ {XtNmarkerTextFont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ XtOffset(GtermWidget,gterm.gm_TextFont), XtRString,
+ "6x13"},
+ {XtNmarkerTextString, XtCString, XtRString, sizeof(String),
+ XtOffset(GtermWidget,gterm.gm_TextString), XtRImmediate,
+ (caddr_t)NULL},
+
+ {XtNmarkerRectLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectLineColor), XtRString,
+ "green"},
+ {XtNmarkerRectKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_RectKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerRectKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_RectKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerBoxLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxLineColor), XtRString,
+ "green"},
+ {XtNmarkerBoxKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerBoxKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_BoxKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerCircleLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleLineColor), XtRString,
+ "green"},
+ {XtNmarkerCircleKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerCircleKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_CircleKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerEllipseLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseLineColor), XtRString,
+ "green"},
+ {XtNmarkerEllipseKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerEllipseKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_EllipseKnotSize), XtRImmediate,
+ (caddr_t)0},
+ {XtNmarkerPgonLineColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonLineColor), XtRString,
+ "green"},
+ {XtNmarkerPgonKnotColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotColor), XtRString,
+ "blue"},
+ {XtNmarkerPgonKnotSize, XtCInt, XtRInt, sizeof(int),
+ XtOffset(GtermWidget,gterm.gm_PgonKnotSize), XtRImmediate,
+ (caddr_t)5},
+};
+
+/* extern void HandlePopupMenu(); */
+static Boolean SetValues();
+static void Initialize(), Realize(), Destroy(), Redisplay(), Resize();
+static void HandleIgnore(), HandleGraphicsInput(), HandleDisplayCrosshair();
+static void HandleSoftReset(), HandleGraphicsContext();
+static void HandleEnterWindow(), HandleLeaveWindow();
+static void color_crosshair(), color_ginmodeCursor();
+static void HandleTrackCursor();
+static void savepos(), blink_cursor();
+static void mp_linkafter(), mp_unlink();
+
+Marker GmSelect();
+static void M_create(), GtMarkerFree();
+static void gm_focusin(), gm_focusout(), gm_refocus();
+static void gm_request_translations(), gm_load_translations();
+static int gm_curpos();
+
+static set_default_color_index();
+static inherit_default_colormap();
+static update_default_colormap();
+static update_transients(), update_cursor();
+static request_colormap_focus(), restore_colormap_focus();
+static refresh_source(), refresh_destination(), get_regions();
+static get_rects(), scale_zoom(), scale_intzoom(), scale_boxcar();
+static lw_convolve(), bx_boxcar(), bx_extract(), bx_interp();
+static mf_getpixel(), mf_getinten();
+static scale_lowpass(), scale_nearest(), scale_bilinear();
+static save_mapping(), load_mapping(), get_pixel_mapping();
+static update_mapping(), free_mapping(), valid_mapping(), rect_intersect();
+static initialize_mapping(), draw_crosshair(), erase_crosshair();
+static DrawContext get_draw_context();
+static invalidate_draw_context();
+static XPoint *mapVector();
+static Colormap get_colormap();
+static Cursor get_cursor();
+static void init_iomap(), invalidate_cmap();
+static Pixel get_pixel(), *get_cmap_in(), *get_cmap_out();
+
+extern double atof();
+
+static XtActionsRec gtermActionsList[] = {
+ { "ignore", HandleIgnore },
+ { "graphics-input", HandleGraphicsInput },
+ { "crosshair", HandleDisplayCrosshair },
+ { "track-cursor", HandleTrackCursor },
+ { "enter-window", HandleEnterWindow },
+ { "leave-window", HandleLeaveWindow },
+/* { "popup-menu", HandlePopupMenu }, */
+ { "reset", HandleSoftReset },
+ { "m_create", M_create },
+};
+
+GtermClassRec gtermClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Gterm",
+ /* widget_size */ sizeof(GtermRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ gtermActionsList,
+ /* num_actions */ XtNumber(gtermActionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ (XrmClass)NULL,
+ /* compress_motion */ True,
+ /* compress_exposure */ True,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultGtermTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass gtermWidgetClass = (WidgetClass) &gtermClassRec;
+#define abs(a) (((a)<0)?(-(a)):(a))
+#define max(a,b) ((a)>=(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define ERR (-1)
+#define OK 0
+#define SQR(a) ((a)*(a))
+
+/*
+ * Widget class procedures.
+ * --------------------------
+ */
+
+/* ARGSUSED */
+static void
+Initialize (request, new)
+ Widget request, new;
+{
+ register GtermWidget w = (GtermWidget)new;
+ register GC gc;
+
+ XColor fg_color, bg_color;
+ XFontStruct **fp;
+ Font cursor_font;
+ Display *display;
+ Screen *screen;
+ Pixel *pp;
+ int i;
+
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ w->gterm.display = display = XtDisplay (w);
+ w->gterm.screen = screen = XtScreen (w);
+ w->gterm.root = RootWindowOfScreen (screen);
+ XtVaSetValues ((Widget)w, XtNbackground, (XtArgVal)w->gterm.color0, NULL);
+
+ /* Initialize color map. */
+ pp = &w->gterm.color0;
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = *pp++;
+ for ( ; i < MAX_SZCMAP; i++) {
+ memset ((char *)&w->gterm.color[i], 0, sizeof(XColor));
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = i;
+ }
+ XQueryColors (display, w->core.colormap, w->gterm.color, SZ_STATIC_CMAP);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ init_iomap (w);
+
+ w->gterm.useDefaultCM = (strcmp (w->gterm.cmapName, "default") == 0);
+ w->gterm.haveColormap = w->gterm.useDefaultCM;
+ w->gterm.cmapLastUpdate = 0;
+ w->gterm.cmapLastShadow = 0;
+ w->gterm.in_window = 0;
+
+ /* Get clear pixmap GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color0);
+ w->gterm.clearGC = gc;
+
+ /* Get expose GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ w->gterm.exposeGC = gc;
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc, 1, LineSolid, CapButt, JoinMiter);
+ w->gterm.drawGC = gc;
+
+ /* Get dialog box GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ /* XSetFunction (display, gc, GXcopyInverted); */
+ w->gterm.dialogGC = gc;
+
+ /* Get crosshair cursor GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XSetLineAttributes (display, gc, 0, LineSolid, CapButt, JoinMiter);
+ w->gterm.cursorGC = gc;
+
+ /* Get special cursors. */
+ bg_color.pixel = w->gterm.idleCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.idleCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.idle_cursor = get_cursor (w, w->gterm.idleCursor);
+ XRecolorCursor (display, w->gterm.idle_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.busyCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.busyCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.busy_cursor = get_cursor (w, w->gterm.busyCursor);
+ XRecolorCursor (display, w->gterm.busy_cursor, &fg_color, &bg_color);
+
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ cursor_font = XLoadFont (display, "cursor");
+ w->gterm.crosshair_cursor = XCreateGlyphCursor (display,
+ cursor_font, cursor_font, XC_crosshair, XC_crosshair,
+ &fg_color, &bg_color);
+
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+ if (strcmp (w->gterm.ginmodeCursor, "full_crosshair") != 0) {
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, w->core.colormap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ XRecolorCursor (display,
+ w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+ } else
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, "full_crosshair") == 0);
+
+ /* Make sure we have all the fonts we need. */
+ for (fp = &w->gterm.alphaFont1, i=0; i < NAlphaFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.alpha_fonts[i] = *fp;
+ }
+ for (fp = &w->gterm.dialogFont1, i=0; i < NDialogFonts; i++, fp++) {
+ if (*fp == NULL) {
+ *fp = XQueryFont (display,
+ XGContextFromGC (DefaultGCOfScreen(screen)));
+ }
+ w->gterm.dialog_fonts[i] = *fp;
+ }
+
+ /* Raster initialization. */
+ w->gterm.rasters = NULL;
+ w->gterm.nrasters = 0;
+ w->gterm.mappings = NULL;
+ w->gterm.nmappings = 0;
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ w->gterm.colormaps = NULL;
+ w->gterm.wa_defined = 0;
+ memset ((char *)&w->gterm.draw, 0, sizeof (struct drawContext));
+
+ /* Marker initialization. */
+ w->gterm.gm_head = NULL;
+ w->gterm.gm_tail = NULL;
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.defTranslations = NULL;
+ w->gterm.nauxTrans = 0;
+ w->gterm.gm_defTranslations = NULL;
+ w->gterm.gm_curTranslations = NULL;
+ w->gterm.gm_reqTranslations = NULL;
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ w->gterm.gm_initialized = False;
+
+ /* Set defaults (some of these are clobbered anyway by Realize/Resize). */
+ w->gterm.raster = 0;
+ w->gterm.cur_x = 0;
+ w->gterm.cur_y = 0;
+ w->gterm.last_x = 0;
+ w->gterm.last_y = 0;
+ w->gterm.cursor_drawn = 0;
+ w->gterm.cursor_type = GtIdleCursor;
+ w->gterm.pixmap = (Pixmap)NULL;
+ w->gterm.d_pixmap = (Pixmap)NULL;
+ w->gterm.preserve_screen = 0;
+ w->gterm.preserve_valid = 0;
+ w->gterm.d_saved = 0;
+ w->gterm.alpha_font = DefaultAlphaFont;
+ w->gterm.dialog_font = DefaultDialogFont;
+ w->gterm.optcols = 80;
+ w->gterm.optrows = 35;
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ set_default_color_index (w);
+
+ /* Disable input until window is ready. */
+ w->gterm.delay = 1;
+}
+
+static void
+Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ GtermWidget w = (GtermWidget) gw;
+ XVisualInfo rvinfo, *vinfo = (XVisualInfo *) NULL;
+ Visual *ourVisual = (Visual *) NULL;
+ int i, nvis;
+
+ /* Set default window size. */
+ XtMakeResizeRequest (gw, w->core.width, w->core.height,
+ &w->core.width, &w->core.height);
+
+ /* Should define pseudocolor visual here, if truecolor or directcolor
+ * default visual.
+ */
+
+ /* Create graphics window. We first look for an 8-Bit PseudoColor
+ * visual to use, otherwise we fail. (MJF 8/22/97)
+ XtCreateWindow (gw, InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attrs);
+ */
+ vinfo = XGetVisualInfo (w->gterm.display, 0L, &rvinfo, &nvis);
+ for (i=0; i < nvis; i++)
+ if (vinfo[i].depth == 8 && vinfo[i].class == PseudoColor)
+ ourVisual = vinfo[i].visual;
+ if (ourVisual)
+ XtCreateWindow (gw, InputOutput, ourVisual, *valueMask, attrs);
+ else {
+ fprintf (stderr, "No 8-bit PseudoColor visual found.\n");
+ exit(1);
+ }
+
+ w->gterm.window = XtWindow (gw);
+ w->gterm.old_width = w->gterm.xres = w->core.width;
+ w->gterm.old_height = w->gterm.yres = w->core.height;
+
+ GtRasterInit (w);
+ GtMarkerInit (w);
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = w->gterm.idle_cursor);
+
+ Resize (gw);
+}
+
+static void
+Destroy (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb, *cb_next;
+ Display *display = w->gterm.display;
+
+ /* Get rid of any raster stuff. */
+ GtRasterInit (gw);
+ XtFree ((char *)w->gterm.rasters);
+ XtFree ((char *)w->gterm.mappings);
+
+ /* Destroy any markers. */
+ GtMarkerFree (w);
+
+ /* Can't use XtDestroyGC here; the source says it is broken and will
+ * work only for applications that have only 1 display, and we have 2.
+ * Also the documentation in Asente&Swick documents the calling sequence
+ * incorrectly.
+ */
+ XFreeGC (display, w->gterm.clearGC);
+ XFreeGC (display, w->gterm.exposeGC);
+ XFreeGC (display, w->gterm.drawGC);
+ XFreeGC (display, w->gterm.dialogGC);
+ XFreeGC (display, w->gterm.cursorGC);
+
+ /* This one also proves problematic. When there are multiple gterm
+ * widgets allocating the same cursor, succeeding calls for the same
+ * cursor return the same cursor ID. When these widgets are later
+ * destroyed, the first XFreeCursor succeeds but subsequent ones find
+ * the referenced cursor undefined and the application boms with a
+ * BadCursor error. This must be some problem with reference counts
+ * in the X server. Cursors use minor amounts of resources and they
+ * will probably be freed anyway when the display is closed, so we just
+ * leave them defined here.
+ *
+ XFreeCursor (display, w->gterm.idle_cursor);
+ XFreeCursor (display, w->gterm.busy_cursor);
+ XFreeCursor (display, w->gterm.crosshair_cursor);
+ if (w->gterm.ginmode_cursor != w->gterm.crosshair_cursor)
+ XFreeCursor (display, w->gterm.ginmode_cursor);
+ */
+
+ if (w->gterm.pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+
+ /* Destroy callback lists. */
+ for (cb = w->gterm.resetCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.resizeCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ for (cb = w->gterm.inputCallback; cb; cb = cb_next) {
+ cb_next = cb->next;
+ XtFree ((char *)cb);
+ }
+ w->gterm.resetCallback = NULL;
+ w->gterm.resizeCallback = NULL;
+ w->gterm.inputCallback = NULL;
+
+ XtFree (w->gterm.ginmodeCursor);
+}
+
+static void
+Resize (gw)
+ Widget gw;
+{
+ GtermWidget w = (GtermWidget) gw;
+ register GtCallback *cb;
+ int char_width, char_height, char_base;
+ int bestfont, fonterr, dx, dy, i;
+ unsigned int width, height, u_junk;
+ GtCallback cbl[128];
+ XFontStruct *fp;
+ int ncb, junk;
+ Pixmap pixmap;
+ Window root;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ /* Create new pixmap. */
+ pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width + 1, w->core.height + 1, w->core.depth);
+ if (pixmap)
+ XFillRectangle (w->gterm.display, pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+
+ /* Copy old pixmap into new and free old pixmap. */
+ if (w->gterm.pixmap) {
+ XGetGeometry (w->gterm.display, w->gterm.pixmap,
+ &root, &junk, &junk, &width, &height, &u_junk, &u_junk);
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.copyOnResize)
+ XCopyArea (w->gterm.display, w->gterm.pixmap, pixmap,
+ w->gterm.exposeGC, 0, 0, width-1, height-1, 0, 0);
+ XFreePixmap (w->gterm.display, w->gterm.pixmap);
+ }
+
+ /* Install new pixmap. */
+ w->gterm.pixmap = pixmap;
+ w->gterm.preserve_valid = 0;
+
+ /* Redraw window. */
+ if (w->gterm.pixmap) {
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, 0, 0, w->core.width, w->core.height, 0, 0);
+ }
+
+ /* Pick best alpha font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NAlphaFonts; i++) {
+ fp = w->gterm.alpha_fonts[i];
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ dx = (((int)w->core.width / char_width) - w->gterm.optcols) * 2;
+ dy = ((int)w->core.height / char_height) - w->gterm.optrows;
+ if (abs(dx) + abs(dy) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx) + abs(dy);
+ }
+ }
+
+ w->gterm.alpha_font = bestfont;
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ XSetFont (w->gterm.display, w->gterm.drawGC, fp->fid);
+
+ /* Pick best dialog font. */
+ bestfont = 0; fonterr = 9999;
+ for (i=0; i < NDialogFonts; i++) {
+ fp = w->gterm.dialog_fonts[i];
+ char_width = fp->max_bounds.width;
+ dx = ((int)w->core.width / char_width) - 80;
+ if (abs(dx) < fonterr) {
+ bestfont = i;
+ fonterr = abs(dx);
+ }
+ }
+
+ w->gterm.dialog_font = bestfont;
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ char_base = fp->max_bounds.ascent;
+
+ w->gterm.d_xoff = 2;
+ w->gterm.d_yoff = w->core.height - char_height - 2;
+ w->gterm.d_height = char_height;
+ XSetFont (w->gterm.display, w->gterm.dialogGC, fp->fid);
+
+ /* Create dialog save area pixmap. */
+ if (w->gterm.d_pixmap)
+ XFreePixmap (w->gterm.display, w->gterm.d_pixmap);
+ w->gterm.d_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, char_height, w->core.depth);
+ w->gterm.d_saved = 0;
+
+ /* Adjust cursor position to allow for change in window size. */
+ w->gterm.cur_x = w->gterm.cur_x * (int)w->core.width / w->gterm.old_width;
+ w->gterm.cur_y = w->gterm.cur_y * (int)w->core.height / w->gterm.old_height;
+ w->gterm.old_width = w->core.width;
+ w->gterm.old_height = w->core.height;
+ if (w->gterm.cursor_type == GtGinmodeCursor) {
+ XWarpPointer (w->gterm.display, w->gterm.window, w->gterm.window,
+ 0,0,0,0, w->gterm.cur_x, w->gterm.cur_y);
+ update_cursor (w);
+ }
+
+ /* Raster descriptor 0 must track the window size. */
+ if (w->gterm.rasters) {
+ Raster rp = &w->gterm.rasters[0];
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ }
+
+ /* Mark gterm widget ready for further client input. */
+ w->gterm.delay = 0;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resizeCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w);
+}
+
+/* ARGSUSED */
+static void
+Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register GtermWidget w = (GtermWidget) gw;
+ register XExposeEvent *ev = (XExposeEvent *)event;
+ int x, y, width, height;
+
+ if (!XtIsRealized (gw))
+ return;
+
+ if (event) {
+ x = ev->x;
+ y = ev->y;
+ width = ev->width;
+ height = ev->height;
+ } else {
+ x = 0;
+ y = 0;
+ width = w->core.width;
+ height = w->core.height;
+ }
+
+ if (w->gterm.pixmap) {
+ /* Clipping with the region argument does not work properly with
+ * the OpenLook server for some reason - the clip region is one
+ * pixel too small on the right and bottom. Until the reason for
+ * this becomes clear, we use the bounding box provided in the
+ * Expose event to roughly clip the refresh.
+ *
+ XSetClipOrigin (w->gterm.display, w->gterm.exposeGC, 0, 0);
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, region);
+ */
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, x, y, width, height, x, y);
+ }
+
+ update_transients (w, region);
+
+ /* A dummy expose event is used to ensure that the resize delay is
+ * cleared, in the event that the resize request is not granted.
+ */
+ if (ev && ev->send_event)
+ w->gterm.delay = 0;
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues (current, request, set)
+ Widget current, request, set;
+{
+ GtermWidget old = (GtermWidget) current;
+ GtermWidget req = (GtermWidget) request;
+ register GtermWidget w = (GtermWidget) set;
+ Display *display = w->gterm.display;
+ Boolean redisplay = False;
+ register GC gc;
+
+ if (old->gterm.dialogBgColor != req->gterm.dialogBgColor) {
+ gc = w->gterm.dialogGC;
+ XSetBackground (display, gc, w->gterm.dialogBgColor);
+ }
+ if (old->gterm.dialogFgColor != req->gterm.dialogFgColor) {
+ gc = w->gterm.dialogGC;
+ XSetForeground (display, gc, w->gterm.dialogFgColor);
+ }
+
+ if (old->gterm.ginmodeCursor != req->gterm.ginmodeCursor) {
+ static char *full_crosshair = "full_crosshair";
+
+ XtFree (old->gterm.ginmodeCursor);
+ w->gterm.ginmodeCursor = XtNewString (w->gterm.ginmodeCursor);
+
+ erase_crosshair (w);
+ w->gterm.full_crosshair =
+ (strcmp (w->gterm.ginmodeCursor, full_crosshair) == 0);
+
+ if (w->gterm.full_crosshair) {
+ w->gterm.ginmode_cursor = w->gterm.crosshair_cursor;
+ color_crosshair (w);
+ } else {
+ w->gterm.ginmode_cursor = get_cursor (w, w->gterm.ginmodeCursor);
+ color_ginmodeCursor (w);
+ }
+
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->core.visible)
+ XDefineCursor (display, w->gterm.window,
+ w->gterm.cursor = w->gterm.ginmode_cursor);
+ }
+
+ if (old->gterm.crosshairCursorColor != req->gterm.crosshairCursorColor) {
+ color_crosshair (w);
+ }
+
+ if (old->gterm.ginmodeCursorBgColor != req->gterm.ginmodeCursorBgColor ||
+ old->gterm.ginmodeCursorFgColor != req->gterm.ginmodeCursorFgColor) {
+ color_ginmodeCursor (w);
+ }
+
+ return (XtIsRealized(current) ? redisplay : False);
+}
+
+static void
+color_crosshair (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+ register GC gc;
+
+ erase_crosshair (w);
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.color0;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.crosshairCursorColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ gc = w->gterm.cursorGC;
+ XSetForeground (display, gc, w->gterm.crosshairCursorColor);
+ XRecolorCursor (display, w->gterm.crosshair_cursor, &fg_color, &bg_color);
+
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+
+ update_cursor (w);
+}
+
+static void
+color_ginmodeCursor (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ XColor fg_color, bg_color;
+ Colormap defcmap;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ bg_color.pixel = w->gterm.ginmodeCursorBgColor;
+ XQueryColor (display, defcmap, &bg_color);
+ fg_color.pixel = w->gterm.ginmodeCursorFgColor;
+ XQueryColor (display, defcmap, &fg_color);
+
+ XRecolorCursor (display, w->gterm.ginmode_cursor, &fg_color, &bg_color);
+ w->gterm.ginmodeColors[0] = bg_color;
+ w->gterm.ginmodeColors[1] = fg_color;
+}
+
+/*
+ * Action procedures.
+ * -----------------------
+ */
+
+/* ARGSUSED */
+static void HandleIgnore (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ /* ignore an event */
+}
+
+/* ARGSUSED */
+static void HandleGraphicsInput (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.inputCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, event);
+}
+
+/* ARGSUSED */
+static void HandleDisplayCrosshair (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *nparams; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XButtonEvent *ev = &event->xbutton;
+
+ /* Ignore if cursor is in a marker. */
+ if (w->gterm.gm_active)
+ return;
+
+ if (*nparams && strcmp (params[0], "on") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.crosshair_cursor);
+ draw_crosshair (w, ev->x, ev->y);
+ } else if (*nparams && strcmp (params[0], "off") == 0) {
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, w->gterm.cursor);
+ }
+}
+
+/* ARGSUSED */
+static void HandleTrackCursor (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ XMotionEvent *ev = &event->xmotion;
+ gmSelection what;
+ Marker gm;
+
+ savepos (w, (XEvent *)ev);
+
+ if ((gm = GmSelect (w, ev->x, ev->y, &what)))
+ gm_focusin (w, gm, &what);
+ else if (w->gterm.gm_active)
+ gm_focusout (w, 1);
+
+ if (w->gterm.cursor_type == GtGinmodeCursor)
+ if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, ev->x, ev->y);
+
+ /* Flushing here keeps cursor tracking synchronous and tends
+ * to aid motion compression, by preventing crosshair draw
+ * requests from being queued up for transmission to the
+ * server.
+ */
+ XFlush (w->gterm.display);
+
+ } else {
+ w->gterm.cur_x = ev->x;
+ w->gterm.cur_y = ev->y;
+ }
+}
+
+/* ARGSUSED */
+static void HandleEnterWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XEnterWindowEvent *ev = (XEnterWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int update = w->gterm.cmapUpdate;
+
+ /* To avoid excessive server queries the colormap is only updated
+ * every so often. Updating is disabled if cmapUpdate is set to zero.
+ if (update && ev->time - w->gterm.cmapLastUpdate > update * 1000) {
+ */
+ if (update) {
+ inherit_default_colormap (w);
+ w->gterm.cmapLastUpdate = ev->time;
+ }
+
+ /* Advise the window manager to load our colormap. */
+ request_colormap_focus (w);
+ }
+
+ w->gterm.in_window++;
+}
+
+/* ARGSUSED */
+static void HandleLeaveWindow (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XLeaveWindowEvent *ev = (XLeaveWindowEvent *) event;
+
+ if (!w->gterm.useDefaultCM && w->gterm.haveColormap) {
+ int shadow = w->gterm.cmapShadow;
+
+ /* The shadow option matches unused cells in the default colormap
+ * with the colors in our custom colormap.
+ if (shadow && ev->time - w->gterm.cmapLastShadow > shadow * 1000) {
+ */
+ if (shadow) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = ev->time;
+ }
+
+ restore_colormap_focus (w);
+ }
+
+ w->gterm.in_window = 0;
+}
+
+/* ARGSUSED */
+static void HandleSoftReset (widget, event, params, param_count)
+ Widget widget;
+ XEvent *event; /* unused */
+ String *params; /* unused */
+ Cardinal *param_count; /* unused */
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register GtCallback *cb;
+ GtCallback cbl[128];
+ int ncb, i;
+
+ GtReset (w);
+
+ /* Call any resize callbacks. Callbacks can delete or add callbacks,
+ * so make a copy of the callback list first.
+ */
+ for (cb = w->gterm.resetCallback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = *cb;
+ for (i=0; i < ncb; i++)
+ (*cbl[i].proc) (cbl[i].client_data, w, NULL);
+}
+
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++) {
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap)
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+ mx->xoffset = mx->yoffset = 0;
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+*/
+ mx->scale = 0;
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
+
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window. */
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ w->gterm.nrasters++;
+
+ /* Free any previously allocated colormap cells. */
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors - SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ /* Only rasters of depth 8 bits are currently supported. */
+ if (depth && depth != 8)
+ return (ERR);
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, RasterDepth);
+ if (rp->r.pixmap == (Pixmap)NULL)
+ goto ximage;
+ XFillRectangle (w->gterm.display, rp->r.pixmap, w->gterm.clearGC,
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage. */
+ximage:
+ rp->type = ImageRaster;
+
+ /* Get pixel storage. */
+ npix = width * height;
+ if ((data = (uchar *) XtMalloc (npix)) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+ }
+
+ w->gterm.nrasters++;
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = RasterDepth;
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+ int bytes_per_line, i;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+ if (raster == 0 && w->gterm.pixmap) {
+
+ /* ### Someone (Mike?) added this code for some reason, but it
+ * does not appear to be valid. This code already writes to the
+ * backing store (gterm.pixmap) so use_backing_store should not
+ * be required. Also blindly using only the first mapping context
+ * and ignoring any others cannot be correct. There is code
+ * below which executes any mappings defined on the raster.
+ * In general this requires scaling, not a simple XCopyArea.
+ *
+ * DrawContext dx = get_draw_context (w);
+ * register MappingContext mx;
+ * mx = &dx->mapContext[0];
+ */
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ /* ### (cont'd)
+ * if (mx->use_backing_store)
+ * XCopyArea (display, w->gterm.pixmap, mx->pixmap,
+ * w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ */
+
+ XCopyArea (display, w->gterm.pixmap, rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+ } else
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC, ximage,
+ 0, 0, x1, y1, nx, ny);
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map is
+ * dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation woudl also make it easy
+ * to add support later for image depths other than 8 bit. Doing the
+ * conversion to display pixels here is however simpler and more
+ * efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = (cmap[*ip++] & 0377);
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage. */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ? w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + y * bytes_per_line + x;
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; )
+ *op++ = cmap[*ip++];
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store)
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (i);
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ dst, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n;
+ unsigned long plane_masks[1];
+ int req, need;
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+ /* See if the colormap already exists. */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it. */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap. */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache. */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+ } else
+ wa = w->gterm.wa;
+
+ if (wa.depth == 1)
+ goto unitary;
+
+ switch (wa.visual->class) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp))
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ Colormap colormap;
+ long timeval, time();
+ int ncolors, shadow;
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow))) {
+
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+unitary:
+ for (i = first; i < first+nelem; i++) {
+ w->gterm.cmap[i] = i;
+ cp = &w->gterm.color[i];
+ cp->pixel = i;
+ cp->red = r[i+first];
+ cp->green = g[i+first];
+ cp->blue = b[i+first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+ break;
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+ register int i;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++)
+ if (first+i < w->gterm.ncolors) {
+ cp = &w->gterm.color[first+i];
+ r[i] = cp->red;
+ g[i] = cp->green;
+ b[i] = cp->blue;
+ } else
+ break;
+
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap. */
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ } else {
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ * is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ /* Load the colormap into the display. */
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+ /* If the colormap we loaded to the display was the display colormap,
+ * restore the original unscaled colors in the gterm descriptor so that
+ * we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0)
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+
+ return (OK);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+ }
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ Mapping sv_mp, p_mp;
+ int status;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return;
+ } else if (!mp->enabled) {
+ return;
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return;
+
+ if (rop & R_RefreshNone)
+ return;
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &rop,
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+ if (w->gterm.haveColormap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+ /* Get custom colormap.
+ */
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+ request_colormap_focus (w);
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++)
+ for (j=0, v = ip->pixel; j < n; j++)
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++)
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap,
+ colors, op - colors);
+
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+}
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Compute the intersection of the modified region of the source raster
+ * with the rectangular region of the source raster affected by the given
+ * mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect. */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap;
+ XRectangle r;
+
+ if (!XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!valid_mapping (w, mp))
+ return (ERR);
+ if (!mp->enabled)
+ return (OK);
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (!sr->type || !dr->type)
+ return (ERR);
+ if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0)
+ return (ERR);
+ if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters)
+ return (ERR);
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XCopyArea (display, w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XCopyArea (display, sr->r.pixmap, dr->r.pixmap, w->gterm.exposeGC,
+ sx, sy, snx, sny, dx, dy);
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display, sr->r.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+
+ } else {
+ /* Source is an ximage. */
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ goto done;
+ }
+
+ /* Get output ximage. */
+ if (dr->type == ImageRaster) {
+ xout = dr->r.ximage;
+ ox = dx; oy = dy;
+ } else {
+ uchar *data = (uchar *) XtMalloc (dnx * dny);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0; oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination. */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ XCopyArea (display, w->gterm.pixmap, dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+ } else {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin)
+ XDestroyImage (xin);
+ if (delxout)
+ XDestroyImage (xout);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++)
+ op[i] = ip[xmap[i]];
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + yflip ? (dny-ny-j) : j) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+ gc = XCreateGC (display, w->gterm.root, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle:
+ gm->rotangle = gm_getfloat (value, type);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle:
+ if (gm_putfloat (gm->rotangle, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts > gm->npoints) {
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) {
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", gm->rotangle); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_gm->rotangle); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ (XtArgVal)params[i], (XtArgVal)params[i+1], XtRString);
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE + 1;
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta = -(gm->rotangle);
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ p[gm->npoints-1] = p[0];
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double scale, alpha, beta, rx, ry;
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x);
+ beta = atan2 (ry, rx);
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm->rotangle = new_gm.rotangle;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+ cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+ ptop = p + gm->npoints;
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (d1 + d2 - seglen < e_dist) {
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ }
+
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h
new file mode 100644
index 00000000..575c6f8b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h
@@ -0,0 +1,247 @@
+#ifndef _Gterm_h
+#define _Gterm_h
+
+/* Parameters:
+(this is not yet updated for xgterm - the rest of this file is)
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel White
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ foreground Foreground Pixel Black
+ height Height Dimension 240
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reverseVideo ReverseVideo Boolean False
+ width Width Dimension 320
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * Resource definitions.
+ */
+#define XtCInt "Int"
+
+#define XtNalphaFont1 "alphaFont1"
+#define XtNalphaFont2 "alphaFont2"
+#define XtNalphaFont3 "alphaFont3"
+#define XtNalphaFont4 "alphaFont4"
+#define XtNalphaFont5 "alphaFont5"
+#define XtNalphaFont6 "alphaFont6"
+#define XtNalphaFont7 "alphaFont7"
+#define XtNalphaFont8 "alphaFont8"
+
+#define XtNdialogFont1 "dialogFont1"
+#define XtNdialogFont2 "dialogFont2"
+#define XtNdialogFont3 "dialogFont3"
+#define XtNdialogFont4 "dialogFont4"
+#define XtNdialogFont5 "dialogFont5"
+#define XtNdialogFont6 "dialogFont6"
+#define XtNdialogFont7 "dialogFont7"
+#define XtNdialogFont8 "dialogFont8"
+
+#define XtNdialogBgColor "dialogBgColor"
+#define XtNdialogFgColor "dialogFgColor"
+#define XtNidleCursorBgColor "idleCursorBgColor"
+#define XtNidleCursorFgColor "idleCursorFgColor"
+#define XtNbusyCursorBgColor "busyCursorBgColor"
+#define XtNbusyCursorFgColor "busyCursorFgColor"
+#define XtNginmodeCursorBgColor "ginmodeCursorBgColor"
+#define XtNginmodeCursorFgColor "ginmodeCursorFgColor"
+#define XtNginmodeBlinkInterval "ginmodeBlinkInterval"
+#define XtNcrosshairCursorColor "crosshairCursorColor"
+
+#define XtNidleCursor "idleCursor"
+#define XtNbusyCursor "busyCursor"
+#define XtNginmodeCursor "ginmodeCursor"
+#define XtNwarpCursor "warpCursor"
+#define XtNraiseWindow "raiseWindow"
+#define XtNdeiconifyWindow "deiconifyWindow"
+#define XtNuseTimers "useTimers"
+
+#define XtNcolor0 "color0"
+#define XtNcolor1 "color1"
+#define XtNcolor2 "color2"
+#define XtNcolor3 "color3"
+#define XtNcolor4 "color4"
+#define XtNcolor5 "color5"
+#define XtNcolor6 "color6"
+#define XtNcolor7 "color7"
+#define XtNcolor8 "color8"
+#define XtNcolor9 "color9"
+
+#define XtNcmapName "cmapName"
+#define XtNcmapInitialize "cmapInitialize"
+#define XtNcopyOnResize "copyOnResize"
+#define XtNbasePixel "basePixel"
+#define XtNcmapUpdate "cmapUpdate"
+#define XtNcmapShadow "cmapShadow"
+#define XtNcmapInterpolate "cmapInterpolate"
+#define XtNmaxRasters "maxRasters"
+#define XtNcacheRasters "cacheRasters"
+#define XtNmaxMappings "maxMappings"
+#define XtNmaxColors "maxColors"
+
+#define XtNmarkerTranslations "markerTranslations"
+#define XtNdefaultMarker "defaultMarker"
+#define XtNnearEdge "nearEdge"
+#define XtNnearVertex "nearVertex"
+#define XtNmarkerLineWidth "markerLineWidth"
+#define XtNmarkerLineStyle "markerLineStyle"
+#define XtNmarkerFill "markerFill"
+#define XtNmarkerFillColor "markerFillColor"
+#define XtNmarkerFillBgColor "markerFillBgColor"
+#define XtNmarkerFillStyle "markerFillStyle"
+#define XtNxorFill "xorFill"
+#define XtNxorFillColor "xorFillColor"
+#define XtNxorFillBgColor "xorFillBgColor"
+#define XtNmarkerHighlightWidth "markerHighlightWidth"
+#define XtNmarkerHighlightColor "markerHighlightColor"
+#define XtNmarkerCursorFgColor "markerCursorFgColor"
+#define XtNmarkerCursorBgColor "markerCursorBgColor"
+#define XtNmarkerLineLineColor "markerLineLineColor"
+#define XtNmarkerLineKnotColor "markerLineKnotColor"
+#define XtNmarkerLineKnotSize "markerLineKnotSize"
+#define XtNmarkerTextLineColor "markerTextLineColor"
+#define XtNmarkerTextColor "markerTextColor"
+#define XtNmarkerTextBgColor "markerTextBgColor"
+#define XtNmarkerTextBorder "markerTextBorder"
+#define XtNmarkerTextFont "markerTextFont"
+#define XtNmarkerTextString "markerTextString"
+#define XtNmarkerRectLineColor "markerRectLineColor"
+#define XtNmarkerRectKnotColor "markerRectKnotColor"
+#define XtNmarkerRectKnotSize "markerRectKnotSize"
+#define XtNmarkerBoxLineColor "markerBoxLineColor"
+#define XtNmarkerBoxKnotColor "markerBoxKnotColor"
+#define XtNmarkerBoxKnotSize "markerBoxKnotSize"
+#define XtNmarkerCircleLineColor "markerCircleLineColor"
+#define XtNmarkerCircleKnotColor "markerCircleKnotColor"
+#define XtNmarkerCircleKnotSize "markerCircleKnotSize"
+#define XtNmarkerEllipseLineColor "markerEllipseLineColor"
+#define XtNmarkerEllipseKnotColor "markerEllipseKnotColor"
+#define XtNmarkerEllipseKnotSize "markerEllipseKnotSize"
+#define XtNmarkerPgonLineColor "markerPgonLineColor"
+#define XtNmarkerPgonKnotColor "markerPgonKnotColor"
+#define XtNmarkerPgonKnotSize "markerPgonKnotSize"
+
+/*
+ * Gterm widget flags.
+ */
+#define GtSet 1 /* drawing mode */
+#define GtClear 2
+#define GtInvert 3
+
+#define GtOutline 1 /* line styles */
+#define GtPoint 2
+#define GtSolid 3
+#define GtDashed 4
+#define GtDotted 5
+#define GtDashDot 6
+#define GtDash3Dot 7
+
+#define GtNoCursor 0 /* cursor types */
+#define GtGinmodeCursor 1
+#define GtBusyCursor 2
+#define GtIdleCursor 3
+
+#define GtDefault 0 /* raster types */
+#define GtClient 1
+#define GtServer 2
+
+#define GtPixel 0 /* coordinate types */
+#define GtNDC 1
+
+#define GtMap 0 /* mapping direction */
+#define GtUnmap 1
+
+#define GtWindow 0 /* drawable types */
+#define GtWidget 1
+
+#define R_OpcodeMask 0000017 /* rasterop definitions */
+#define R_Transient 0000020
+#define R_RefreshAll 0000040
+#define R_RefreshNone 0000100
+#define R_MFMask 0777000
+
+#define MF_NEAREST 0001000 /* antialiasing functions */
+#define MF_BILINEAR 0002000
+#define MF_AREA 0004000
+#define MF_BLKAVG 0010000
+#define MF_BOXCAR 0020000
+#define MF_LOWPASS 0040000
+#define MF_GAUSSIAN 0100000
+
+#define GmText "text" /* graphics marker types */
+#define GmLine "line"
+#define GmPolyline "polyline"
+#define GmRectangle "rectangle"
+#define GmBox "box"
+#define GmCircle "circle"
+#define GmEllipse "ellipse"
+#define GmPolygon "polygon"
+
+#define Gm_Text 1 /* integer codes for above */
+#define Gm_Line 2
+#define Gm_Polyline 3
+#define Gm_Rectangle 4
+#define Gm_Box 5
+#define Gm_Circle 6
+#define Gm_Ellipse 7
+#define Gm_Polygon 8
+#define Gm_NTypes 8
+
+#define GmType "type" /* marker attributes */
+#define GmActivated "activated"
+#define GmVisible "visible"
+#define GmSensitive "sensitive"
+#define GmAutoRedraw "autoRedraw"
+#define GmTranslations "translations"
+#define GmX "x"
+#define GmY "y"
+#define GmWidth "width"
+#define GmHeight "height"
+#define GmRotangle "rotangle"
+#define GmHighlightColor "highlightColor"
+#define GmLineColor "lineColor"
+#define GmLineWidth "lineWidth"
+#define GmLineStyle "lineStyle"
+#define GmKnotColor "knotColor"
+#define GmKnotSize "knotSize"
+#define GmFill "fill"
+#define GmFillColor "fillColor"
+#define GmFillBgColor "fillBgColor"
+#define GmFillPattern "fillPattern"
+#define GmFillStyle "fillStyle"
+#define GmTextColor "textColor"
+#define GmTextBgColor "textBgColor"
+#define GmTextBorder "textBorder"
+#define GmImageText "imageText"
+#define GmFont "font"
+#define GmRotIndicator "rotIndicator" /* MF020 */
+
+#define GmEvNotify 00001 /* marker callback events */
+#define GmEvMoveResize 00002
+#define GmEvModify 00004
+#define GmEvRedraw 00010
+#define GmEvDestroy 00020
+#define GmEvInput 00040
+#define GmEvFocusIn 00100
+#define GmEvFocusOut 00200
+#define GmEvConstraint 00400
+
+/* Double version of XPoint. */
+struct dPoint {
+ double x;
+ double y;
+};
+typedef struct dPoint DPoint;
+
+typedef struct _GtermRec *GtermWidget;
+typedef struct _GtermClassRec *GtermWidgetClass;
+
+extern WidgetClass gtermWidgetClass;
+
+#endif /* _Gterm_h */
diff --git a/vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h b/vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h
new file mode 100644
index 00000000..f86d4e1c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h
@@ -0,0 +1,524 @@
+#ifndef _GtermP_h
+#define _GtermP_h
+
+#include "Gterm.h"
+
+/*
+ * GtermP -- Private definitions for the Gterm graphics widget.
+ */
+
+#define DEF_WIDTH 640
+#define DEF_HEIGHT 480
+#define MAX_RASTERS 512
+#define MAX_MAPPINGS 32
+#define SZ_NUMBER 64
+#define SZ_STATIC_CMAP 10 /* bg+fg+NColors */
+#define MAX_SZCMAP 256 /* max size colormap */
+#define DEF_MAXCOLORS 216 /* max dynamic colors */
+#define MAX_WMWIN 32 /* max WM colormaps */
+#define MAX_REGIONS 64 /* setMapping regions */
+#define MAX_AUXTRANS 8 /* auxiliary translations */
+#define DEF_BASEPIXEL 38 /* base of custom colormap */
+#define DEF_CMAPUPDATE 60 /* seconds */
+#define DEF_CMAPSHADOW 10 /* seconds */
+#define DEF_COPYONRESIZE True /* copy pixmap on resize */
+#define DEF_WARPCURSOR False /* enable warp cursor */
+#define DEF_RAISEWINDOW False /* enable raise window */
+#define DEF_DEICONIFYWINDOW False /* enable deiconfify window */
+#define DEF_USETIMERS True /* ok to use timers */
+#define MAX_DRAW 64 /* max mappings for a draw */
+#define MAX_POINTS 4096 /* max points in polyline */
+#define GM_MAXVERTICES 64 /* max GM points w/o malloc */
+#define GM_NPTSCIRCLE 48 /* npoints circle or ellipse */
+#define GM_MAXCALLBACKS 16 /* max GM callbacks */
+#define GM_UPDATE 30 /* marker update interval */
+#define MAXNDC 32767 /* GKI/NDC scale factor */
+#define V_DIST 4 /* Close to vertex, pixels */
+#define E_DIST 1 /* Close to edge, pixels */
+
+
+#define RasterDepth 8
+#define NAlphaFonts 8
+#define NDialogFonts 8
+#define NColors 8
+
+typedef void (*GmVMethod)();
+typedef int (*GmIMethod)();
+#define uchar unsigned char
+#define ushort unsigned short
+
+/* Raster definitions. */
+#define ImageRaster 1
+#define PixmapRaster 2
+
+struct raster {
+ int type;
+ int delete;
+ int width, height;
+ union {
+ Pixmap pixmap;
+ XImage *ximage;
+ } r;
+};
+
+/* Colormap structure. */
+struct colormap {
+ int map;
+ int ncells;
+ struct colormap *next;
+ unsigned short r[MAX_SZCMAP];
+ unsigned short g[MAX_SZCMAP];
+ unsigned short b[MAX_SZCMAP];
+};
+
+/* mapExtent - Range of dst pixels affected by a src pixel. */
+typedef struct {
+ Position lo;
+ Position hi;
+} mapExtent, *MapExtent;
+
+/* Mappings map a source to a destination. A src or dst of zero refers to
+ * the window, a nonzero value is the raster number.
+ */
+struct mapping {
+ int mapping; /* mapping number */
+ int enabled; /* update destination */
+ int defined; /* mapping is defined */
+ int updated; /* internal params ready */
+ int refresh; /* refresh entire dest */
+ int rop; /* rasterop */
+ int src; /* source rect */
+ int st;
+ int sx, sy;
+ int snx, sny;
+ int dst; /* destination rect */
+ int dt;
+ int dx, dy;
+ int dnx, dny;
+ int scaling; /* internal parameters */
+ float xscale, yscale;
+ mapExtent *x_extent, *y_extent;
+ int *x_srcpix, *y_srcpix;
+ float *x_src, *y_src;
+ uchar *mapdata;
+ int datalen;
+ struct mapping *prev; /* previous in stack order */
+ struct mapping *next; /* next in stack order */
+};
+
+#define M_NOSCALING 0
+#define M_ZOOM 1
+#define M_INTZOOM 2
+#define M_DEZOOM 3
+
+/* The drawing context defines what happens when a drawing operation (e.g.
+ * polyline) takes place. In the simplest case (raster=0) one simply draws
+ * into the display window with no transformation or clipping. When a
+ * raster provides the drawing context, the graphics are drawn once for each
+ * active mapping defined on the raster, using the scaling and drawable
+ * defined by the mapping.
+ */
+struct drawContext {
+ int valid;
+ int raster;
+ struct raster *rp;
+ int nmappings;
+ struct mappingContext {
+ int mapping;
+ struct mapping *mp;
+ int scale;
+ float xoffset, xscale;
+ float yoffset, yscale;
+ int use_backing_store;
+ Pixmap pixmap;
+ GC drawGC;
+ int GC_private;
+ } mapContext[MAX_DRAW];
+};
+
+/* Graphics Markers. A marker is an active graphics object displayed on
+ * top of a drawing to mark a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state.
+ */
+
+/* Callback descriptor. */
+struct markerCallback {
+ int events;
+ GmIMethod func;
+ XtPointer client_data;
+};
+
+/* Marker selection. */
+struct markerSelection {
+ int type;
+ int vertex;
+};
+
+/* Main Marker descriptor. */
+struct marker {
+ GtermWidget w; /* backpointer to widget */
+ int type; /* marker type */
+ int flags; /* bitflags */
+ int x, y; /* position */
+ int width, height; /* size */
+ double rotangle; /* orientation */
+ XtTranslations translations; /* marker translations */
+ XRectangle old_rect; /* old bounding box */
+ Region old_region; /* old screen region */
+ XRectangle cur_rect; /* current bounding box */
+ Region cur_region; /* current screen region */
+ Time time; /* time of last marker edit */
+ struct marker *next; /* next marker */
+ struct marker *prev; /* previous marker */
+ struct marker *parent; /* set if copy */
+
+ int lineColor, lineWidth, lineStyle; /* marker attributes */
+ int highlightColor;
+ int knotColor, knotSize;
+ int fill, fillStyle;
+ int fillColor, fillBgColor;
+ Pixmap fillPattern;
+ int imageText, textBorder;
+ int textColor, textBgColor;
+ int rotIndicator; /* MF020 */
+ XFontStruct *font;
+
+ int npoints; /* marker data */
+ XPoint *points;
+ XPoint point_data[GM_MAXVERTICES+1];
+ struct dPoint *pgon;
+ int pgon_npts;
+ char *text;
+
+ GmIMethod select; /* class methods */
+ GmVMethod markpos;
+ GmVMethod redraw;
+ GmVMethod update;
+ GmVMethod addPt;
+ GmVMethod deletePt;
+ GmVMethod movePt;
+ GmVMethod move;
+ GmVMethod resize;
+ GmVMethod rotate;
+
+ int ncallbacks; /* callbacks */
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ XtIntervalId focus_id;
+ int constraints;
+};
+
+/* Graphics marker bitflags. */
+#define Gm_Activated 000001
+#define Gm_Visible 000002
+#define Gm_Sensitive 000004
+#define Gm_AutoRedraw 000010
+#define Gm_PgonInit 000020
+#define Gm_Smooth 000040
+#define Gm_Modified 000100
+#define Gm_BeingDestroyed 000200
+
+/* Attribute value type codes. */
+#define Gt_Bool 1
+#define Gt_Int 2
+#define Gt_DFloatP 3
+#define Gt_Pointer 4
+#define Gt_String 5
+
+/* Attribute name codes. */
+#define Ga_Type 1
+#define Ga_Activated 2
+#define Ga_Visible 3
+#define Ga_Sensitive 4
+#define Ga_AutoRedraw 5
+#define Ga_Translations 6
+#define Ga_X 7
+#define Ga_Y 8
+#define Ga_Width 9
+#define Ga_Height 10
+#define Ga_Rotangle 11
+#define Ga_HighlightColor 12
+#define Ga_LineColor 13
+#define Ga_LineWidth 14
+#define Ga_LineStyle 15
+#define Ga_KnotColor 16
+#define Ga_KnotSize 17
+#define Ga_Fill 18
+#define Ga_FillColor 19
+#define Ga_FillBgColor 20
+#define Ga_FillPattern 21
+#define Ga_FillStyle 22
+#define Ga_TextColor 23
+#define Ga_TextBgColor 24
+#define Ga_TextBorder 25
+#define Ga_ImageText 26
+#define Ga_Font 27
+#define Ga_Text 28
+#define Ga_RotIndicator 29 /* MF020 */
+
+/* Bitflags for selected attributes. */
+#define Gb_X 00001
+#define Gb_Y 00002
+#define Gb_Width 00004
+#define Gb_Height 00010
+#define Gb_Rotangle 00020
+
+/* Codes for marker selection types. */
+#define Ge_Marker 1
+#define Ge_Point 2
+#define Ge_Edge 3
+
+/* Auxiliary translation tables. */
+#define T_replace 0
+#define T_augment 1
+#define T_override 2
+
+typedef struct raster *Raster;
+typedef struct mapping *Mapping;
+typedef struct drawContext *DrawContext;
+typedef struct mappingContext *MappingContext;
+typedef struct marker *Marker;
+typedef struct markerSelection gmSelection;
+typedef struct markerSelection *GmSelection;
+
+
+/* Gterm callbacks. */
+typedef void (*GtCallbackProc)();
+struct gtCallback {
+ GtCallbackProc proc;
+ XtPointer client_data;
+ struct gtCallback *next;
+};
+typedef struct gtCallback GtCallback;
+
+
+/* Main Gterm widget instance descriptor.
+ */
+typedef struct {
+ /* resources */
+ XFontStruct *alphaFont1; /* graphics fonts */
+ XFontStruct *alphaFont2;
+ XFontStruct *alphaFont3;
+ XFontStruct *alphaFont4;
+ XFontStruct *alphaFont5;
+ XFontStruct *alphaFont6;
+ XFontStruct *alphaFont7;
+ XFontStruct *alphaFont8;
+
+ XFontStruct *dialogFont1; /* dialog fonts */
+ XFontStruct *dialogFont2;
+ XFontStruct *dialogFont3;
+ XFontStruct *dialogFont4;
+ XFontStruct *dialogFont5;
+ XFontStruct *dialogFont6;
+ XFontStruct *dialogFont7;
+ XFontStruct *dialogFont8;
+
+ Pixel dialogBgColor; /* default colors */
+ Pixel dialogFgColor;
+ Pixel idleCursorBgColor;
+ Pixel idleCursorFgColor;
+ Pixel busyCursorBgColor;
+ Pixel busyCursorFgColor;
+ Pixel ginmodeCursorBgColor;
+ Pixel ginmodeCursorFgColor;
+ int ginmodeBlinkInterval;
+ XColor ginmodeColors[2];
+ Pixel crosshairCursorColor;
+ String idleCursor;
+ String busyCursor;
+ String ginmodeCursor;
+ Boolean warpCursor;
+ Boolean raiseWindow;
+ Boolean deiconifyWindow;
+ Boolean useTimers;
+
+ Pixel color0;
+ Pixel color1;
+ Pixel color2;
+ Pixel color3;
+ Pixel color4;
+ Pixel color5;
+ Pixel color6;
+ Pixel color7;
+ Pixel color8;
+ Pixel color9;
+
+ String cacheRasters;
+ int maxRasters; /* raster display stuff */
+ int maxMappings;
+ int maxColors;
+
+ /* private state */
+ Display *display;
+ Screen *screen;
+ Window window;
+ Window root;
+
+ int raster; /* used for drawing context */
+ int delay; /* wait for display */
+ Pixmap pixmap; /* used to refresh window */
+ Pixmap d_pixmap; /* used to erase dialog area */
+ int d_saved; /* set when d_pixmap filled */
+ GC clearGC; /* clear pixmap */
+ GC exposeGC; /* copy pixmap to window */
+ GC drawGC; /* graphics drawing */
+ GC dialogGC; /* dialog box */
+ GC cursorGC; /* crosshair cursor */
+ int cursor_type; /* type of cursor to display */
+ Cursor cursor; /* current cursor */
+ int full_crosshair; /* crosshair enabled */
+ int preserve_screen; /* cursor preserves screen */
+ int preserve_valid; /* saved data is valid */
+ Cursor idle_cursor; /* application is idle */
+ Cursor busy_cursor; /* application is busy */
+ Cursor ginmode_cursor; /* graphics input mode */
+ Cursor crosshair_cursor; /* graphics input mode */
+ int cursor_drawn; /* crosshair cursor drawn */
+ int cur_x, cur_y; /* crosshair cursor coords */
+ int old_width, old_height; /* size before resize */
+ int save_root; /* root window of saved cur */
+ int save_x, save_y; /* saved cursor location */
+ int last_x, last_y; /* x,y of last event */
+ int interactive; /* set if cursor read */
+ int char_size; /* not used */
+ int data_level; /* draw or erase graphics */
+ int line_style; /* solid or patterned line */
+ int line_width; /* width of line in pixels */
+ int fill_type; /* not used */
+ int color_index; /* current color index */
+ int xres, yres; /* tek logical resolution */
+ int d_xoff, d_yoff; /* dialog area offset */
+ int d_height; /* dialog area height */
+ int optcols, optrows; /* optimum screen size, chars */
+ int alpha_font; /* current alpha font index */
+ int dialog_font; /* current dialog font index */
+
+ int ncolors; /* current cmap size */
+ int haveColormap; /* colormap initialized */
+ Boolean copyOnResize; /* copy old pixmap on resize */
+ int useDefaultCM; /* use default colormap */
+ Pixel base_pixel; /* used for custom colormap */
+ String cmapName; /* private colormap name */
+ Boolean cmapInitialize; /* forcibly install colormap */
+ Atom cmapAtom; /* atom for cmap property */
+ int cmapShadow; /* update default colormap */
+ Time cmapLastShadow; /* time of last update */
+ Boolean cmapInterpolate; /* interpolate colormap */
+ int cmapUpdate; /* update interval, seconds */
+ Time cmapLastUpdate; /* time of last update */
+ Pixel cmap[MAX_SZCMAP]; /* map color number to pixval */
+ XColor color[MAX_SZCMAP]; /* RGB color assignments */
+ ushort iomap[MAX_SZCMAP]; /* client i/o color map */
+ Pixel cmap_in[MAX_SZCMAP]; /* umap and cmap combined */
+ Pixel cmap_out[MAX_SZCMAP]; /* umap and cmap combined */
+ int cmap_in_valid; /* set when cmap_in computed */
+ int cmap_out_valid; /* set when cmap_out computed */
+ struct colormap *colormaps; /* list of client colormaps */
+ Window wmTop; /* top level window */
+ Window wmWindows[MAX_WMWIN]; /* custom colormap windows */
+ int n_wmWindows; /* number of WM windows */
+ int in_window; /* pointer is in window */
+ XWindowAttributes wa; /* window attributes */
+ int wa_defined; /* set when above is defined */
+
+ XFontStruct *alpha_fonts[NAlphaFonts]; /* alpha font index */
+ XFontStruct *dialog_fonts[NDialogFonts];/* dialog font index */
+
+ GtCallback *resetCallback; /* client setGterm callbacks */
+ GtCallback *resizeCallback; /* client resize callback */
+ GtCallback *inputCallback; /* client event input cb */
+
+ Raster rasters; /* raster descriptors */
+ int nrasters; /* number of alloced rasters */
+ Mapping mappings; /* mapping descriptors */
+ int nmappings; /* number of mappings */
+ Mapping mp_head; /* head of mapping list */
+ Mapping mp_tail; /* tail of mapping list */
+ struct drawContext draw; /* drawing context */
+
+ /* Markers */
+ Marker gm_head; /* head of marker list */
+ Marker gm_tail; /* head of marker list */
+ Marker gm_create; /* set if creating marker */
+ Marker gm_active; /* marker that has focus */
+ gmSelection gm_selection; /* active portion of marker */
+ GC gm_drawGC; /* marker drawing GC */
+ GC gm_rubberGC; /* marker rubber-band GC */
+ Cursor gm_markerCursor; /* pointer in marker */
+ Cursor gm_edgeCursor; /* pointer on marker edge */
+ Cursor gm_pointCursor; /* pointer near marker point */
+ int gm_redisplay; /* redisplay needed */
+ int gm_initialized; /* set after init */
+
+ XtTranslations defTranslations; /* gterm translations */
+ XtTranslations auxTrans[MAX_AUXTRANS]; /* auxiliary translations */
+ int auxTType[MAX_AUXTRANS]; /* translation type */
+ int nauxTrans; /* number of auxilary trans */
+ String gm_translations; /* Marker translations */
+ XtTranslations gm_defTranslations; /* default marker trans */
+ Marker gm_curTranslations; /* current translations */
+ Marker gm_reqTranslations; /* requested translations */
+ XtIntervalId gm_timer_id; /* translation request timer */
+
+ String gm_defaultMarker; /* default marker type name */
+ int gm_defaultType; /* default marker type */
+ int gm_nearEdge; /* defines area near edge */
+ int gm_nearVertex; /* defines area near Vertex */
+
+ int gm_lineWidth; /* shared attributes */
+ int gm_lineStyle;
+ Boolean gm_fill;
+ Pixel gm_fillColor;
+ Pixel gm_fillBgColor;
+ int gm_fillStyle;
+ Boolean gm_xorFill; /* fill with GXxor */
+ int gm_xorFillColor; /* xor-fill color */
+ int gm_xorFillBgColor; /* xor-fill background color */
+ int gm_highlightWidth; /* highlight width, pixels */
+ int gm_highlightColor; /* highlight color */
+ Pixel gm_cursorFgColor; /* marker cursors */
+ Pixel gm_cursorBgColor; /* marker cursors */
+
+ Pixel gm_LineLineColor; /* Lines, Polylines */
+ Pixel gm_LineKnotColor;
+ int gm_LineKnotSize;
+ Pixel gm_TextLineColor; /* Text markers */
+ Pixel gm_TextColor;
+ Pixel gm_TextBgColor; /* bkg color, image text */
+ int gm_TextBorder; /* border around text */
+ XFontStruct *gm_TextFont; /* default font */
+ String gm_TextString; /* default text */
+
+ Pixel gm_RectLineColor; /* Rectangle markers */
+ Pixel gm_RectKnotColor;
+ int gm_RectKnotSize;
+ Pixel gm_BoxLineColor; /* Box markers */
+ Pixel gm_BoxKnotColor;
+ int gm_BoxKnotSize;
+ Pixel gm_CircleLineColor; /* Circle markers */
+ Pixel gm_CircleKnotColor;
+ int gm_CircleKnotSize;
+ Pixel gm_EllipseLineColor; /* Ellipse markers */
+ Pixel gm_EllipseKnotColor;
+ int gm_EllipseKnotSize;
+ Pixel gm_PgonLineColor; /* Polygon markers */
+ Pixel gm_PgonKnotColor;
+ int gm_PgonKnotSize;
+} GtermPart;
+
+typedef struct _GtermRec {
+ CorePart core;
+ GtermPart gterm;
+} GtermRec;
+
+typedef struct {int dummy;} GtermClassPart;
+
+typedef struct _GtermClassRec {
+ CoreClassPart core_class;
+ GtermClassPart gterm_class;
+} GtermClassRec;
+
+extern GtermClassRec gtermClassRec;
+
+#endif /* _GtermP_h */
diff --git a/vendor/x11iraf/obm/ObmW/GtermCmap.c b/vendor/x11iraf/obm/ObmW/GtermCmap.c
new file mode 100644
index 00000000..f4ec239e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermCmap.c
@@ -0,0 +1,765 @@
+
+
+
+/*
+ * Internal procedures for the above code.
+ * ----------------------------------------
+ */
+
+/* get_colormap -- Get a private colormap. On all calls after the first
+ * this just returns the existing gterm widget colormap. On the first call
+ * we query the server for the named custom colormap, and if the colormap
+ * exists we modify the gterm widget to use it. If the custom colormap has
+ * not yet been created by some other client, we create it.
+ *
+ * This code creates a custom colormap using the "standard colormap"
+ * facilities provided by XLIB. Although we do not use any of the predefined
+ * standard colormaps, use of the standard colormap facilities allows any
+ * number of clients to share the same custom colormap. Use of a custom
+ * colormap helps avoid running out of space in the default colormap, ensures
+ * that the gterm widget will get the color cells it needs, and makes it
+ * easier for several imaging clients which share the same colormap to
+ * simultaneously display their windows.
+ *
+ * To minimize colormap flashing we try to avoid using the full colormap,
+ * setting the unused cells to the colors set in the default colormap. In
+ * most cases this will prevent the rest of the screen from changing color
+ * when the custom colormap is installed.
+ */
+static Colormap
+get_colormap (w)
+ GtermWidget w;
+{
+ register int i, j;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ XColor def_colors[SZ_STATIC_CMAP], *cp, *c1, *c2;
+ XStandardColormap cm, *cm_p;
+ XColor colors[MAX_SZCMAP];
+ int base_pixel, p1, p2;
+ Colormap colormap;
+ char property[128];
+ int ncmap, nitems;
+ Pixel pixel;
+ Atom atom;
+
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_colormap: have=%d ncols=%d maxcols=%d base=%d\n",
+ w->gterm.haveColormap, w->gterm.ncolors, w->gterm.maxColors,
+ w->gterm.base_pixel);
+
+ if (w->gterm.haveColormap || w->gterm.useGlobalCmap)
+ return (w->core.colormap);
+
+ /* Map custom colormap name to atom. */
+ sprintf (property, "GT_%s", w->gterm.cmapName);
+ atom = XInternAtom (display, property, False);
+ w->gterm.cmapAtom = atom;
+
+
+ /* Get custom colormap.
+ */
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_colormap: cmapInitialize=%d GetRGB=%d of %d\n",
+ w->gterm.cmapInitialize,
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom),
+ ncmap);
+
+
+ if (!w->gterm.cmapInitialize &&
+ XGetRGBColormaps (display, w->gterm.root, &cm_p, &ncmap, atom)) {
+
+ /* Colormap aleady exists, just use it.
+ */
+ cm = *cm_p;
+ colormap = cm.colormap;
+ w->gterm.base_pixel = cm.base_pixel;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "get_colormap: use existing cmap=0x%x; base=%d\n",
+ colormap, w->gterm.base_pixel);
+
+
+ } else if (w->gterm.w_depth > 8) {
+
+ /* Setup for TrueColor visual.
+ */
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_colormap: TrueColor gt.ncolors=%d base=%d\n",
+ w->gterm.ncolors, w->gterm.base_pixel);
+
+ nitems = MAX_SZCMAP;
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+
+ /* Get a private colormap.
+ */
+ for (i=0; i < MAX_SZCMAP; i++)
+ colors[i].pixel = i;
+
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, w->gterm.base_pixel + i - SZ_STATIC_CMAP);
+
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "\n\nget_colormap: gt.ncolors = %d maxcols = %d\n\n\n",
+ w->gterm.ncolors, w->gterm.maxColors);
+
+ goto use_default;
+
+ } else {
+ /* Create or reinitialize a global colormap.
+ */
+ XVisualInfo template, *vi;
+ Display *d;
+ Screen *s;
+ Window root;
+ long mask;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "get_colormap: ...creating colormap, ncols=%d\n",
+ w->gterm.ncolors);
+
+
+ if (!(d = XOpenDisplay (DisplayString(display))))
+ goto use_default;
+ s = DefaultScreenOfDisplay (d);
+ root = DefaultRootWindow (d);
+
+ /* Try to get a pseudocolor visual. */
+ mask = 0;
+ template.screen = DefaultScreen(d); mask |= VisualScreenMask;
+ template.depth = RasterDepth; mask |= VisualDepthMask;
+ template.class = PseudoColor; mask |= VisualClassMask;
+
+ if (!(vi = XGetVisualInfo (d, mask, &template, &nitems))) {
+ XCloseDisplay (d);
+ goto use_default;
+ }
+
+ /* Create custom colormap with all cells allocated read/write */
+ colormap = XCreateColormap (d, root, vi->visual, AllocAll);
+
+ /* Initialize colormap to be same as default colormap. */
+ nitems = min (MAX_SZCMAP, CellsOfScreen(s));
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (d, DefaultColormapOfScreen(s), colors, nitems);
+ XStoreColors (d, colormap, colors, nitems);
+
+ /* Globally define permanent server custom colormap. */
+ memset ((char *)&cm, 0, sizeof(cm));
+ cm.colormap = colormap;
+ cm.base_pixel = w->gterm.base_pixel;
+ cm.red_max = 0;
+ cm.visualid = vi->visualid;
+ cm.killid = 1;
+ XSetRGBColormaps (d, root, &cm, 1, atom);
+
+ XSetCloseDownMode (d, RetainPermanent);
+ XCloseDisplay (d);
+ w->gterm.cmapInitialize = False;
+
+ /* Free the XVisualInfo struct. */
+ if (vi)
+ XFree ((void *)vi); /* MF040 */
+
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_colormap: .............creating done\n");
+ }
+
+ /* Save default color assignments for static colors. */
+ for (i=0; i < SZ_STATIC_CMAP; i++)
+ def_colors[i] = w->gterm.color[i];
+
+ nitems = min (MAX_SZCMAP, CellsOfScreen(screen));
+ w->gterm.ncolors = SZ_STATIC_CMAP + w->gterm.maxColors;
+ base_pixel = w->gterm.base_pixel;
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,
+ "\n\nget_colormap: gt.ncolors = %d maxcols = %d\n\n\n",
+ w->gterm.ncolors, w->gterm.maxColors);
+
+ /* Get the private colormap. */
+ for (i=0; i < nitems; i++)
+ colors[i].pixel = i;
+ XQueryColors (display, colormap, colors, nitems);
+
+ /* Initialize the raster pixel to display pixel mapping and set the
+ * color assigned to each pixel value in the private colormap.
+ */
+ for (i = SZ_STATIC_CMAP; i < w->gterm.ncolors; i++) {
+ w->gterm.color[i].pixel = w->gterm.cmap[i] = pixel =
+ min (nitems - 1, base_pixel + i - SZ_STATIC_CMAP);
+ w->gterm.color[i] = colors[pixel];
+ }
+
+ /* Check the static part of the cmap to make sure that the pixel numbers
+ * aren't aliased to pixels in the dynamic part of the custom colormap.
+ * If this happens, reassign these color numbers to the pixels just
+ * preceeding the dynamic part of the custom colormap. The red_max
+ * field of the colormap descriptor is used to keep track of the number
+ * of static colors allocated by different clients. These static colors
+ * are shared, hence the same color will not be stored twice.
+ */
+ p1 = p2 = base_pixel - cm.red_max;
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ pixel = w->gterm.cmap[i];
+ if (pixel >= base_pixel && pixel < base_pixel+DEF_MAXCOLORS && p1 > 2) {
+ /* First check to see if we already have a static entry reserved
+ * for this color.
+ */
+ c1 = &def_colors[i];
+ for (j=p1, cp=NULL; j < base_pixel; j++) {
+ c2 = &colors[j];
+ if (c1->red == c2->red && c1->green == c2->green &&
+ c1->blue == c2->blue) {
+ cp = c2;
+ break;
+ }
+ }
+
+ /* Assign a new screen pixel value. */
+ if (cp)
+ w->gterm.cmap[i] = cp->pixel;
+ else {
+ cp = &colors[--p1];
+ *cp = def_colors[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = w->gterm.cmap[i] = p1;
+ cm.red_max++;
+ }
+ w->gterm.color[i].pixel = w->gterm.cmap[i];
+ }
+ }
+ if (p1 < p2) {
+ XStoreColors (display, colormap, &colors[p1], p2 - p1);
+ XSetRGBColormaps (display, w->gterm.root, &cm, 1, atom);
+ }
+
+ /* Assign the new colormap to the gterm widget's window. */
+ XtVaSetValues ((Widget)w, XtNcolormap, (XtArgVal)colormap, NULL);
+ w->gterm.haveColormap++;
+
+ /* If the pointer is in the window, advise window manager to load the
+ * colortable for the window.
+ */
+ if (w->gterm.in_window)
+ request_colormap_focus (w);
+
+ return (colormap);
+
+use_default:
+ /* Unable to create custom colormap. */
+ w->gterm.useDefaultCM++;
+ w->gterm.haveColormap++;
+ return (w->core.colormap);
+}
+
+
+/* request_colormap_focus -- Modify the WM_COLORMAP_WINDOWS property on a
+ * widget's top level shell window to advise the window manager that the
+ * widget's window should have its colormap loaded. This should only be
+ * used for windows that have a colormap different than that of the top
+ * level window.
+ */
+static
+request_colormap_focus (w)
+ GtermWidget w;
+{
+ Widget p;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Find the top level window. */
+ for (p = XtParent(w); !XtIsShell(p); p = XtParent(p))
+ ;
+
+ /* Modify WM_COLORMAP_WINDOWS to give the current window priority.
+ */
+ if (p) {
+ Window window = XtWindow (p);
+ Window *wl = NULL, n_wl[MAX_WMWIN+1];
+ register int n_nw, i;
+ int nw;
+
+ /* If WM_COLORMAP_WINDOWS is already set save its value, otherwise
+ * start a list initially containing only the top level window.
+ */
+ w->gterm.wmTop = window;
+ if (XGetWMColormapWindows (w->gterm.display, window, &wl, &nw)) {
+ memmove (w->gterm.wmWindows, (char *)wl, nw * sizeof(int));
+ w->gterm.n_wmWindows = nw = min (nw, MAX_WMWIN);
+ free ((char *)wl);
+ } else {
+ w->gterm.wmWindows[0] = window;
+ w->gterm.n_wmWindows = nw = 1;
+ }
+
+ n_nw = 0;
+ wl = w->gterm.wmWindows;
+ n_wl[n_nw++] = XtWindow(w);
+
+ for (i=0; i < nw; i++)
+ if (wl[i] != XtWindow(w))
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, window, n_wl, n_nw);
+ }
+}
+
+
+/* restore_colormap_focus -- Reset WM_COLORMAP_WINDOWS. Retain the window
+ * that had the focus in the list, but drop its priority one notch. This
+ * should follow a prior call to request_colormap_focus.
+ */
+static
+restore_colormap_focus (w)
+ GtermWidget w;
+{
+ register int nw, n_nw, i;
+ Window *wl, n_wl[MAX_WMWIN+1], old;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ old = XtWindow(w);
+ wl = w->gterm.wmWindows;
+ if ((nw = w->gterm.n_wmWindows) == 0 || (nw == 1 && wl[0] == old))
+ return;
+
+ n_nw = 0;
+ if (wl[0] != old)
+ n_wl[n_nw++] = wl[0];
+ n_wl[n_nw++] = old;
+
+ for (i=1; i < nw; i++)
+ if (wl[i] != old)
+ n_wl[n_nw++] = wl[i];
+
+ XSetWMColormapWindows (w->gterm.display, w->gterm.wmTop, n_wl, n_nw);
+}
+
+
+/* inherit_default_colormap -- Set any unused cells of the custom colormap
+ * to the colors defined for the corresponding cells of the default colormap.
+ * This minimizes colormap flashing when using a custom colormap, but only
+ * works if a few unused cells can be reserved, e.g., at the beginning of
+ * the colormap (which is usually where X allocates its colors).
+ */
+static
+inherit_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *cp, *ap;
+ register int ncolors, i;
+ Display *display = w->gterm.display;
+ Screen *screen = w->gterm.screen;
+ Window root = w->gterm.root;
+ Atom atom = w->gterm.cmapAtom;
+ XColor colors[MAX_SZCMAP];
+ XStandardColormap *cm;
+ int first, nitems, ncmap;
+
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "inherit_default_cmap: ncols=%d maxcols=%d base=%d\n",
+ w->gterm.ncolors, w->gterm.maxColors, w->gterm.base_pixel);
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.base_pixel <= 0)
+ return; /* fully allocated colormap */
+
+ /* We have to read the colormap property again as another client could
+ * have reserved more static colors (i.e.,changed red_max), and we don't
+ * want to clobber these colors.
+ */
+ if (XGetRGBColormaps (display, root, &cm, &ncmap, atom)) {
+ /* Make sure we have the right colormap. */
+ if (w->core.colormap != cm->colormap)
+ XtVaSetValues ((Widget)w,XtNcolormap,(XtArgVal)cm->colormap,NULL);
+
+ /* Get lower part of default colormap. */
+ ncolors = cm->base_pixel - cm->red_max;
+ for (cp=colors, i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = i;
+ }
+
+ /* Get upper part of default colormap. */
+ first = cm->base_pixel + w->gterm.ncolors - SZ_STATIC_CMAP;
+ ncolors = min (MAX_SZCMAP, CellsOfScreen(screen)) - first;
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ cp->pixel = first + i;
+ }
+
+ /* Inherit values from default colormap. */
+ ncolors = cp - colors;
+ XQueryColors (display, DefaultColormapOfScreen(screen),
+ colors, ncolors);
+ XStoreColors (display, w->core.colormap, colors, ncolors);
+
+ /* The global gterm colormap may have changed. Compare widget's
+ * version of color table with the global colortable and update
+ * the widget's state if the global colortable has changed.
+ */
+ ncolors = w->gterm.ncolors;
+ memmove (colors, w->gterm.color, ncolors * sizeof(*cp));
+ XQueryColors (display, w->core.colormap, colors, ncolors);
+ for (i=ncolors, cp=colors, ap=w->gterm.color; --i >= 0; cp++, ap++)
+ if (cp->red != ap->red || cp->green != ap->green ||
+ cp->blue != ap->blue) {
+ memmove (w->gterm.color, colors, ncolors * sizeof(*cp));
+ invalidate_cmap (w);
+ }
+
+ } else {
+ if (DBG_TRACE)
+ fprintf (stderr, "inherit_default_cmap: else XGetRGBColormaps\n");
+ }
+}
+
+
+/* update_default_colormap -- Update the default colormap so that any
+ * unallocated cells mirror the widget's custom colormap. This increases
+ * the chance that the widget's contents will be visible when the window
+ * does not have the colormap focus, and minimizes flashing when the
+ * colormap focus changes.
+ */
+static
+update_default_colormap (w)
+ GtermWidget w;
+{
+ register XColor *ip, *op;
+ register int j, n;
+ register Pixel v;
+
+ XColor colors[MAX_SZCMAP];
+ Pixel pixels[MAX_SZCMAP];
+ char allocated[MAX_SZCMAP];
+ int overflow, req, need, first, nelem, i;
+ unsigned long plane_masks[1];
+ Colormap defcmap;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap)
+ return;
+ if (w->gterm.useGlobalCmap) /* 24-bit */
+ return;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "update_def_colormap: ENTER\n");
+
+ first = SZ_STATIC_CMAP;
+ nelem = w->gterm.ncolors;
+
+ defcmap = DefaultColormapOfScreen (w->gterm.screen);
+ /* need = min (MAX_SZCMAP, first + nelem - SZ_STATIC_CMAP); */
+ need = MAX_SZCMAP;
+
+ /* Get the colormap cells. */
+ for (req=need, n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, defcmap, False,
+ plane_masks, 0, &pixels[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Perform the color matching. This is awkward as the pixel value
+ * assignments may be different in the two colormaps. We have to look
+ * up each pixel before attempting to assign a color, or XStoreColors
+ * below will result in a server error.
+ */
+ memset (allocated, 0, sizeof(allocated));
+ overflow = 0;
+
+ for (i=0; i < n; i++) {
+ v = pixels[i];
+ if (v < MAX_SZCMAP)
+ allocated[v] = 1;
+ else {
+ overflow++;
+ break;
+ }
+ }
+
+ ip = &w->gterm.color[first];
+ op = colors;
+ if (overflow) {
+ for (i=0; i < nelem; i++, ip++) {
+ for (j=0, v = ip->pixel; j < n; j++) {
+ if (pixels[j] == v) {
+ *op++ = *ip;
+ break;
+ }
+ }
+ }
+ } else {
+ for (j=0; j < nelem; j++, ip++) {
+ if (allocated[ip->pixel]) {
+ allocated[ip->pixel] = 0;
+ *op++ = *ip;
+ }
+ }
+ }
+
+ if (op > colors)
+ XStoreColors (w->gterm.display, defcmap, colors, op - colors);
+
+ if (!w->gterm.useGlobalCmap)
+ XFreeColors (w->gterm.display, defcmap, pixels, n, 0);
+
+done:
+ if (DBG_TRACE)
+ fprintf (stderr, "update_def_colormap: LEAVING\n");
+}
+
+
+
+
+/* Global Colormap routines.
+ */
+static int SetGlobalCmap(w)
+ GtermWidget w;
+{
+ static int init=0;
+
+ if( !init ){
+ strcpy (global_cmapname, XtNcmapName);
+ global_ncolors = 0;
+ global_mincolors = 0;
+ init = 1;
+ }
+ if( !w->gterm.useGlobalCmap ){
+ w->gterm.cmap = (Pixel *)XtCalloc(MAX_SZCMAP, sizeof(Pixel));
+ w->gterm.color = (XColor *)XtCalloc(MAX_SZCMAP, sizeof(XColor));
+
+ return(0);
+
+ } else{
+ w->gterm.cmap = global_cmap;
+ w->gterm.color = global_color;
+
+ return(global_ncolors);
+ }
+}
+
+
+static int ParseGlobalCmap(w)
+ GtermWidget w;
+{
+ char *s;
+ char *t;
+ char *cmapname;
+ int colors;
+ int usedefault=0;
+
+ /* process a directive such as "default[n:m,name]", where
+ * n = min number of colors that must be allocated or else
+ * use a private map called "name". m is the max colors to
+ * allocate (same as maxColors). Either or both can be omitted
+ */
+ cmapname = w->gterm.cmapName;
+ if( !strncmp (cmapname, "default", 7) ){
+ usedefault = 1;
+ if( (s=strchr(cmapname,'[')) != NULL ){
+ /* skip open bracket */
+ s++;
+ /* get min number of colors */
+ global_mincolors = strtol(s, &t, 10);
+ /* for n:m syntax, get max colors */
+ if( *t == ':' ){
+ s = ++t;
+ colors = strtol(s, &t, 10);
+ if( colors > 0 )
+ w->gterm.maxColors = colors;
+ }
+ /* look for default name */
+ if( *t == ',' ){
+ t++;
+ }
+ s = t;
+ /* this is the new name of the cmap -- but it can't be "default"! */
+ if( (strncmp(s, "default", 7)) && (*s != ']') ){
+ strcpy(global_cmapname, s);
+ /* null out closing bracket */
+ if( (s = strchr(global_cmapname, ']')) != NULL )
+ *s = '\0';
+ }
+ /* now make sure we can grab the min number of colors,
+ or else set up to use a private color map */
+ colors = GetMaxCmapColors(w);
+ if( colors < global_mincolors ){
+ usedefault = 0;
+ w->gterm.haveColormap = 0;
+ strcpy(w->gterm.cmapName, global_cmapname);
+ }
+ else{
+ w->gterm.maxColors = min(w->gterm.maxColors, colors);
+ }
+ }
+ }
+ return(usedefault);
+}
+
+/*
+ *
+ * GetMaxCmapColors -- try to determine how many colors we can alloc in the
+ * default colormap. We do this now in order set maxColors to this number,
+ * to avoid the situation where a larger colormap is used that repeats
+ * the actually-allocated colormap -- very ugly ...
+ *
+ */
+static int GetMaxCmapColors(w)
+ GtermWidget w;
+{
+ register int n;
+ unsigned long plane_masks[1];
+ int req;
+ int first, nelem, maxelem;
+ Pixel cmap[MAX_SZCMAP];
+ Display *dpy;
+ Colormap colormap;
+ Visual *visual;
+ int screen;
+
+
+ dpy = XtDisplay(w);
+ screen = XDefaultScreen(dpy);
+ visual = XDefaultVisual(dpy, screen);
+ colormap = XDefaultColormap(dpy, screen);
+
+ /* Make sure we have the right sort of visual.
+ */
+ if (visual->class == TrueColor)
+ return (global_ncolors);
+
+ if ((visual->class != PseudoColor) && (visual->class != GrayScale))
+ return (0);
+
+ /* Get current colormap specs.
+ */
+ GtQueryColormap (w, 0, &first, &nelem, &maxelem);
+
+ /* Try to alloc the max size colormap.
+ */
+ if (maxelem > 0) {
+ req = min(MAX_SZCMAP, maxelem);
+ for (n=0; req > 0 && n < maxelem; ){
+ if (XAllocColorCells (dpy, colormap,
+ False, plane_masks, 0, &cmap[n], req)) {
+ n += req;
+ } else
+ req /= 2;
+ }
+
+ /* just wondering ... don't really need this.
+ */
+ if (! w->gterm.useGlobalCmap)
+ XFreeColors (dpy, colormap, cmap, n, 0);
+
+ } else
+ n = 0;
+
+ return (n);
+}
+
+
+static int
+GetGlobalColors()
+{
+ return (global_ncolors);
+}
+
+
+static void
+SetGlobalColors(n)
+ int n;
+{
+ global_ncolors = n;
+}
+
+
+/*
+ * This routine will search the STATIC colors of w->core.colormap to find an
+ * exact match for the color name. If no match is found, the foreground is
+ * returned.
+ */
+
+static Pixel
+ColorNameToPixel (w, str)
+GtermWidget w;
+String str;
+{
+ int i;
+ XColor color;
+ XColor cmap[SZ_STATIC_CMAP];
+ char *ip, *op, name[32];
+ unsigned long r, g, b;
+ unsigned long val = 0;
+
+
+
+ bzero (cmap, (SZ_STATIC_CMAP * sizeof(XColor)));
+ if (!str)
+ return (0);
+
+ if (w->gterm.w_depth > ColormapDepth && w->gterm.useGlobalCmap) {
+ bzero (name, 32);
+ for (ip=str, op=name; ip && *ip; )
+ *op++ = (char) tolower ((int)*ip++);
+
+
+ for (i=0; i < (SZ_STATIC_CMAP + SZ_OVERLAY_CMAP); i++) {
+ if (strcmp (name, static_colors[i].name) == 0) {
+ r = ((uchar)static_colors[i].r & 0xff) << 16;
+ g = ((uchar)static_colors[i].g & 0xff) << 8;
+ b = ((uchar)static_colors[i].b & 0xff);
+ val = static_colors[i].value;
+ break;
+ }
+ }
+ return (val);
+
+ } else {
+ /* Find what colors are available... */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ memset (&cmap[i], 0, sizeof(XColor));
+ cmap[i].pixel = i;
+ cmap[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ XQueryColors(w->gterm.display, w->core.colormap, cmap, SZ_STATIC_CMAP);
+
+ /* ...and find a match */
+ if (XParseColor(w->gterm.display, w->core.colormap, str, &color)) {
+ for (i=0; i<SZ_STATIC_CMAP; i++) {
+ if ((color.red == cmap[i].red) &&
+ (color.green == cmap[i].green) &&
+ (color.blue == cmap[i].blue)) {
+ return i;
+ }
+ }
+ }
+
+ }
+
+ return 1;
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/GtermCnv.c b/vendor/x11iraf/obm/ObmW/GtermCnv.c
new file mode 100644
index 00000000..47119bb6
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermCnv.c
@@ -0,0 +1,486 @@
+
+/* Convenience macros.
+*/
+#define GPMtoRPM gtermPM_to_rasPM /* Pixmap */
+#define RPMtoRPM rasPM_to_rasPM /* Pixmap */
+#define RPMtoGPM rasPM_to_gtermPM /* Pixmap */
+
+#define IMGtoGPM ximage_to_gtermPM /* XImage */
+#define IMGtoRPM ximage_to_rasPM /* XImage */
+
+
+Pixmap gtermPM_to_rasPM (GtermWidget w, Raster dest);
+Pixmap rasPM_to_rasPM (Raster src, Raster dest);
+Pixmap rasPM_to_gtermPM (Raster src, GtermWidget w);
+
+XImage *ximage_to_gtermPM (GtermWidget w, XImage *xin,
+ int sx, int sy, int dnx, int dny);
+XImage *ximage_to_rasPM (GtermWidget w, XImage *xin, Raster dest,
+ int sx, int sy, int dnx, int dny);
+
+
+
+
+
+
+/* Match the destination pixmap to the Gterm pixmap. If they are the
+** same depth we can simply return the gterm pixmap, otherwise return
+** a copy of the Gterm pixmap at the dest raster's depth.
+*/
+
+Pixmap gtermPM_to_rasPM (GtermWidget w, Raster dest)
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "GPMtoRPM: %d <-> %d\n", w->gterm.w_depth,dest->depth);
+
+ /* Should be a no-op in 8-bit Pseudocolor mode. */
+ if (w->gterm.w_depth == dest->depth)
+ return (w->gterm.pixmap);
+}
+
+
+/* Match the raster pixmap to another raster pixmap. If they are the
+** same depth we can simply return the src pixmap, otherwise render the
+** src pixmap to match the destination depth.
+*/
+
+Pixmap rasPM_to_rasPM (Raster src, Raster dest)
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "RPMtoRPM: %d <-> %d\n", src->depth, dest->depth);
+
+ /* Should be a no-op in 8-bit Pseudocolor mode. */
+ if (src->depth == dest->depth)
+ return (src->r.pixmap);
+
+
+ if (src->depth < dest->depth) {
+ fprintf (stderr, "RPMtoRPM: %d < %d\n", src->depth, dest->depth);
+ ;
+ } else if (src->depth > dest->depth) {
+ fprintf (stderr, "RPMtoRPM: %d > %d\n", src->depth, dest->depth);
+ ;
+ }
+}
+
+
+/* Match the raster pixmap to the Gterm pixmap. If they are the
+** same depth we can simply return the raster pixmap, otherwise render the
+** raster pixmap to match the Gterm pixmap depth.
+*/
+
+Pixmap rasPM_to_gtermPM (Raster src, GtermWidget w)
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "RPMtoGPM: %d <-> %d\n", src->depth, w->gterm.w_depth);
+
+
+ /* Should be a no-op in 8-bit Pseudocolor mode. */
+ if (src->depth == w->gterm.w_depth)
+ return (src->r.pixmap);
+
+
+ if (src->depth < w->gterm.w_depth) {
+ fprintf (stderr, "RPMtoRPM: %d < %d\n", src->depth, w->gterm.w_depth);
+ ;
+ } else if (src->depth > w->gterm.w_depth) {
+ fprintf (stderr, "RPMtoRPM: %d > %d\n", src->depth, w->gterm.w_depth);
+ ;
+ }
+}
+
+
+
+/* Match the input XImage to match the raster pixmap. If they are the
+** same depth we can simply return the input ximage, otherwise return an
+** ximage at the proper depth.
+*/
+
+XImage *ximage_to_rasPM (GtermWidget w, XImage *xin, Raster dest,
+ int sx, int sy, int dnx, int dny)
+{
+ uchar *renderPixels ();
+ XImage *cnvImg = (XImage *) NULL;
+
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "IMGtoRPM: %d <-> %d [%d,%d] cnvImg=0x%x\n",
+ xin->depth, dest->depth, xin->width, xin->height, cnvImg);
+ fprintf (stderr, "IMGtoRPM: Map: (%d,%d) : %d %d\n",
+ sx, sy, dnx, dny);
+ }
+
+
+ /* Should be a no-op in 8-bit Pseudocolor mode. */
+ if (xin->depth == dest->depth)
+ return (xin);
+
+ if (xin->depth < dest->depth) { /* e.g. 8 -> 24 */
+
+ cnvImg = XCreateImage (w->gterm.display, NULL, RGBDepth,
+ ZPixmap, 0, (char *) NULL, xin->width, xin->height, 32, 0);
+
+ cnvImg->data =
+ (char *) renderPixels (w, xin->data, xin->width, xin->height,
+ dest->depth, sx, sy, dnx, dny, cnvImg->bytes_per_line,
+ cnvImg->bits_per_pixel, cnvImg->byte_order);
+
+ return (cnvImg);
+
+ } else if (xin->depth > dest->depth) { /* shouldn't happen... */
+ if (DBG_TRACE)
+ fprintf (stderr, "IMGtoRPM: shouldn't be here...\n");
+ ;
+ }
+
+ return ((XImage *) NULL);
+}
+
+
+/* Match the destination pixmap to the Gterm pixmap. If they are the
+** same depth we can simply return the dest pixmap, otherwise render the
+** gterm pixmap to match the destination.
+*/
+
+XImage *ximage_to_gtermPM (GtermWidget w, XImage *xin,
+ int sx, int sy, int dnx, int dny)
+{
+ uchar *renderPixels ();
+ XImage *cnvImg = (XImage *) NULL;
+
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "IMGtoGPM: %d <-> %d [%d,%d]\n",
+ xin->depth, w->gterm.w_depth, xin->width, xin->height);
+ fprintf (stderr, "IMGtoGPM: Map: (%d,%d) : %d %d\n",
+ sx, sy, dnx, dny);
+ }
+
+
+ /* Should be a no-op in 8-bit Pseudocolor mode. */
+ if (xin->depth == w->gterm.w_depth)
+ return (xin);
+
+ if (xin->depth < w->gterm.w_depth) { /* e.g. 8 -> 24 */
+
+ cnvImg = XCreateImage (w->gterm.display, NULL, w->gterm.w_depth,
+ ZPixmap, 0, (char *) NULL, xin->width, xin->height, 32, 0);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "IMGtoGPM: bpl=%d bpp=%d border=%d\n",
+ cnvImg->bytes_per_line, cnvImg->bits_per_pixel,
+ cnvImg->byte_order);
+
+ cnvImg->data =
+ (char *) renderPixels (w, xin->data, xin->width, xin->height,
+ w->gterm.w_depth, sx, sy, dnx, dny, cnvImg->bytes_per_line,
+ cnvImg->bits_per_pixel, cnvImg->byte_order);
+
+ return (cnvImg);
+
+ } else if (xin->depth > w->gterm.w_depth) { /* shouldn't happen... */
+ if (DBG_TRACE)
+ fprintf (stderr, "IMGtoGPM: shouldn't be here...\n");
+ }
+
+ return ((XImage *) NULL);
+}
+
+
+/* Render the 8-bit image pixels to the specified depth. We'll allocate
+** the pointer to the output pixels and assume the caller will free it.
+*/
+uchar *
+renderPixels (w, in, width, height, depth, sx, sy, dnx, dny, bpl, bpp, border)
+GtermWidget w;
+uchar *in;
+int width, height, depth;
+int sx, sy, dnx, dny;
+int bpl, bpp, border;
+{
+ register int i, j, npix = (width * height);
+ unsigned long *lp, xcol, lval;
+ int nbytes = ((depth == ColormapDepth) ? 1 : 4);
+ uchar *ip = in, pv;
+ uchar *img = (uchar *) NULL;
+
+ int min=256, max=0, cmin=256, cmax=0, xmin=0, xmax=0;
+ time_t start, end;
+
+
+
+ if (DBG_TRACE) {
+ start = time ((time_t) NULL);
+ fprintf (stderr, "renderPix: ENTER\n");
+ }
+
+ /* Compute the lookup table for the most recent offset/scale. If this
+ ** hasn't changed, this is a no-op.
+ */
+ if (init_lut (bpp, border) != OK)
+ return ((uchar *) NULL);
+
+ /* Allocate the new image data. The bytes-per-line might be larger than
+ ** the indicated width, so use that for the size.
+ */
+ img = (uchar *) calloc ((size_t) 1, (size_t) (bpl * height));
+
+
+ /* Here we render only the pixels in the src rect, leaving the remainder
+ ** of the output XImage blank. The idea is that we process only what
+ ** will be visible on the screen, the input XImage still contains all the
+ ** off-screen pixels.
+ */
+ ip = &in[sy * width + sx];
+ lp = (unsigned long *) img;
+ lp += sy * width + sx;
+ for (i=0; i < dny; i++) {
+ for (j=0; j < dnx; j++)
+ *lp++ = global_lut[*ip++];
+
+ ip += (width - dnx); /* advance to next line of rect */
+ lp += (width - dnx);
+ }
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "renderPix: pix %d %d cmap %d %d xcol 0x%x 0x%x bpp = %d\n",
+ min,max, cmin,cmax, xmin,xmax, bpp);
+ end = time ((time_t) NULL);
+ fprintf (stderr, "renderPix: DONE time = %.5f %ld %ld\n",
+ difftime(start,end), (long)start, (long)end);
+ }
+
+ return (img);
+}
+
+
+/* Compute the lookup table for the RGB rendering.
+*/
+init_lut (bpp, border)
+int bpp;
+int border;
+{
+ register int i;
+ unsigned long rmask, gmask, bmask, rpix, gpix, bpix, xcol, lval;
+ int rshift, gshift, bshift, nbytes;
+ uchar *op, pv;
+
+
+ if (valid_lut)
+ return (OK);
+
+ /* Compute various shifting constants that we'll need.
+ */
+ switch (bpp) { /* should really get this from Visual */
+ case 32:
+ case 24:
+ rmask = 0xff0000; gmask = 0xff00; bmask = 0xff;
+ rshift = -16; gshift = -8; bshift = 0;
+ nbytes = 4;
+
+ /* Create the lookup table.
+ */
+ bzero (global_lut, sizeof(long) * MAX_SZCMAP);
+ for (i=0; i < MAX_SZCMAP; i++) {
+ pv = global_cmap[i + SZ_STATIC_CMAP];
+
+ /* Get the color components.
+ */
+ rpix = global_color[pv].red >> 8;
+ gpix = global_color[pv].green >> 8;
+ bpix = global_color[pv].blue >> 8;
+
+ /* Shift and mask.
+ */
+ rpix = (rpix << (-rshift)) & rmask;
+ gpix = (gpix << (-gshift)) & gmask;
+ bpix = (bpix << (-bshift)) & bmask;
+
+ /* Create the pixel and load the LUT.
+ */
+ xcol = rpix | gpix | bpix;
+
+ op = (unsigned char *) &lval;
+ if (border == MSBFirst) {
+ *op++ = (xcol>>24) & 0xff;
+ *op++ = (xcol>>16) & 0xff;
+ *op++ = (xcol>>8) & 0xff;
+ *op++ = xcol & 0xff;
+ } else {
+ *op++ = xcol & 0xff;
+ *op++ = (xcol>>8) & 0xff;
+ *op++ = (xcol>>16) & 0xff;
+ *op++ = (xcol>>24) & 0xff;
+ }
+ global_lut[i] = lval;
+ }
+ break;
+ case 16:
+ rmask = 0x1f0000; gmask = 0x1f00; bmask = 0x1f;
+ rshift = -16; gshift = -8; bshift = 0;
+ nbytes = 2;
+
+ /* FIXME */
+ break;
+ case 15:
+ rmask = 0x1f0000; gmask = 0x1f00; bmask = 0x1f;
+ rshift = -10; gshift = -5; bshift = 0;
+ nbytes = 2;
+
+ /* FIXME */
+ break;
+ case 8:
+ /* FIXME */
+ break;
+ default:
+ valid_lut = 0;
+ return (ERR);
+ }
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "init_lut: mask=(0x%x,0x%x,0x%x) shift=(%d,%d,%d)\n",
+ rmask, gmask, bmask, rshift, gshift, bshift);
+
+ valid_lut = 1;
+ return (OK);
+}
+
+
+/* Find highest one bit set.
+** Returns bit number + 1 of highest bit that is set, otherwise returns 0.
+** High order bit is 31 (or 63 in _LP64 kernel).
+*/
+int highbit(unsigned long i)
+{
+ register int h = 1;
+ if (i == 0)
+ return (0);
+#ifdef _LP64
+ if (i & 0xffffffff00000000ul) { h += 32; i >>= 32; }
+#endif
+ if (i & 0xffff0000) { h += 16; i >>= 16; }
+ if (i & 0xff00) { h += 8; i >>= 8; }
+ if (i & 0xf0) { h += 4; i >>= 4; }
+ if (i & 0xc) { h += 2; i >>= 2; }
+ if (i & 0x2) { h += 1; }
+
+ return (h);
+}
+
+
+/* Find lowest one bit set.
+** Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
+** Low order bit is 0.
+*/
+int lowbit(unsigned long i)
+{
+ register int h = 1;
+
+ if (i == 0)
+ return (0);
+
+#ifdef _LP64
+ if (!(i & 0xffffffff)) { h += 32; i >>= 32; }
+#endif
+ if (!(i & 0xffff)) { h += 16; i >>= 16; }
+ if (!(i & 0xff)) { h += 8; i >>= 8; }
+ if (!(i & 0xf)) { h += 4; i >>= 4; }
+ if (!(i & 0x3)) { h += 2; i >>= 2; }
+ if (!(i & 0x1)) { h += 1; }
+
+ return (h);
+}
+
+
+/* Debug Utilities.
+*/
+bob() { int i = 0; fprintf (stderr, "Hi from Bob\n"); }
+
+dbg_printCmaps (GtermWidget w)
+{
+ int i, j, first, nelem, maxelem, nc;
+ unsigned short r[256], g[256], b[256];
+ unsigned short rs[256], gs[256], bs[256], iomap[256];
+
+
+ bzero (r, (256*sizeof(short)));
+ bzero (g, (256*sizeof(short)));
+ bzero (b, (256*sizeof(short)));
+ bzero (rs, (256*sizeof(short)));
+ bzero (gs, (256*sizeof(short)));
+ bzero (bs, (256*sizeof(short)));
+ bzero (iomap,(256*sizeof(short)));
+
+ /* Get the current colormap and iomap.
+ */
+ GtQueryColormap (w, 0, &first, &nelem, &maxelem);
+ nc = GtReadColormap (w, 0, 0, MAX_SZCMAP, rs, gs, bs);
+ GtReadIomap (w, iomap, 0, MAX_SZCMAP);
+
+ fprintf (stderr, "cmaps: first=%d nelem=%d max=%d nc=%d\n",
+ first, nelem, maxelem, nc);
+ fprintf (stderr, "cmaps: basePixel=%d maxColors=%d ncolors=%d\n",
+ w->gterm.base_pixel, w->gterm.maxColors, w->gterm.ncolors);
+
+
+ for (i=0; i < nc; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8); g[i] = (gs[j] >> 8); b[i] = (bs[j] >> 8);
+ }
+ for (i=nc; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8); g[i] = (gs[j] >> 8); b[i] = (bs[j] >> 8);
+ }
+
+ fprintf (stderr, "cmap: idx iomap ReadColormap UserColormap ");
+ fprintf (stderr, "GlobalCmap cm in out\n");
+ for (i=0; i < MAX_SZCMAP; i++)
+ fprintf (stderr,
+ "cmap: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
+ i, iomap[i], rs[i]>>8, gs[i]>>8, bs[i]>>8, r[i], g[i], b[i],
+ global_color[i].red>>8, global_color[i].green>>8,
+ global_color[i].blue>>8, global_cmap[i],
+ w->gterm.cmap_in[i], w->gterm.cmap_out[i]);
+}
+
+dbg_printMappings (GtermWidget w)
+{
+ Mapping mp;
+ char *scales[] = {"noScale", "zoom", "intZoom", "deZoom"};
+
+ for (mp=w->gterm.mp_head; mp; mp = mp->next) {
+ fprintf (stderr, "Map %2d: src=%d ty=%s s=(%d,%d) n=(%d,%d)\n",
+ mp->mapping, mp->src, (mp->st == GtPixel ? "GtPixel" : "GtNDC"),
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (stderr, " : dst=%d ty=%s s=(%d,%d) n=(%d,%d)\n",
+ mp->dst, (mp->dt == GtPixel ? "GtPixel" : "GtNDC"),
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ fprintf (stderr, " : rop=%d refresh=%d enabled=%d def=%d %s\n",
+ mp->rop, mp->refresh, mp->enabled, mp->defined,
+ scales[mp->scaling]);
+ fprintf (stderr, " : src=0x%x dst=0x%x pixmap=0x%x\n",
+ (int)&w->gterm.rasters[mp->src], (int)&w->gterm.rasters[mp->dst],
+ (int)&w->gterm.rasters[0]);
+ }
+}
+
+
+dbg_printRasters (GtermWidget w)
+{
+ register int i;
+ Raster rp;
+
+
+ for (i=0; i < w->gterm.nrasters; i++) {
+ rp = &w->gterm.rasters[i];
+
+ fprintf (stderr, "Raster %d: ty=%s size=(%d,%d,%d)\t",
+ i, (rp->type == 1 ? "ximage" : "pixmap"),
+ rp->width, rp->height, rp->depth);
+ fprintf (stderr, ": p=0x%x im=0x%x sh=0x%x\n",
+ rp->r.pixmap, rp->r.ximage, rp->shadow_pixmap);
+ }
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/GtermDebug.c b/vendor/x11iraf/obm/ObmW/GtermDebug.c
new file mode 100644
index 00000000..710cb6af
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermDebug.c
@@ -0,0 +1,23 @@
+
+
+static char *dbg_wSize (GtermWidget w)
+{
+ static char b[32];
+
+ bzero (b, 32);
+ sprintf (b, "%dx%dx%d", w->core.width, w->core.height, w->core.depth);
+ return (b);
+}
+
+
+static char *dbg_visStr (int class)
+{
+ switch (class) {
+ case StaticGray: return ( "StaticGray" );
+ case StaticColor: return ( "StaticColor" );
+ case GrayScale: return ( "GrayScale" );
+ case PseudoColor: return ( "PseudoColor" );
+ case TrueColor: return ( "TrueColor" );
+ default: return ( "unknown" );
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/GtermGraphics.c b/vendor/x11iraf/obm/ObmW/GtermGraphics.c
new file mode 100644
index 00000000..1224d603
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermGraphics.c
@@ -0,0 +1,1474 @@
+
+/*
+ * GRAPHICS routines (public functions).
+ * --------------------------------------
+ */
+
+GtActivate (w)
+ GtermWidget w;
+{
+ w->gterm.interactive = 0;
+ w->gterm.save_x = w->gterm.save_y = 0;
+}
+
+GtDeactivate (w)
+ GtermWidget w;
+{
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+
+ if (w->gterm.interactive) {
+ if (w->gterm.save_x > 0 && w->gterm.save_y > 0) {
+ if (w->gterm.warpCursor) {
+ /* Workaround X server bug. */
+ if (w->gterm.root != w->gterm.save_root)
+ XWarpPointer (display,None,w->gterm.root, 0,0,0,0,
+ WidthOfScreen(w->gterm.screen) - 1,
+ HeightOfScreen(w->gterm.screen) - 1);
+
+ /* Move pointer to saved position. */
+ XWarpPointer (display, None, w->gterm.save_root,
+ 0,0,0,0, w->gterm.save_x, w->gterm.save_y);
+ }
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ }
+ w->gterm.interactive = 0;
+ }
+}
+
+GtReady (w)
+ GtermWidget w;
+{
+ return (w->gterm.delay == 0);
+}
+
+GtReset (w)
+ GtermWidget w;
+{
+ invalidate_draw_context (w);
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapButt, JoinMiter);
+
+ /* Set defaults. */
+ w->gterm.line_width = 1;
+ w->gterm.data_level = GtSet;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.raster = 0;
+}
+
+GtTimerInhibit (w, state)
+ GtermWidget w;
+ Boolean state;
+{
+ /* This is a kludge to allow a client (xgterm) to disable use of timers
+ * if they don't work in a given implementation.
+ */
+ w->gterm.useTimers = !state;
+}
+
+GtAugmentTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_augment;
+ w->gterm.nauxTrans++;
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtOverrideTranslations (w, translations)
+ register GtermWidget w;
+ char *translations;
+{
+ register int i;
+
+ if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = T_override;
+ w->gterm.nauxTrans++;
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ }
+}
+
+GtFlush (w)
+ GtermWidget w;
+{
+ XFlush (w->gterm.display);
+}
+
+GtSetLogRes (w, width, height)
+ GtermWidget w;
+ int width, height;
+{
+ w->gterm.xres = width;
+ w->gterm.yres = height;
+}
+
+GtGetLogRes (w, width, height)
+ GtermWidget w;
+ int *width, *height;
+{
+ *width = w->gterm.xres;
+ *height = w->gterm.yres;
+}
+
+GtGetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster; /* zero for screen size */
+ int *width, *height;
+{
+ if (raster) {
+ register Raster rp = &w->gterm.rasters[raster];
+ *width = rp->width;
+ *height = rp->height;
+ } else {
+ *width = w->core.width;
+ *height = w->core.height;
+ }
+}
+
+GtSetPhysRes (w, raster, width, height)
+ GtermWidget w;
+ int raster;
+ int width, height;
+{
+ GtCreateRaster (w, raster, GtServer, width, height, RasterDepth);
+}
+
+GtSetRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ if (raster >= 0 && raster < w->gterm.maxRasters) {
+ w->gterm.raster = raster;
+ invalidate_draw_context (w);
+ }
+}
+
+GtGetRaster (w)
+ GtermWidget w;
+{
+ return (w->gterm.raster);
+}
+
+/* ARGSUSED */
+GtSetTextRes (w, optrows, optcols)
+ GtermWidget w;
+ int optrows, optcols;
+{
+ w->gterm.optrows = optrows;
+ w->gterm.optcols = optcols;
+}
+
+/* ARGSUSED */
+GtSetCharSize (w, ival)
+ GtermWidget w;
+ int ival;
+{
+}
+
+GtSetDataLevel (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ invalidate_draw_context (w);
+
+ switch (ival) {
+ case GtSet:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ if (w->gterm.useGlobalCmap)
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[w->gterm.color_index].value);
+ else
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[w->gterm.color_index]);
+ w->gterm.data_level = ival;
+ break;
+
+ case GtClear:
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ if (w->gterm.useGlobalCmap)
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[0].value);
+ else
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color0);
+ w->gterm.data_level = ival;
+ break;
+
+ case GtInvert:
+ /* This probably won't work correctly but leave it for now... */
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXxor);
+ w->gterm.data_level = ival;
+ break;
+ }
+}
+
+
+GtSetLineWidth (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ w->gterm.line_width = ival;
+ GtSetLineStyle (w, w->gterm.line_style);
+}
+
+#define Dashed "\010\003"
+#define Dotted "\002\003"
+#define DashDot "\016\003\001\003"
+#define Dash3Dot "\024\003\001\003\001\003\001\003"
+
+GtSetLineStyle (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ int line_width = w->gterm.line_width;
+ int line_style = LineSolid;
+ int cap_style = CapButt;
+ int join_style = JoinMiter;
+ int dash_offset = 0;
+ char *dash_list = NULL;
+ int dash_list_length = 0;
+
+ switch (ival) {
+ case GtSolid:
+ w->gterm.line_style = ival;
+ break;
+ case GtDashed:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dashed;
+ dash_list_length = strlen(Dashed);
+ w->gterm.line_style = ival;
+ break;
+ case GtDotted:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dotted;
+ dash_list_length = strlen(Dotted);
+ w->gterm.line_style = ival;
+ break;
+ case GtDashDot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)DashDot;
+ dash_list_length = strlen(DashDot);
+ w->gterm.line_style = ival;
+ break;
+ case GtDash3Dot:
+ line_style = LineOnOffDash;
+ dash_list = (char *)Dash3Dot;
+ dash_list_length = strlen(Dash3Dot);
+ w->gterm.line_style = ival;
+ break;
+ }
+
+ if (dash_list_length)
+ XSetDashes (w->gterm.display, w->gterm.drawGC, dash_offset, dash_list,
+ dash_list_length);
+
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, line_width, line_style, cap_style, join_style);
+
+ invalidate_draw_context (w);
+}
+
+GtSetColorIndex (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ register int color = w->gterm.iomap[ival];
+
+ if (color >= 0 && color < w->gterm.ncolors) {
+ if (w->gterm.useGlobalCmap) {
+ register int i, found = 0;
+
+ for (i=0; i < num_static_colors; i++) {
+ if (ival == static_colors[i].index) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[i].value);
+ found++;
+ }
+ }
+
+ /* If no match found, set the foreground color as the index.
+ */
+ if (!found) {
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[1].value);
+ }
+ } else
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ w->gterm.cmap[color]);
+ w->gterm.color_index = color;
+ invalidate_draw_context (w);
+ }
+}
+
+GtSetFillType (w, ival)
+ GtermWidget w;
+ int ival;
+{
+ switch (ival) {
+ case GtSolid:
+ case GtOutline:
+ w->gterm.fill_type = ival;
+ break;
+ }
+}
+
+GtClearScreen (w)
+GtermWidget w;
+{
+ register Mapping mp;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap)
+ XFillRectangle (w->gterm.display, w->gterm.pixmap,
+ w->gterm.clearGC, 0, 0, w->core.width, w->core.height);
+ XClearWindow (w->gterm.display, w->gterm.window);
+
+ set_default_color_index (w);
+ XSetFunction (w->gterm.display, w->gterm.drawGC, GXcopy);
+ if (w->gterm.useGlobalCmap)
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[1].value);
+ else
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.color1);
+ XSetLineAttributes (w->gterm.display,
+ w->gterm.drawGC, 1, LineSolid, CapRound, JoinRound);
+
+ w->gterm.line_width = 1;
+ w->gterm.line_style = GtSolid;
+ w->gterm.fill_type = GtSolid;
+ w->gterm.data_level = GtSet;
+ w->gterm.preserve_valid = 0;
+ w->gterm.gm_redisplay = 1;
+ w->gterm.d_saved = 0;
+
+ /* Mark any screen mappings to be unconditionally refreshed. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp->enabled && mp->dst == 0)
+ mp->refresh++;
+
+ invalidate_draw_context (w);
+ update_transients (w, NULL);
+
+ /* Reinitialize the display pixmap shadow.
+ */
+ if (w->gterm.rasters)
+ initialize_shadow_pixmap (w, 0);
+}
+
+GtDrawPolyline (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolymarker (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ /* Add code to support max display request size. */
+ if (mx->use_backing_store)
+ XDrawPoints (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ XDrawPoints (w->gterm.display, mx->pixmap,
+ mx->drawGC, points, npts, CoordModeOrigin);
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawPolygon (w, pv, npts)
+ GtermWidget w;
+ XPoint *pv;
+ int npts;
+{
+ XPoint *points, o_pv[MAX_POINTS];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int i;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+
+ if (w->gterm.fill_type == GtOutline) {
+ /* Draw outline of region.
+ */
+ int first = 0;
+ int last = npts - 1;
+
+ if (mx->use_backing_store)
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+
+ if (points[last].x != points[first].x ||
+ points[last].y != points[first].y) {
+
+ if (mx->use_backing_store)
+ XDrawLine (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ XDrawLine (w->gterm.display, mx->pixmap, mx->drawGC,
+ points[last].x, points[last].y,
+ points[first].x, points[first].y);
+ }
+ } else {
+ /* Fill the outlined area.
+ */
+ if (mx->use_backing_store) {
+ XFillPolygon (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, w->gterm.pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ XFillPolygon (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, Nonconvex, CoordModeOrigin);
+ XDrawLines (w->gterm.display, mx->pixmap, mx->drawGC,
+ points, npts, CoordModeOrigin);
+ }
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtDrawMarker (w, x, y, xsize, ysize, type)
+ GtermWidget w;
+ int x, y;
+ int xsize, ysize;
+ int type;
+{
+}
+
+GtBell (w)
+ GtermWidget w;
+{
+ XBell (w->gterm.display, 0);
+}
+
+
+/* GtSetCursorPos -- Set the cursor position to the given coordinates X,Y.
+ * Coordinates are specified in the current graphics coordinate system,
+ * defined by the current raster and logical resolution.
+ *
+ * This routine is a little more complex than one might think due to the
+ * complication of mappings. Screen coordinates are required to set the
+ * cursor, but the graphics drawing context may be defined relative to
+ * any raster. In the general case a graphics pipeline defines the series
+ * of coordinate transformations required to transform from graphics
+ * coordinates to screen coordinates. Things are further complicated since
+ * the pipeline or desired position may not map to the screen, or there
+ * may be multiple mappings to the screen. The first case (no mapping to
+ * the screen) is dealt with by ignoring the request to warp the cursor.
+ * The second case (one-to-many mapping) is dealt with by a heuristic:
+ * the most recent screen coordinates are unmapped back to the raster we
+ * are "drawing" into, defining a unique path through the mappings which
+ * we can use to map back to the screen.
+ *
+ * The simplest case occurs when we are drawing directly into the screen.
+ * In this case (raster=0) there may still be a logical to physical
+ * coordinate transformation, but there are no mappings to complicate things.
+ */
+GtSetCursorPos (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ register MappingContext mx;
+ register DrawContext dx;
+ register Mapping mp;
+
+ Window window = w->gterm.window;
+ int sv_raster = w->gterm.raster;
+ int sv_xres = w->gterm.xres, sv_yres = w->gterm.yres;
+ int rasters[256], mappings[256], nmap=0, ntrans=0;
+ int rx, ry, src, dst, map, i, npts = 1;
+ int raster = w->gterm.raster;
+ XPoint pv1[1], pv2[2];
+ XPoint *points, pv[1];
+ Raster rp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Follow the current cursor position back to the source raster if
+ * possible. This gives us a default pipeline to follow in the reverse
+ * direction to map raster coordinates to screen coordinates, and is
+ * necessary to find the right mappings when multiple mappings are
+ * defined on a single source.
+ */
+ rx = w->gterm.last_x;
+ ry = w->gterm.last_y;
+ src = 0;
+ do {
+ src = GtSelectRaster (w, dst=src, GtPixel,rx,ry, GtPixel,&rx,&ry,&map);
+ if (src != dst) {
+ rasters[nmap] = src;
+ mappings[nmap++] = map;
+ }
+ } while (src != dst && src != raster);
+
+ /* Ray trace the point through all of the mappings to the screen.
+ * This isn't fully general, but gives us the capability to follow
+ * most graphics pipelines to a point on the screen.
+ */
+ do {
+ GtSetRaster (w, raster);
+ if (ntrans++ || raster == 0) { /* MF041 */
+ /* After the first transformation we have raster coordinates,
+ * so set the logical resolution to the raster dimensions.
+ */
+ rp = &w->gterm.rasters[raster];
+ GtSetLogRes (w, rp->width, rp->height);
+ }
+
+ dx = get_draw_context (w);
+ if (!dx->nmappings)
+ return;
+
+ /* Try to find the next mapping. */
+ if (nmap && rasters[nmap-1] == raster)
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->mapping == mappings[nmap-1]) {
+ mp = mx->mp;
+ nmap--;
+ goto havemap;
+ }
+ }
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ mp = mx->mp;
+ if (mp && mp->dst == 0)
+ break;
+ }
+ if (i >= dx->nmappings) {
+ mx = &dx->mapContext[0];
+ mp = mx->mp;
+ }
+
+havemap:
+ rp = &w->gterm.rasters[mp ? mp->dst : raster];
+
+ /* Compute the coordinates points[0].{x,y} of the point x,y in the
+ * destination raster.
+ */
+ if (mx->scale) {
+ /* Scaling is in effect. The following subterfuge is used to
+ * compute the coordinates of the center of the raster pixel (x,y)
+ * when the image is zoomed. We want to set the cursor to the
+ * center of the selected pixel, not the edge.
+ */
+ pv[0].x = x; pv[0].y = y;
+ mapVector (mx, pv, pv1, npts);
+ pv[0].x = x + 1; pv[0].y = y + 1;
+ mapVector (mx, pv, pv2, npts);
+
+ pv[0].x = (pv1[0].x + pv2[0].x) / 2.0;
+ pv[0].y = (pv1[0].y + pv2[0].y) / 2.0;
+ points = pv;
+
+ } else {
+ /* No scaling. */
+ pv[0].x = x; pv[0].y = y;
+ points = pv;
+ }
+
+ /* Clip to the bounds of the destination raster and generate the
+ * new x,y.
+ */
+ x = max(0, min(rp->width-1, points[0].x));
+ y = max(0, min(rp->height-1, points[0].y));
+
+ } while (mp && (raster = mp->dst));
+
+ XWarpPointer (w->gterm.display, window, window, 0,0,0,0, x,y);
+
+ w->gterm.last_x = w->gterm.cur_x = x;
+ w->gterm.last_y = w->gterm.cur_y = y;
+
+ GtSetRaster (w, sv_raster);
+ GtSetLogRes (w, sv_xres, sv_yres);
+}
+
+
+GtGetCursorPos (w, x, y)
+ GtermWidget w;
+ int *x, *y;
+{
+ *x = w->gterm.last_x;
+ *y = w->gterm.last_y;
+}
+
+GtSetCursorType (w, type)
+ GtermWidget w;
+ int type;
+{
+ static XtIntervalId id = (XtIntervalId) NULL;
+ Display *display = w->gterm.display;
+ Cursor cursor;
+ int interval;
+ Widget pw;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (w->gterm.cursor_type == type)
+ return;
+
+ switch (w->gterm.cursor_type = type) {
+ case GtNoCursor:
+ case GtIdleCursor:
+ erase_crosshair (w);
+ cursor = w->gterm.idle_cursor;
+ break;
+
+ case GtGinmodeCursor:
+ /* Begin graphics cursor mode.
+ */
+
+ /* If a screen clear or drawing operation has caused the redisplay
+ * flag to be set, redisplay any marker overlays.
+ */
+ if (w->gterm.gm_redisplay) {
+ GmRedisplay (w, (Region)NULL);
+ w->gterm.gm_redisplay = False;
+ }
+
+ /* Make sure the window is visible.
+ */
+ if (w->gterm.raiseWindow || w->gterm.deiconifyWindow)
+ for (pw = (Widget)w; pw; pw = XtParent(pw))
+ if (XtIsShell(pw)) {
+ if (w->gterm.deiconifyWindow)
+ XMapWindow (display, XtWindow(pw));
+ if (w->gterm.raiseWindow)
+ XRaiseWindow (display, XtWindow(pw));
+ XSync (display, False);
+ }
+
+ /* The first time this is done after a GtActivate causes the cursor
+ * to be warped into the graphics window. The interactive flag is set
+ * to cause GtDeactivate to restore the cursor to its original position
+ * after the graphics interaction finishes.
+ */
+ if (w->gterm.warpCursor) {
+ int root_x, root_y, win_x, win_y;
+ int xoff, yoff, width, height, x, y;
+ Window gtermwin, root, child;
+ unsigned int keys;
+ int in_window = 0;
+
+ width = w->core.width;
+ height = w->core.height;
+ gtermwin = w->gterm.window;
+ XTranslateCoordinates (display, gtermwin, w->gterm.root,
+ w->core.x, w->core.y, &xoff, &yoff, &child);
+
+ if (XQueryPointer (display, w->gterm.root, &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &keys)) {
+
+ /* Already in gterm window? */
+ if ((root_x >= xoff && root_x < xoff+width) &&
+ (root_y >= yoff && root_y < yoff+height)) {
+
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = 0;
+ w->gterm.save_y = 0;
+ w->gterm.interactive++;
+ }
+ x = root_x - xoff; y = root_y - yoff;
+ in_window++;
+
+ } else {
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+ } else {
+ /* Pointer not on the current screen.
+ */
+ if (!w->gterm.interactive) {
+ w->gterm.save_x = root_x;
+ w->gterm.save_y = root_y;
+ w->gterm.save_root = root;
+ w->gterm.interactive++;
+ }
+ x = w->gterm.cur_x; y = w->gterm.cur_y;
+ }
+
+ if ((x < 5 || x > width-5) || (y < 5 || y > height-5)) {
+ x = width / 2;
+ y = height / 2;
+ }
+
+ if (!in_window) {
+ erase_crosshair (w);
+ if (w->gterm.warpCursor) {
+ XWindowAttributes wa;
+ if (XGetWindowAttributes (display, gtermwin, &wa) &&
+ wa.map_state == IsViewable) {
+
+ /* The following should not be necessary but is needed
+ * to workaround an X server bug. When warping to a
+ * different screen the pointer is not erased on the
+ * old screen. It is hard to erase it, but we can
+ * at least move it to the corner of the screen.
+ */
+ if (root != w->gterm.root) {
+ Screen *screen = w->gterm.screen;
+ if (XGetWindowAttributes (display, root, &wa))
+ screen = wa.screen;
+ XWarpPointer (display,None,root, 0,0,0,0,
+ WidthOfScreen(screen) - 1,
+ HeightOfScreen(screen) - 1);
+ }
+
+ /* Now warp into the gterm window. */
+ XWarpPointer (display, None, gtermwin, 0,0,0,0, x,y);
+ }
+ if (w->gterm.full_crosshair)
+ draw_crosshair (w, x, y);
+ }
+
+ } else if (w->gterm.full_crosshair) {
+ erase_crosshair (w);
+ draw_crosshair (w, x, y);
+ }
+ } else
+ update_cursor (w);
+
+ cursor = w->gterm.ginmode_cursor;
+ if (interval = w->gterm.ginmodeBlinkInterval) {
+ XtAppContext appcon = XtWidgetToApplicationContext ((Widget) w);
+ id = XtAppAddTimeOut (appcon,
+ interval, blink_cursor, (XtPointer)w);
+ } else
+ id = (XtIntervalId) NULL;
+ break;
+
+ case GtBusyCursor:
+ /* Exit graphics cursor mode.
+ */
+ erase_crosshair (w);
+ cursor = w->gterm.busy_cursor;
+ break;
+ }
+
+ if (w->core.visible)
+ XDefineCursor (w->gterm.display, w->gterm.window,
+ w->gterm.cursor = cursor);
+ if (id && w->gterm.cursor_type != GtGinmodeCursor) {
+ XtRemoveTimeOut (id);
+ id = (XtIntervalId) NULL;
+ }
+}
+
+static void
+blink_cursor (w, id)
+ GtermWidget w;
+ XtIntervalId *id;
+{
+ XtAppContext app_context;
+ XColor bg, fg;
+ int interval;
+
+ if (w->gterm.cursor_type != GtGinmodeCursor) /* MF032 */
+ return;
+
+ bg = w->gterm.ginmodeColors[1];
+ fg = w->gterm.ginmodeColors[0];
+
+ app_context = XtWidgetToApplicationContext ((Widget) w);
+ XRecolorCursor (w->gterm.display, w->gterm.ginmode_cursor, &fg, &bg);
+ XFlush (w->gterm.display);
+
+ w->gterm.ginmodeColors[0] = bg;
+ w->gterm.ginmodeColors[1] = fg;
+
+ if (interval = w->gterm.ginmodeBlinkInterval)
+ XtAppAddTimeOut (app_context,
+ interval, (XtTimerCallbackProc) blink_cursor, (XtPointer)w);
+}
+
+GtPostInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.inputCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.inputCallback = new;
+}
+
+GtDeleteInputProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.inputCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.inputCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resetCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resetCallback = new;
+}
+
+GtDeleteResetProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resetCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resetCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtPostResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *new;
+
+ new = (GtCallback *) XtMalloc (sizeof (GtCallback));
+ new->proc = userfcn;
+ new->client_data = client_data;
+ new->next = NULL;
+
+ for (cb = w->gterm.resizeCallback; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ w->gterm.resizeCallback = new;
+}
+
+GtDeleteResizeProc (w, userfcn, client_data)
+ GtermWidget w;
+ GtCallbackProc userfcn;
+ XtPointer client_data;
+{
+ register GtCallback *cb, *prev;
+
+ for (prev=NULL, cb = w->gterm.resizeCallback; cb; cb = cb->next)
+ if (cb->proc == userfcn && cb->client_data == client_data) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ w->gterm.resizeCallback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ } else
+ prev = cb;
+}
+
+GtDrawAlphaText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ XPoint *points, pv[1], o_pv[1];
+ DrawContext dx = get_draw_context (w);
+ register MappingContext mx;
+ register int npts, i;
+
+ pv[0].x = x;
+ pv[0].y = y;
+ npts = 1;
+
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ points = mx->scale ? mapVector(mx,pv,o_pv,npts) : pv;
+ x = points[0].x; y = points[0].y;
+
+ if (mx->use_backing_store)
+ XDrawString (w->gterm.display, w->gterm.pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ XDrawString (w->gterm.display, mx->pixmap,
+ mx->drawGC, x, y, text, strlen(text));
+ }
+
+ update_transients (w, (Region)NULL);
+}
+
+GtGetAlphaTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.alpha_fonts[w->gterm.alpha_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+GtWriteAlphaCursor (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+}
+
+GtEraseAlphaCursor (w)
+ GtermWidget w;
+{
+}
+
+GtStartDialog (w)
+ GtermWidget w;
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "GtStartDialog: ENTER d_pixmap=0x%x d_saved=%d\n",
+ w->gterm.d_pixmap, w->gterm.d_saved);
+
+ if (w->gterm.d_pixmap) {
+ if (w->gterm.d_saved) {
+ GtEraseDialog (w);
+ } else {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap ? w->gterm.pixmap : w->gterm.window,
+ w->gterm.d_pixmap, w->gterm.exposeGC,
+ 0, w->gterm.d_yoff, w->core.width, w->gterm.d_height, 0, 0);
+ w->gterm.d_saved = 1;
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtStartDialog: LEAVING\n");
+}
+
+GtEndDialog (w)
+ GtermWidget w;
+{
+ GtEraseDialog (w);
+ w->gterm.d_saved = 0;
+}
+
+GtEraseDialog (w)
+ GtermWidget w;
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "GtEraseDialog: ENTER d_pixmap=0x%x d_saved=%d\n",
+ w->gterm.d_pixmap, w->gterm.d_saved);
+
+ if (w->gterm.d_pixmap && w->gterm.d_saved) {
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ if (w->gterm.pixmap)
+ XCopyArea (w->gterm.display,
+ w->gterm.d_pixmap, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, 0, w->core.width, w->gterm.d_height, 0, w->gterm.d_yoff);
+ update_transients (w, (Region)NULL);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtEraseDialog: LEAVING\n");
+}
+
+GtDrawDialogText (w, x, y, text)
+ GtermWidget w;
+ int x, y;
+ char *text;
+{
+ int xpos = w->gterm.d_xoff + x;
+ int ypos = w->gterm.d_yoff + y;
+
+ if (w->gterm.pixmap)
+ XDrawImageString (w->gterm.display, w->gterm.pixmap,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.dialogGC, xpos, ypos, text, strlen(text));
+}
+
+GtGetDialogTextSize (w, string, width, height, base)
+ GtermWidget w;
+ char *string;
+ int *width, *height, *base;
+{
+ XFontStruct *fp;
+
+ fp = w->gterm.dialog_fonts[w->gterm.dialog_font];
+ if (string)
+ *width = XTextWidth (fp, string, strlen(string));
+ else
+ *width = fp->max_bounds.width;
+
+ *height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ *base = fp->max_bounds.ascent;
+}
+
+
+/*
+ * Internal functions for above code.
+ * ----------------------------------------
+ */
+
+static
+set_default_color_index (w)
+ GtermWidget w;
+{
+ /* The default color index is 1, corresponding to the foreground
+ * drawing color color1. Index zero is the background drawing color
+ * color0. The remaining NColors color table entries are the optional
+ * drawing colors corresponding to resources "color2" through "colorN".
+ * These are used only if explicitly selected by the client application.
+ */
+ if (w->gterm.useGlobalCmap)
+ XSetForeground (w->gterm.display, w->gterm.drawGC,
+ static_colors[1].value);
+ else
+ XSetForeground (w->gterm.display, w->gterm.drawGC, w->gterm.cmap[1]);
+ w->gterm.color_index = 1;
+ invalidate_draw_context (w);
+}
+
+
+static
+draw_crosshair (w, x, y)
+ GtermWidget w;
+ int x, y;
+{
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.pixmap) {
+ /* The preserve_screen flag is set if we need to preserve the
+ * exact display window contents, rather than merely refresh from
+ * the backing store pixmap.
+ */
+ if (w->gterm.preserve_screen) {
+ if (!w->gterm.preserve_valid || y != w->gterm.cur_y)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, w->core.height);
+ if (!w->gterm.preserve_valid || x != w->gterm.cur_x)
+ XCopyArea (w->gterm.display,
+ w->gterm.window, w->gterm.pixmap, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, w->core.width, 0);
+ w->gterm.preserve_valid = 1;
+ }
+
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ 0, y, w->core.width, y);
+ XDrawLine (w->gterm.display, w->gterm.window, w->gterm.cursorGC,
+ x, 0, x, w->core.height);
+
+ XFlush (w->gterm.display);
+ w->gterm.cursor_drawn++;
+ }
+
+ w->gterm.cur_x = x;
+ w->gterm.cur_y = y;
+}
+
+
+static
+erase_crosshair (w)
+ GtermWidget w;
+{
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (w->gterm.cursor_drawn) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ if (w->gterm.pixmap) {
+ if (w->gterm.preserve_screen && w->gterm.preserve_valid) {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, w->core.height, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ w->core.width, 0, 1, w->core.height, x, 0);
+ } else {
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ 0, y, w->core.width, 1, 0, y);
+ XCopyArea (w->gterm.display,
+ w->gterm.pixmap, w->gterm.window, w->gterm.exposeGC,
+ x, 0, 1, w->core.height, x, 0);
+ }
+ }
+
+ w->gterm.cursor_drawn = 0;
+ w->gterm.preserve_valid = 0;
+ }
+}
+
+
+static
+update_transients (w, region)
+ GtermWidget w;
+ Region region;
+{
+ /* If an explicit region is given redisplay any markers in it immediately,
+ * otherwise set the redisplay flag to cause a full screen redisplay when
+ * drawing finishes and the widget is ready for input.
+ */
+ if ((char *)region)
+ GmRedisplay (w, region);
+ else
+ w->gterm.gm_redisplay = True;
+
+ /* Update the crosshair cursor if GIN mode is in effect. */
+ update_cursor (w);
+}
+
+
+static
+update_cursor (w)
+ GtermWidget w;
+{
+ if (w->gterm.cursor_type == GtGinmodeCursor && w->gterm.full_crosshair) {
+ register int x = w->gterm.cur_x;
+ register int y = w->gterm.cur_y;
+
+ if (x || y)
+ draw_crosshair (w, x, y);
+ }
+}
+
+static Cursor
+get_cursor (w, cursor_name)
+ GtermWidget w;
+ String cursor_name;
+{
+ XrmValue from, to;
+ Cursor cursor;
+
+ from.size = strlen (cursor_name) + 1;
+ from.addr = cursor_name;
+
+ to.addr = (caddr_t) &cursor;
+ to.size = sizeof(cursor);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRCursor, &to))
+ cursor = XCreateFontCursor (w->gterm.display, XC_crosshair);
+
+ return (cursor);
+}
+
+
+static DrawContext
+get_draw_context (w)
+ GtermWidget w;
+{
+ DrawContext dx = &w->gterm.draw;
+
+ if (!dx->valid) {
+ int raster = w->gterm.raster;
+ Raster rp = &w->gterm.rasters[raster];
+ register MappingContext mx = &dx->mapContext[0];
+ Region clip_region, mask_region;
+ struct mapping *map, *mp, *np, p_mp;
+ int xres = w->gterm.xres;
+ int yres = w->gterm.yres;
+ float xscale, yscale;
+ XRectangle r;
+ int i, j;
+
+ dx->raster = w->gterm.raster;
+ dx->rp = rp;
+
+ if (raster == 0) {
+ dx->nmappings = 1;
+ mx->mapping = 0;
+ mx->mp = NULL;
+ mx->use_backing_store = (w->gterm.pixmap != (Pixmap)NULL);
+ mx->pixmap = w->gterm.window;
+ mx->drawGC = w->gterm.drawGC;
+ mx->GC_private = 0;
+
+/* (7/16/97) MJF - we don't scale raster 0 since it's already in screen coords.
+ Otherwise the cursor movement keystrokes scale incorrectly and quickly move
+ to (0,0).
+ mx->xoffset = mx->yoffset = mx->scale = 0;
+ [DCT] This doesn't look entirely right as it disables logical coords for
+ the screen. Leave as is until this can be studied more carefully.
+ */
+
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height)
+ mx->scale = 0;
+ else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ } else {
+ dx->nmappings = 0;
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (!mp->enabled || mp->src != raster ||
+ w->gterm.rasters[mp->dst].type != GtServer)
+ continue;
+ if (!valid_mapping (w, mp))
+ continue;
+
+ mx->mp = mp;
+ mx->mapping = mp->mapping;
+ mx->pixmap = w->gterm.rasters[mp->dst].r.pixmap;
+ mx->use_backing_store = (mp->dst == 0 &&
+ w->gterm.pixmap && !(mp->rop & R_Transient));
+
+ /* Determine if any scaling is necessary. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ /* Compute logical-to-raster scaling. */
+ mx->xoffset = mx->yoffset = 0;
+ if (xres == rp->width && yres == rp->height) {
+ mx->xscale = mx->yscale = 1.0;
+ mx->scale = 0;
+ } else {
+ mx->xscale = (float)rp->width / (float)xres;
+ mx->yscale = (float)rp->height / (float)yres;
+ mx->scale = 1;
+ }
+
+ /* Compute overall scale factors by combining logical-to-
+ * raster and raster-to-screen mappings.
+ */
+ if (map->snx != map->dnx || map->sny != map->dny ||
+ map->sx != map->dx || map->sy != map->dy) {
+
+ xscale = (float)map->dnx / (float)map->snx;
+ mx->xscale *= xscale;
+ if (xscale < 0)
+ mx->xoffset = map->dx + abs(map->dnx) - 1;
+ else
+ mx->xoffset = map->dx;
+ mx->xoffset -= (map->sx * xscale);
+
+ yscale = (float)map->dny / (float)map->sny;
+ mx->yscale *= yscale;
+ if (yscale < 0)
+ mx->yoffset = map->dy + abs(map->dny) - 1;
+ else
+ mx->yoffset = map->dy;
+ mx->yoffset -= (map->sy * yscale);
+
+ mx->scale = 1;
+ }
+
+ /* Compute the clip mask which will clip graphics to the
+ * destination rect of the mapping, minus any regions of
+ * this rect covered by other mappings.
+ */
+ clip_region = XCreateRegion();
+ r.x = map->dx; r.y = map->dy;
+ r.width = abs(map->dnx);
+ r.height = abs(map->dny);
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != mp->dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ mask_region = XCreateRegion();
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ }
+
+ /* Create a drawing GC which is a copy of the global drawGC
+ * but using the clip mask computed above.
+ */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.root,
+ 0, NULL);
+
+ /* Deep Frame */
+ mx->drawGC = XCreateGC (w->gterm.display, w->gterm.window,
+ 0, NULL);
+ /* Deep Frame */
+
+ XCopyGC (w->gterm.display, w->gterm.drawGC, ~0, mx->drawGC);
+ XSetRegion (w->gterm.display, mx->drawGC, clip_region);
+ XDestroyRegion (clip_region);
+ mx->GC_private = 1;
+
+ if (++dx->nmappings >= MAX_DRAW)
+ break;
+ else
+ mx++;
+ }
+ }
+
+ dx->valid = 1;
+ }
+
+ return (dx);
+}
+
+
+static
+invalidate_draw_context (w)
+ GtermWidget w;
+{
+ register DrawContext dx = &w->gterm.draw;
+ register MappingContext mx;
+ register int i;
+
+ if (dx->valid) {
+ for (i=0; i < dx->nmappings; i++) {
+ mx = &dx->mapContext[i];
+ if (mx->GC_private)
+ XFreeGC (w->gterm.display, mx->drawGC);
+ }
+ dx->valid = 0;
+ }
+}
+
+static XPoint *
+mapVector (mx, pv1, pv2, npts)
+ register MappingContext mx;
+ XPoint *pv1;
+ XPoint *pv2;
+ int npts;
+{
+ register XPoint *ip = pv1;
+ register XPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x * mx->xscale + mx->xoffset;
+ op->y = ip->y * mx->yscale + mx->yoffset;
+ }
+
+ return (pv2);
+}
+
+
+static void
+savepos (w, event)
+ GtermWidget w;
+ XEvent *event;
+{
+ if (event == NULL)
+ return;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ w->gterm.last_x = event->xkey.x;
+ w->gterm.last_y = event->xkey.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w->gterm.last_x = event->xbutton.x;
+ w->gterm.last_y = event->xbutton.y;
+ break;
+ case MotionNotify:
+ w->gterm.last_x = event->xmotion.x;
+ w->gterm.last_y = event->xmotion.y;
+ break;
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/GtermImaging.c b/vendor/x11iraf/obm/ObmW/GtermImaging.c
new file mode 100644
index 00000000..b2d5791c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermImaging.c
@@ -0,0 +1,3164 @@
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * GtReadLUT (gt, lut, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ * GtSetDisplayRaster (gt, mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters) {
+ for (i=1; i < w->gterm.maxRasters; i++) {
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+ }
+ }
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtRasterInit: Init display PixmapRaster (%dx%d) depth=%d\n",
+ w->core.width, w->core.height, w->core.depth);
+
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->depth = w->core.depth;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, w->core.height, RasterDepth);
+
+
+ /* Free any previously allocated colormap cells. */
+ if (! w->gterm.useGlobalCmap) {
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors-SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRasterInit: After Init Mappings...Returning\n");
+}
+
+
+initialize_shadow_pixmap (GtermWidget w, int dst)
+{
+ Raster rp = (Raster) NULL;
+
+ if (w->gterm.rasters) {
+ rp = &w->gterm.rasters[dst];
+
+ if (dst == 0 || rp->type == PixmapRaster) {
+ XFillRectangle (w->gterm.display, rp->shadow_pixmap,
+ w->gterm.clear8GC, 0, 0, rp->width, rp->height);
+ }
+ }
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+ } else
+ wa = w->gterm.wa;
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->depth = wa.depth;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtCreateRaster: raster=%d type=%s (%dx%dx%d)\n",
+ raster, ((type == GtClient) ? "GtClient" : "GtServer"),
+ width, height, depth);
+ }
+
+
+ /* Only rasters of depth 8 bits are currently supported. Eventually
+ ** we may want to allow arbitrarily deep frame buffers (e.g. for RGB
+ ** composites, overlay planes, etc).
+ if (depth && depth != 8) {
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster ERROR: attempt to create raster depth=%d\n",
+ depth);
+ return (ERR);
+ }
+ */
+
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters) {
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster ERROR: invalid raster = %d\n", raster);
+ return (ERR);
+ } else
+ rp = &w->gterm.rasters[raster];
+
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->depth = depth;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "GtCreateRaster: cacheRasters = '%s' type=%s cache=%d\n",
+ w->gterm.cacheRasters, (type == GtServer ? "GtServer" : "GtClient"),
+ cache);
+ fprintf (stderr,"GtCreateRaster: cache=%d (%dx%dx%d)\n",
+ cache, width, height, depth);
+ fprintf (stderr,"GtCreateRaster: Creating %s: %d\n",
+ (cache ? "PIXMAPRASTER" : "IMAGERASTER"), raster);
+ }
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->depth = depth;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, depth);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster: [pixmap] creating shadow pixmap %dx%d\n",
+ w->core.width+1, w->core.height+1);
+
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width+1, w->core.height+1, RasterDepth);
+
+ if (rp->r.pixmap == (Pixmap) NULL)
+ goto ximage;
+
+ XFillRectangle (w->gterm.display, rp->r.pixmap,
+ (depth == RasterDepth ? w->gterm.clear8GC : w->gterm.clearGC),
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage for the raster.
+ */
+ximage:
+ rp->type = ImageRaster;
+ rp->depth = depth;
+
+ /* Get pixel storage.
+ */
+ if ((data = (uchar *) XtMalloc((npix=width*height))) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster: [ximage] creating shadow pixmap %dx%d\n",
+ w->core.width+1, w->core.height+1);
+
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width+1, w->core.height+1, RasterDepth);
+ }
+
+ w->gterm.nrasters++;
+
+ if (DBG_TRACE) {
+ int i;
+
+ fprintf (stderr, "GtCreateRaster: LEAVING nraster=%d\n",
+ w->gterm.nrasters);
+
+ for (i=0; i < w->gterm.nrasters; i++)
+ fprintf (stderr, "GtCreateRaster[%d]: type=%8s %dx%d [%d]\n",
+ i,
+ (w->gterm.rasters[i].type==GtClient)?"GtClient":"GtServer",
+ w->gterm.rasters[i].width, w->gterm.rasters[i].height,
+ w->gterm.rasters[i].depth);
+ }
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+
+ if (DBG_TRACE && DBG_VERBOSE)
+ fprintf (stderr, "GtQueryRaster: raster=%d\n", raster);
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = rp->depth;
+
+ if (DBG_TRACE && DBG_VERBOSE)
+ fprintf (stderr, "GtQueryRaster: raster=%d (%s) w=%d h=%d d=%d\n",
+ raster,
+ ((*type == PixmapRaster) ? "GtServer" : "GtClient"),
+ *width, *height, *depth);
+
+
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int i, n, bytes_per_line;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+ XWindowAttributes wa;
+ unsigned int *ras = NULL;
+
+
+ rp = &w->gterm.rasters[raster];
+
+ if (DBG_TRACE)
+ fprintf(stderr,
+ "GtWritePixels[%s] ENTER: nbits=%d raster=%d type='%s' wa=0x%x\n",
+ dbg_wSize(w), nbits, raster,
+ (rp->type == PixmapRaster) ? "PixmapRaster" : "ImageRaster",
+ w->gterm.wa);
+
+
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ fprintf (stderr, "GtWritePixels: Error getting window attrs\n");
+ return (ERR);
+ }
+ } else
+ wa = w->gterm.wa;
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWritePixels: window depth=%d RasterDepth= %d class=%s\n",
+ wa.depth, RasterDepth, dbg_visStr(wa.visual->class));
+
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Doing PixmapRaster[%s]....depth=%d\n",
+ dbg_wSize(w), wa.depth);
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; ) {
+
+ /* In TrueColor mode, we preserve the index values in the
+ ** XImage and apply the colormap when rendering.
+ */
+ *op++ = (wa.depth == ColormapDepth ?
+ (cmap[*ip++] & 0377) : ((*ip++) & 0377));
+ }
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Creating 8-bit ximage\n");
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+
+ if (raster == 0 && w->gterm.pixmap) {
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: type = pixmap, raster=0\n");
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC,
+ IMGtoGPM(w,ximage,0,0,nx,ny),
+ 0, 0, x1, y1, nx, ny);
+
+ XCopyArea (display,
+ GPMtoRPM(w, rp), rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+
+ } else {
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC,
+ IMGtoRPM (w,ximage,rp,0,0,nx,ny),
+ 0, 0, x1, y1, nx, ny);
+ }
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ int min=256, max=0;
+ int min1=256, max1=0;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWritePix: ImageRaster....bytes_per_line=%d ras depth=%d\n",
+ rp->r.ximage->bytes_per_line, rp->r.ximage->depth);
+
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ if (DBG_TRACE)
+ fprintf(stderr,
+ "GtWritePix: Doing ColormapDepth....writing to ximage\n");
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map
+ * is dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation would also make it
+ * easy to add support later for image depths other than 8 bit.
+ * Doing the conversion to display pixels here is however simpler
+ * and more efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; ) {
+ if (wa.depth == ColormapDepth)
+ *op++ = (cmap[*ip++] & 0xFF);
+ else
+ *op++ = (*ip++ & 0xFF);
+
+ if (DBG_TRACE) {
+ if (*ip < min) min = *ip;
+ if (*ip > max) max = *ip;
+ if (cmap[*ip] < min1) min1 = cmap[*ip];
+ if (cmap[*ip] > max1) max1 = cmap[*ip];
+ }
+ }
+ lp += bytes_per_line;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "CMAP MINMAX: %d %d -- %d %d\n", min, max, min1, max1);
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (wa.depth != ColormapDepth) { /* FIXME */
+ update_mapping (w, mp);
+ refresh_source (w, mp, x1, y1, nx, ny);
+ /* break; */
+
+ } else if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePixels[%s] LEAVING....\n", dbg_wSize(w));
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i, nskip = 1;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadPixels: ras=%d %d %d %d %d w->depth=%d\n",
+ raster, x1, y1, nx, ny, w->gterm.w_depth);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage.
+ if (rp->type == PixmapRaster) {
+ */
+ if (rp->type == PixmapRaster || (raster == 0 && w->gterm.w_depth > 8)) {
+
+ Display *display = w->gterm.display;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadPixels: rp->type == PixmapRaster [%d]\n",
+ raster);
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ if (w->gterm.w_depth > ColormapDepth) {
+ Raster ras = (Raster) NULL;
+
+ if (raster)
+ ras = &w->gterm.rasters[w->gterm.d_raster];
+ else
+ ras = &w->gterm.rasters[0];
+
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ?
+ ras->shadow_pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ } else {
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ?
+ w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+ }
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+ nskip = xin->bits_per_pixel / 8;
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtReadPixels: xin->bpp=%d bpl=%d nskip=%d %d,%d %dx%d\n",
+ xin->bits_per_pixel, xin->bytes_per_line, nskip,
+ x1, y1, nx, ny);
+
+ if (w->gterm.w_depth == ColormapDepth)
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + (y * bytes_per_line + (nskip * x));
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; ) {
+ if (w->gterm.w_depth == ColormapDepth) {
+ *op++ = cmap[*ip];
+ } else {
+ *op++ = *ip;
+ }
+ ip += nskip;
+ }
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+ Raster sp = &w->gterm.rasters[0];
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store) {
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XFillRectangle (display, sp->shadow_pixmap, w->gterm.clear8GC,
+ x1, y1, nx, ny);
+ }
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: ENTER\n");
+
+ /* Get pixel coordinates.
+ */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster.
+ */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: mp=0x%x enabled=%d src=%d/%d\n",
+ mp, mp->enabled, mp->src, raster);
+
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtRefreshPixels: update pixtype raster\n");
+
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtRefreshPixels: update non-pix raster\n");
+
+ update_mapping (w, map);
+ }
+
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: LEAVING\n");
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny, /* MF006 */
+ RasterDepth) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (w, i); /* MF005 */
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0, 0, 0, 0,
+ dst, ctype, x, y, width, height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny, /* MF006 */
+ RasterDepth) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n, use_wa = 1;
+ unsigned long plane_masks[1];
+ int req, need, ncolors;
+
+ Colormap colormap;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtWriteColormap: ENTER.....\n");
+ fprintf (stderr,
+ "GtWriteColormap: map=%d first=%d nelem=%d gt.ncols=%d\n",
+ map, first, nelem, w->gterm.ncolors);
+ }
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: create/modify map = %d\n", map);
+
+ /* See if the colormap already exists.
+ */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it.
+ */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap.
+ */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ if (nelem >= 0) {
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: map=%d -- RETURNING\n",map);
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache.
+ */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (w->gterm.w_depth == 0 && w->gterm.w_visual_class == 0) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+
+ if (wa.depth == 1)
+ goto unitary;
+ } else
+ use_wa = 0;
+
+
+ switch ((use_wa ? wa.visual->class : w->gterm.w_visual_class)) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp)) {
+ w->gterm.cmap[i] = cp->pixel;
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: PSEUDOCOLOR vis, defCM=%d, gt.ncols=%d\n",
+ w->gterm.useDefaultCM, w->gterm.ncolors);
+
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: PSEUDOCOLOR defCM, need=%d gt.ncols=%d\n",
+ need, w->gterm.ncolors);
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ long timeval, time();
+ int shadow;
+
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtWriteColormap: PSEUDOCOLOR custom cmap\n");
+ fprintf (stderr,
+ "GtWriteColormap: Pseudo: first=%d nelem=%d -> ncols=%d/%d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+ }
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,
+ "GtWriteColormap: Pseudo: %3d (%3d %3d %3d) %d / %d\n",
+ i, r[i]>>8,g[i]>>8,b[i]>>8, w->gterm.ncolors, ncolors);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: first=%d nelem=%d ncol=%d %d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow * 1000))) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: PSEUDOCOLOR DONE\n");
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: visual default case\n");
+
+unitary:
+ colormap = get_colormap (w);
+
+ if ((first+nelem) > MAX_SZCMAP)
+ break;
+
+ if (w->gterm.useGlobalCmap)
+ break;
+
+ first = SZ_STATIC_CMAP;
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: unitary: first=%d nelem=%d -> ncolors=%d/%d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+
+ for (i = 0; i < ncolors; i++, cp++) {
+ w->gterm.cmap[i] = i;
+ cp->pixel = i;
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,
+ "GtWriteColormap: True: %3d: (%3d, %3d, %3d) %d / %d\n",
+ i, r[i]>>8, g[i]>>8, b[i]>>8, w->gterm.ncolors, ncolors);
+
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "GtWriteColormap: map=%d first=%d nelem=%d ncol=%d %d\n",
+ map, first, nelem, ncolors, w->gterm.ncolors);
+ fprintf (stderr, "GtWriteColormap: TRUECOLOR DONE\n");
+ }
+
+ break;
+ }
+
+
+ if (DBG_TRACE) {
+ dbg_printCmaps (w);
+ fprintf (stderr, "GtWriteColormap: LEAVING\n");
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ register int i;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadColormap: ENTER map=%d first=%d nelem=%d\n",
+ map, first, nelem);
+
+ if (w->gterm.useGlobalCmap) {
+ for (i=0; i < MAX_SZCMAP; i++) {
+ r[i] = global_color[i].red;
+ g[i] = global_color[i].green;
+ b[i] = global_color[i].blue;
+ }
+ return (SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP);
+ }
+
+
+ /* Clear the output colormap.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) r[i] = g[i] = b[i] = 0;
+
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ if (first+i < w->gterm.ncolors) {
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "GtReadColormap: %3d %3d %3d %3d\t",
+ first+i, r[i]>>8, g[i]>>8, b[i]>>8);
+
+ cp = &w->gterm.color[first+i];
+ r[i] = (ushort) cp->red;
+ g[i] = (ushort) cp->green;
+ b[i] = (ushort) cp->blue;
+ } else
+ break;
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,"%3d\t%3d %3d %3d\n",i,r[i]>>8,g[i]>>8,b[i]>>8);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadColormap: LEAVING ncolors=%d\n", i);
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: map=%d offset=%f slope=%f\n",
+ map, offset, slope);
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap.
+ */
+dummy:
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+
+ } else {
+ /* Locate colormap.
+ */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: map=%d/%d cm=0x%x ncells=%d\n",
+ map, cm->map, cm, cm->ncells);
+
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ ** is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ if (w->gterm.useGlobalCmap)
+ nelem = SZ_DYNAMIC_CMAP;
+ else
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtLoadColormap: scaling cmap; nelem=%d\n", nelem);
+
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ if (w->gterm.useGlobalCmap) {
+ for (i=0; i < nelem; i++) {
+ global_color[i+SZ_STATIC_CMAP].red = o_cmap.r[i];
+ global_color[i+SZ_STATIC_CMAP].green = o_cmap.g[i];
+ global_color[i+SZ_STATIC_CMAP].blue = o_cmap.b[i];
+ }
+ global_color[i+SZ_STATIC_CMAP-1].red = o_cmap.r[i] = o_cmap.r[i-2];
+ global_color[i+SZ_STATIC_CMAP-1].green = o_cmap.g[i] = o_cmap.g[i-2];
+ global_color[i+SZ_STATIC_CMAP-1].blue = o_cmap.b[i] = o_cmap.b[i-2];
+ nelem = SZ_DYNAMIC_CMAP;
+ valid_lut = 0;
+ }
+
+ /* Load the colormap into the display.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: loading colormap into display\n");
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+
+ /* If the colormap we loaded to the display was the display colormap,
+ ** restore the original unscaled colors in the gterm descriptor so that
+ ** we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0) {
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+ }
+
+ if (w->gterm.useGlobalCmap) {
+ Mapping mp;
+
+ /* Execute any mappings that reference this raster.
+ */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled) {
+ struct mapping *map=mp, p_mp;
+
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+
+ if (colormap_focus > 0 && colormap_focus < mp->snx) {
+ /* If we're doing a focused update, refresh only the
+ ** central part of the main display.
+ */
+ int half = colormap_focus;
+ int full = ((half * 2 > 512) ? 512 : half * 2);
+
+ /* refresh_source (w, map,
+ mp->sx+(mp->snx/2 - 64), mp->sy+(mp->sny/2 - 64),
+ 128, 128); */
+
+ refresh_source (w, map,
+ mp->sx+(mp->snx/2 - half), mp->sy+(mp->sny/2 - half),
+ full, full);
+ } else {
+ refresh_source (w, map, mp->sx, mp->sy, mp->snx, mp->sny);
+ }
+
+ if (map == &p_mp)
+ free_mapping (w, map);
+
+ /* if (colormap_focus) break; */
+ }
+ }
+ }
+
+ return (OK);
+}
+
+GtSetColormapFocus (int box_size)
+{
+ if (box_size != 0)
+ colormap_focus = ((box_size > 0 && box_size < 64) ? 64 : box_size);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (w->gterm.useGlobalCmap) {
+ *first = SZ_STATIC_CMAP;
+ *nelem = SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP;
+ *maxelem = SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP;
+
+ } else if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+
+ }
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtQueryColormap: map=%d -> first=%d nelem=%d max=%d\n",
+ map, *first, *nelem, *maxelem);
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ if (w->gterm.useGlobalCmap)
+ return;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+
+ if (DBG_TRACE)
+ fprintf (stderr,"GtWriteIomap: first=%d nelem=%d -> c1=%d c2=%d (%d)\n",
+ first, nelem, c1, c2, (c2-c1+1));
+
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+
+ if (DBG_IOMAP) {
+ int i;
+ for (i=0; i < MAX_SZCMAP; i++)
+ fprintf (stderr, "iomap[%3d] = %d\n", i, w->gterm.iomap[i]);
+ }
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* GtReadLUT -- Read back the contents of the global LUT.
+ */
+GtReadLUT (w, lut, first, nelem)
+ register GtermWidget w;
+ unsigned long *lut;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (lut, &global_lut[c1], nelem * sizeof(unsigned long));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+/* init_global_map -- Initialize the global cmap;
+ */
+static void
+init_global_cmap ()
+{
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ global_cmap[i] = (Pixel) i;
+}
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+
+ if (w->gterm.useGlobalCmap)
+ return (global_cmap);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_cmap_in: valid=%d ncolors=%d\n",
+ w->gterm.cmap_in_valid, (w->gterm.ncolors - SZ_STATIC_CMAP));
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+
+ if (w->gterm.useGlobalCmap)
+ return (global_cmap);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_cmap_out: valid=%d ncolors=%d\n",
+ w->gterm.cmap_out_valid, (w->gterm.ncolors - SZ_STATIC_CMAP));
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ struct mapping sv_mp, p_mp; /* MF007 */
+ int status;
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtCopyRaster() -- ENTER\n");
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtCopyRaster() -- RETURNING\n");
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ int dummy_rop; /* MF011 */
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetMapping - ENTER\n");
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return (OK);
+ } else if (!mp->enabled) {
+ return (OK);
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return (OK);
+
+ if (rop & R_RefreshNone)
+ return (OK);
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &dummy_rop, /* MF011 */
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetMapping - LEAVING\n");
+
+ return (OK);
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtEnableMapping: mapping=%d refresh=%d\n",
+ mapping, refresh);
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtSetDisplayRaster -- Set the currently displayed raster. On TrueColor
+** visuals the XImage for a frame represents the actual pixel values and
+** not the colormapped image. We need this for pixel readback where the
+** display pixmap (i.e. w->gterm.pixmap) is the 24-bits colormapped image
+** and we have no way to get back to the pixel values.
+**
+*/
+
+GtSetDisplayRaster (gt, raster)
+ GtermWidget gt;
+ int raster; /* raster number */
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetDisplayRaster: raster=%d\n", raster);
+
+ gt->gterm.d_raster = (raster * 2);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtRefreshMapping() -- ENTER\n");
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtRefreshMapping() -- LEAVING\n");
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/GtermMapping.c b/vendor/x11iraf/obm/ObmW/GtermMapping.c
new file mode 100644
index 00000000..21e4760d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermMapping.c
@@ -0,0 +1,2189 @@
+
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+ int valid;
+
+
+ /* Do nothing if mapping not defined and enabled.
+ */
+ if (!(valid = valid_mapping (w, mp))) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_source: valid=%d\n", valid);
+ return (ERR);
+ }
+ if (!mp->enabled) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR ref_src: mapping %d not enabled\n",
+ mp->mapping);
+ return (OK);
+ }
+
+ /* Compute the intersection of the modified region of the source raster
+ ** with the rectangular region of the source raster affected by the given
+ ** mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect.
+ */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ if (DBG_TRACE) {
+ fprintf(stderr, "refresh_source -- refreshing src (%d,%d) (%d,%d)\n",
+ sx1, sy1, snx, sny);
+ fprintf(stderr, "refresh_source -- refreshing dest (%d,%d) (%d,%d)\n",
+ dx1, dy1, dnx, dny);
+ dbg_printMappings (w);
+ }
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr, pr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+ Pixmap pixmap; /* MF004 */
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap, valid;
+ XRectangle r;
+ XImage *img1 = (XImage *) NULL,
+ *img2 = (XImage *) NULL,
+ *img3 = (XImage *) NULL,
+ *img4 = (XImage *) NULL,
+ *img5 = (XImage *) NULL;
+
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination ENTER[0x%x]: pos=%d,%d sz=%d,%d\n",
+ w, x1,y1,nx,ny);
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!(valid = valid_mapping (w, mp))) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: valid=%d\n", valid);
+ return (ERR);
+ }
+ if (!mp->enabled) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR ref_dst: mapping %d not enabled\n",
+ mp->mapping);
+ return (OK);
+ }
+
+
+ if (DBG_CMAPS && DBG_CM_VERB)
+ dbg_printCmaps (w);
+ if (DBG_TRACE)
+ dbg_printRasters (w);
+
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ pr = &w->gterm.rasters[0]; /* display pixmap raster */
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "refresh_destination: src,dst = %d,%d st,dt = %s[%d],%s[%d]\n",
+ src, dst,
+ (sr->type == 1 ? "image" : "pixmap"), sr->depth,
+ (dr->type == 1 ? "image" : "pixmap"), dr->depth);
+ fprintf (stderr,
+ "refresh: gterm.pixmap=0x%x src.pixmap=0x%x dest.pixmap=0x%x\n",
+ w->gterm.pixmap, sr->r.pixmap, dr->r.pixmap);
+ fprintf (stderr,
+ "refresh: gterm.pixmap=0x%x src.ximage=0x%x dest.ximage=0x%x\n",
+ w->gterm.pixmap, sr->r.ximage, dr->r.ximage);
+ fprintf (stderr,
+ "refresh_destination: src=>(%d,%d : %d,%d) dst=>(%d,%d : %d,%d)\n",
+ sx, sy, snx, sny, dx, dy, dnx, dny);
+ }
+
+
+ /* Basic error checking.
+ */
+ if (!sr->type || !dr->type) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: invalid src or dest type\n");
+ return (ERR);
+
+ } else if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: negative src position or zero size\n");
+ return (ERR);
+
+ } else if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: invalid src or dest value\n");
+ return (ERR);
+ }
+
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx;
+ r.y = dy;
+ r.width = dnx;
+ r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: xflip=%d yflip=%d clip=%d scaling=%d\n",
+ xflip, yflip, clip, scaling);
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: pixmap-to-pixmap copy %d <-> %d\n",
+ src, dst);
+
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: pixmap copy src=dst=0\n");
+
+ XCopyArea (display,
+ w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+
+ XCopyArea (display,
+ GPMtoRPM(w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ /* Update the root display shadow pixmap.
+ */
+ XCopyArea (display,
+ pr->shadow_pixmap, pr->shadow_pixmap,
+ w->gterm.expose8GC, sx, sy, snx, sny, dx, dy);
+
+ } else {
+ Raster rp = &w->gterm.rasters[src-1];
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "refresh_destination: pixmap copy src || dst != 0\n");
+ fprintf (stderr, "src=%d dest=%d shadow=0x%x ximage=0x%x\n",
+ src, dst, dr->shadow_pixmap, rp->r.ximage);
+ dbg_printRasters (w);
+ fprintf (stderr,
+ "src=%d,%d %d %d dest=%d,%d %d %d (src=%d dst=%d)\n",
+ sx, sy, snx, sny, dx, dy, dnx, dny, src, dst);
+ }
+
+ XCopyArea (display,
+ RPMtoRPM(sr, dr), dr->r.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+
+
+ /* Update the shadow pixmap.
+ */
+ XCopyArea (display,
+ sr->shadow_pixmap, dr->shadow_pixmap,
+ w->gterm.expose8GC, sx, sy, snx, sny, dx, dy);
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display,
+ RPMtoGPM (sr, w), w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: spec_case: pixmap copy no scaling\n");
+
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: source type is PixmapRaster[%d]\n", src);
+
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ if (CacheXImage) { /* MF004 */
+ pixmap = (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap;
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin is cached XImage ");
+ fprintf (stderr, " src=%d pix=0x%x dims=%d,%d\n",
+ src, w->gterm.pixmap, sr->width, sr->height);
+ }
+
+ xin = GetCachedXImage (w, pixmap, sr->width, sr->height);
+ if (xin == NULL) {
+ xin = XGetImage (display, pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ } else
+ NewCachedXImage (w, xin, pixmap, sr->width, sr->height);
+ }
+
+ } else { /* MF004 */
+
+ /*
+ */
+ if (w->gterm.w_depth > ColormapDepth) {
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "src=%d dst=%d d_ras=%d %d x %d pr=0x%x sr=0x%x\n",
+ src, dst, w->gterm.d_raster, sr->width, sr->height,
+ pr->shadow_pixmap, sr->shadow_pixmap);
+ dbg_printRasters (w);
+ }
+
+ xin = XGetImage (display, sr->shadow_pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+
+ } else {
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ }
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin is drawable '%s'\n",
+ (src || !w->gterm.pixmap) ? "sr raster" : "gterm pixmap");
+ fprintf (stderr,
+ "refresh_destination: xin size=%d,%d bpp=%d bpl=%d\n",
+ xin->width, xin->height, xin->bits_per_pixel,
+ xin->bytes_per_line);
+ }
+
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } /* MF004 */
+
+ } else {
+ /* Source is an ximage. */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: src type is XImage (sr->r.ximage)\n");
+
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: NO scaling, dest=Pixmap\n");
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: dest == 0\n");
+
+ XPutImage (display,
+ w->gterm.pixmap, w->gterm.exposeGC,
+ (img1=IMGtoGPM(w,xin,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "\n\nrefresh: gterm.pixmap=0x%x dest.pixmap=0x%x\n\n",
+ w->gterm.pixmap, dr->r.pixmap);
+
+ XCopyArea (display,
+ GPMtoRPM (w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ XPutImage (display, pr->shadow_pixmap, w->gterm.expose8GC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+
+ } else {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin dst > 0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ sx, sy, dx, dy, dnx, dny);
+ fprintf (stderr,
+ "refresh_destination: dr->shadow_pixmap = 0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr, "refresh_destination: xin => %d x %d x %d\n",
+ xin->width, xin->height, xin->depth);
+ }
+
+ /* Copy the 'xin' to the 'dr->r.pixmap'
+ */
+ XPutImage (display,
+ dr->r.pixmap, w->gterm.exposeGC,
+ (img2=IMGtoRPM(w,xin,dr,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC,
+ (img3=IMGtoRPM(w,xin,dr,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+ /* Shadow the pixmap with an 8-bit version for readback.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: NO scaling, dest=Pixmap -- DONE\n");
+
+ goto done;
+ }
+
+ /* Get output ximage.
+ */
+ if (dr->type == ImageRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: dest type is XImage (dr->r.ximage)\n");
+
+ xout = dr->r.ximage;
+ ox = dx;
+ oy = dy;
+
+ } else {
+
+ uchar *data = (uchar *) XtCalloc (dnx * dny, sizeof(uchar));
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: dest type is Pixmap, create XImage\n");
+
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: creating 8-bit ximage....%d x %d\n",
+ dnx, dny);
+
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0;
+ oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh: scaling=%d xin=0x%x xout=0x%x\n",
+ scaling, xin, xout);
+
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl + sx;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination.
+ */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: COPY TO OUTPUT PIXMAP\n");
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: dst=0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+
+ XPutImage (display,
+ w->gterm.pixmap, w->gterm.exposeGC,
+ (img4=IMGtoGPM(w,xout,ox,oy,dnx,dny)),
+ ox, oy, dx, dy, dnx, dny);
+
+ XCopyArea (display,
+ GPMtoRPM (w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr,
+ "updating %d,%d to %d,%d %d %d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xout, ox, oy, dx, dy, dnx, dny);
+ }
+
+ } else {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xout dst > 0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+
+ XPutImage (display,
+ dr->r.pixmap, w->gterm.exposeGC,
+ (img5=IMGtoRPM(w,xout,dr,ox,oy,dnx,dny)),
+ ox, oy, dx, dy, dnx, dny);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ /*
+ XPutImage (display, pr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ */
+
+ /* Shadow the pixmap with an 8-bit version for readback.
+ */
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr,
+ "updating %d,%d to %d,%d %d %d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin) XDestroyImage (xin);
+ if (delxout) XDestroyImage (xout);
+
+ if (img1) XDestroyImage (img1);
+ if (img2) XDestroyImage (img2);
+ if (img3) XDestroyImage (img3);
+ if (img4) XDestroyImage (img4);
+ if (img5) XDestroyImage (img5);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: doing mappings status=%d\n",
+ status);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination: LEAVING status=%d\n", status);
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++) {
+ op[i] = ip[xmap[i]];
+ }
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+
+ op = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+
+ /* Why are the case statements below necessary, doesn't the
+ * default case do the same thing regardless of what nx is? MJF
+ */
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Discard the temporary mapping.
+ free_mapping (w, &p_mp);
+ */
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/GtermMarker.c b/vendor/x11iraf/obm/ObmW/GtermMarker.c
new file mode 100644
index 00000000..0ed4f1ca
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermMarker.c
@@ -0,0 +1,4674 @@
+
+/*
+ * Graphics MARKERS.
+ * --------------------
+ * A marker is an active graphics object displayed on top of a drawing to
+ * mark, annotate, or outline a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state. Markers are used to
+ * interactively define regions with the mouse, to provide a dynamic graphical
+ * display which doesn't interfere with the underlying graphics frame, or as a
+ * graphical means of command input, using callbacks to perform some operation
+ * when the marker is moved or resized by the user.
+ *
+ * GtMarkerInit (w)
+ * GtMarkerFree (w)
+ *
+ * gm = GmCreate (w, type, interactive)
+ * GmRedisplay (w, region|NULL)
+ * gm = GmCopy (gm)
+ * GmDestroy (gm)
+ * GmAddCallback (gm, events, func, client_data)
+ * GmDeleteCallback (gm, func, client_data)
+ * gm = GmSelect (gt, x, y, &what)
+ *
+ * GmMarkpos (gm)
+ * GmRedraw (gm, func, erase)
+ * GmRaise (gm, ref_gm|NULL)
+ * GmLower (gm, ref_gm|NULL)
+ * GmNotify (gm, events, event, param, nparams)
+ *
+ * GmAddPt (gm, x, y)
+ * GmDeletePt (gm, x, y)
+ * GmMovePt (gm, x, y)
+ * GmMove (gm, x, y)
+ * GmResize (gm, x, y)
+ * GmRotate (gm, x, y)
+ *
+ * GmSetAttributes (gm, args, nargs, type)
+ * GmGetAttributes (gm, args, nargs, type)
+ * GmSetAttribute (gm, attribute, value, type)
+ * GmGetAttribute (gm, attribute, value, type)
+ * GmSetVertices (gm, points, first, npts)
+ * npts = GmGetVertices (gm, points, first, maxpts)
+ * GmGetBoundingBox (gm, x, y, width, height)
+ *
+ * type = GmStrToType (marker_type)
+ * event = GmStrToEvent (event_type)
+ * func = GmStrToFunction (drawing_function)
+ *
+ * Markers operate in screen coordinates (raster 0). The SelectRaster
+ * and MapVector routines may be used to convert to and from raster
+ * coordinates if desired.
+ *
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mp)
+ * GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
+ *
+ * The Gm procedures above implement the main functionality of markers. User
+ * interaction is provided at a higher level using action procedures which
+ * are bound to pointer and keyboard events via translations (or by the GUI
+ * itself directly calling the above procedures).
+ */
+
+static void gm_text_init(), gm_line_init(), gm_plin_init(), gm_rect_init();
+static void gm_boxx_init(), gm_circ_init(), gm_elip_init(), gm_pgon_init();
+static int gm_putint(), gm_putfloat(), gm_do_callbacks(), gm_constraint();
+static int gm_getint(), gm_getattribute(), gm_gettype();
+static double gm_getfloat();
+static char *gm_getstring();
+
+static void gm_markpos(), gm_erase(), gm_redraw(), gm_setCurRect();
+static void gm_linkafter(), gm_unlink();
+static double gm_niceAngle();
+static Pixel gm_getpixel();
+static int gm_select();
+static int gm_getfillstyle();
+
+static GmVMethod gm_classinit[] = {
+ gm_text_init, gm_line_init, gm_plin_init, gm_rect_init,
+ gm_boxx_init, gm_circ_init, gm_elip_init, gm_pgon_init
+};
+
+static Region null_region;
+static XRectangle null_rect = { 0, 0, 0, 0 };
+#define NullRect(r) (!(r)->width || !(r)->height)
+
+#define PI_2 1.57079632679489661923
+#define PI_4 0.78539816339744830962
+#define BORDER 5
+
+static void M_create(), M_destroy(), M_destroyNull(), M_set(), M_raise();
+static void M_lower(), M_notify(), M_markpos(), M_markposAdd(), M_redraw();
+static void M_addPt(), M_deletePt(), M_movePt(), M_deleteDestroy();
+static void M_move(), M_resize(), M_moveResize(), M_rotate();
+static void M_rotateResize(), M_input();
+static void gm_focusin(), gm_focusout();
+
+static XtActionsRec markerActionsList[] = {
+ { "m_create", M_create },
+ { "m_destroy", M_destroy },
+ { "m_destroyNull", M_destroyNull },
+ { "m_set", M_set },
+ { "m_raise", M_raise },
+ { "m_lower", M_lower },
+ { "m_notify", M_notify },
+ { "m_input", M_input },
+ { "m_markpos", M_markpos },
+ { "m_markposAdd", M_markposAdd },
+ { "m_redraw", M_redraw },
+ { "m_addPt", M_addPt },
+ { "m_deletePt", M_deletePt },
+ { "m_movePt", M_movePt },
+ { "m_deleteDestroy", M_deleteDestroy },
+ { "m_move", M_move },
+ { "m_resize", M_resize },
+ { "m_moveResize", M_moveResize },
+ { "m_rotate", M_rotate },
+ { "m_rotateResize", M_rotateResize },
+};
+
+
+/* GtMarkerInit -- Initialize the marker subsystem.
+ */
+GtMarkerInit (w)
+ GtermWidget w;
+{
+ register Marker gm, prev;
+ XColor fg_color, bg_color;
+ Display *display = w->gterm.display;
+ int type, i;
+ GC gc;
+
+ for (gm = w->gterm.gm_tail; gm; gm = prev) {
+ prev = gm->prev;
+ GmDestroy (gm);
+ }
+
+ if (!w->gterm.gm_initialized) {
+ /* Register some additional actions for markers. */
+ XtAppAddActions (XtWidgetToApplicationContext((Widget)w),
+ markerActionsList, XtNumber(markerActionsList));
+
+ /* Get the gterm widget translations. */
+ if ((char *)w->gterm.defTranslations == NULL) {
+ char *translations = NULL;
+ XtTranslations tt;
+ XtResource r;
+ int ttype, i;
+
+ r.resource_name = XtNtranslations;
+ r.resource_class = XtCTranslations;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ XtGetApplicationResources ((Widget)w, &translations, &r, 1,NULL,0);
+
+ if (translations) {
+ if (strncmp (translations, "#augment", 8) == 0)
+ ttype = T_augment;
+ else if (strncmp (translations, "#override", 9) == 0)
+ ttype = T_override;
+ else
+ ttype = T_replace;
+
+ if (ttype == T_replace) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (translations);
+ } else if ((i = w->gterm.nauxTrans) < MAX_AUXTRANS) {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ w->gterm.auxTrans[i] =
+ XtParseTranslationTable (translations);
+ w->gterm.auxTType[i] = ttype;
+ w->gterm.nauxTrans++;
+ }
+
+ } else {
+ w->gterm.defTranslations =
+ XtParseTranslationTable (defaultGtermTranslations);
+ }
+
+ /* Get the marker translations. */
+ if ((char *)w->gterm.gm_defTranslations == NULL)
+ w->gterm.gm_defTranslations =
+ XtParseTranslationTable (w->gterm.gm_translations);
+ }
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ /* Get graphics drawing GC. */
+/* gc = XCreateGC (display, w->gterm.root, 0, NULL); */
+ gc = XCreateGC (display, w->gterm.window, 0, NULL);
+ XSetBackground (display, gc, w->gterm.color0);
+ XSetForeground (display, gc, w->gterm.color1);
+ XSetLineAttributes (display, gc,
+ w->gterm.gm_lineWidth, w->gterm.gm_lineStyle, CapButt, JoinMiter);
+ w->gterm.gm_drawGC = gc;
+
+ /* Get graphics rubber-band GC. */
+/* gc = XCreateGC (display, w->gterm.root, 0, NULL); */
+ gc = XCreateGC (display, w->gterm.window, 0, NULL);
+ XSetFunction (display, gc, GXxor);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, w->gterm.gm_xorFillColor);
+ XSetBackground (display, gc, w->gterm.gm_xorFillBgColor);
+ XSetLineAttributes (display, gc,
+ 0, LineDoubleDash, CapButt, JoinMiter);
+ w->gterm.gm_rubberGC = gc;
+
+ fg_color.pixel = w->gterm.gm_cursorFgColor;
+ bg_color.pixel = w->gterm.gm_cursorBgColor;
+ XQueryColor (display, w->core.colormap, &fg_color);
+ XQueryColor (display, w->core.colormap, &bg_color);
+
+ w->gterm.gm_markerCursor = XCreateFontCursor (display, XC_fleur);
+ XRecolorCursor (display, w->gterm.gm_markerCursor, &fg_color,&bg_color);
+ w->gterm.gm_edgeCursor = XCreateFontCursor (display, XC_dotbox);
+ XRecolorCursor (display, w->gterm.gm_edgeCursor, &fg_color,&bg_color);
+ w->gterm.gm_pointCursor = XCreateFontCursor (display, XC_sizing);
+ XRecolorCursor (display, w->gterm.gm_pointCursor, &fg_color,&bg_color);
+
+ if (!(type = GmStrToType (w->gterm.gm_defaultMarker)))
+ type = Gm_Rectangle;
+ w->gterm.gm_defaultType = type;
+
+ if (!null_region)
+ null_region = XCreateRegion();
+ w->gterm.gm_initialized++;
+ }
+
+ w->gterm.gm_create = NULL;
+ w->gterm.gm_active = NULL;
+ w->gterm.gm_redisplay = False;
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* GtMarkerFree -- Free any marker subsystem resources.
+ */
+static void
+GtMarkerFree (w)
+ register GtermWidget w;
+{
+ register Display *display = w->gterm.display;
+ register Marker gm;
+
+ /* Cancel any load translation table interval timer. */
+ if (w->gterm.gm_timer_id) {
+ XtRemoveTimeOut (w->gterm.gm_timer_id);
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+ }
+
+ /* Set the default gterm window translations. */
+ gm_load_translations (w, NULL);
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev)
+ GmDestroy (gm);
+
+ if (!w->gterm.gm_initialized)
+ return;
+
+ XFreeGC (display, w->gterm.gm_drawGC);
+ XFreeGC (display, w->gterm.gm_rubberGC);
+
+ /* This call can fail - see comments elsewhere in this file about
+ * XFreeCursor.
+ *
+ XFreeCursor (display, w->gterm.gm_markerCursor);
+ XFreeCursor (display, w->gterm.gm_edgeCursor);
+ XFreeCursor (display, w->gterm.gm_pointCursor);
+ */
+
+ w->gterm.gm_initialized = 0;
+}
+
+
+/* gm_focusin -- Called when gterm window input is directed to a marker.
+ */
+static void
+gm_focusin (w, gm, what)
+ register GtermWidget w;
+ register Marker gm;
+ GmSelection what;
+{
+ Cursor cursor;
+ int erase;
+ Marker am;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (am = w->gterm.gm_active) {
+ if (am != gm)
+ gm_focusout (w, 0);
+ else if (what && what->type == w->gterm.gm_selection.type) {
+ /* no change */
+ return;
+ }
+ }
+
+ if (what) {
+ switch (what->type) {
+ case Ge_Point:
+ cursor = w->gterm.gm_pointCursor;
+ break;
+ case Ge_Edge:
+ cursor = w->gterm.gm_edgeCursor;
+ break;
+ default:
+ cursor = w->gterm.gm_markerCursor;
+ break;
+ }
+ } else
+ cursor = w->gterm.gm_markerCursor;
+
+ erase_crosshair (w);
+ XDefineCursor (w->gterm.display, w->gterm.window, cursor);
+ w->gterm.gm_active = gm;
+ w->gterm.gm_selection = *what;
+
+ if (gm && gm != am) {
+ gm_request_translations (w, gm);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusIn, NULL, NULL, 0);
+}
+
+
+/* gm_focusout -- Called to restore the normal gterm window input when the
+ * pointer moves off a marker.
+ */
+static void
+gm_focusout (w, enableSetTrans)
+ register GtermWidget w;
+ int enableSetTrans; /* replace translations */
+{
+ register Display *display = w->gterm.display;
+ register Marker gm = w->gterm.gm_active;
+ int erase, i;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Restore the default gterm window translations. */
+ if (enableSetTrans)
+ gm_request_translations (w, NULL);
+
+ XDefineCursor (display, w->gterm.window, w->gterm.cursor);
+ w->gterm.gm_active = NULL;
+
+ if (gm) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ gm_do_callbacks (gm, GmEvFocusOut, NULL, NULL, 0);
+}
+
+
+/* gm_refocus -- Simulate a pointer event to recompute the marker pointer
+ * focus. Called when a software event changes the marker stacking order
+ * in some way.
+ */
+static void
+gm_refocus (w)
+ GtermWidget w;
+{
+ XMotionEvent event;
+ int nparams = 0;
+
+ event.type = MotionNotify; /* MF009 */
+ event.x = w->gterm.last_x;
+ event.y = w->gterm.last_y;
+ HandleTrackCursor ((Widget)w, &event, NULL, &nparams);
+}
+
+
+/*
+ * Translation tables. The widget's translation table must not be replaced
+ * while a translation is executing. This can be a problem as it is often
+ * events and their translations which lead to the translation table getting
+ * replaced. To avoid this problem we merely queue a timer event to load
+ * the desired translation table, allowing any existing translation to
+ * finish executing before the translation table is swapped out. If multiple
+ * translation table load requests are issued only the final one has any
+ * effect.
+ */
+
+/* gm_request_translations -- Queue a request to load the translations for the
+ * specified marker (or NULL to load the default gterm translations). If this
+ * is the first request and timers are enabled a timer is posted to load the
+ * translations when any current event processing is complete. If a request
+ * is already active then the most recent request supercedes any previous one.
+ */
+static void
+gm_request_translations (w, gm)
+ register GtermWidget w;
+ Marker gm;
+{
+ w->gterm.gm_reqTranslations = gm;
+
+ if (!w->gterm.useTimers)
+ gm_load_translations (w, NULL);
+ else if (!w->gterm.gm_timer_id) {
+ w->gterm.gm_timer_id =
+ XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)w), 0,
+ gm_load_translations, (XtPointer)w);
+ }
+}
+
+
+/* gm_load_translations -- Swap out the widget's translation table. This is
+ * a no-op if the requested translation table is already loaded.
+ */
+static void
+gm_load_translations (w, id)
+ register GtermWidget w;
+ XtIntervalId id;
+{
+ register Marker am, gm;
+ register int i;
+
+ w->gterm.gm_timer_id = (XtIntervalId) NULL;
+
+ am = w->gterm.gm_curTranslations;
+ gm = w->gterm.gm_reqTranslations;
+ if (am == gm && w->gterm.gm_initialized)
+ return;
+
+ if (gm) {
+ /* Set the translations for the indicated marker. */
+ if (!am || am->translations != gm->translations)
+ XtOverrideTranslations ((Widget)w, gm->translations);
+ } else {
+ /* Restore the default gterm window translations. */
+ XtVaSetValues ((Widget)w,
+ XtNtranslations, (XtArgVal)w->gterm.defTranslations, NULL);
+ for (i=0; i < w->gterm.nauxTrans; i++) {
+ switch (w->gterm.auxTType[i]) {
+ case T_augment:
+ XtAugmentTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ case T_override:
+ XtOverrideTranslations ((Widget)w, w->gterm.auxTrans[i]);
+ break;
+ }
+ }
+ }
+
+ w->gterm.gm_curTranslations = w->gterm.gm_reqTranslations;
+}
+
+
+/* Public marker functions.
+ * --------------------------
+ */
+
+/* GmCreate -- Create a new marker.
+ */
+Marker
+GmCreate (w, type, interactive)
+ GtermWidget w;
+ int type; /* marker type */
+ int interactive; /* use pointer to set position */
+{
+ register Marker gm;
+
+ /* Allocate descriptor. */
+ if (type < 1 || type > Gm_NTypes)
+ return (NULL);
+ if (!(gm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ /* Initialize descriptor. */
+ gm->w = w;
+ gm->type = type;
+ gm->flags = interactive ? (Gm_Visible|Gm_Sensitive) : 0;
+ gm->translations = w->gterm.gm_defTranslations;
+ gm->old_region = XCreateRegion();
+ gm->cur_region = XCreateRegion();
+ (gm_classinit[type-1]) (gm, interactive);
+
+ /* Link marker to tail of marker list. */
+ gm_linkafter (gm, w->gterm.gm_tail);
+
+ /* If marker is being created interactive, set flag to indicate that the
+ * next create marker event should finish creating this marker.
+ */
+ if (w->gterm.gm_create)
+ GmDestroy (w->gterm.gm_create);
+ w->gterm.gm_create = interactive ? gm : NULL;
+
+ return (gm);
+}
+
+
+/* GmDestroy -- Destroy a marker.
+ */
+GmDestroy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ Region old_region, cur_region;
+
+ /* GmDestroy can be called recursively during a destroy operation as a
+ * side effect of the destroy callback. Set the Gm_BeingDestroyed flag
+ * to cause these redundant destroy requests to be ignored.
+ */
+ if (gm->flags & Gm_BeingDestroyed)
+ return (OK);
+ gm->flags |= Gm_BeingDestroyed;
+
+ /* Release the focus if active marker. This should be done before
+ * proceeding to destroy the marker, i.e. before calling the destroy
+ * callbacks.
+ */
+ if (w->gterm.gm_active == gm) {
+ gm_focusout (w, 1);
+ w->gterm.gm_active = NULL;
+ }
+
+ /* Inform any clients that have registered a callback for this marker
+ * that we are about to destroy the marker.
+ */
+ gm_do_callbacks (gm, GmEvDestroy, NULL, NULL, 0);
+
+ /* Erase the marker from the screen. */
+ GmMarkpos (gm);
+ gm_erase (gm);
+
+ /* Note marker position. */
+ old_region = gm->old_region;
+ cur_region = gm->cur_region;
+
+ /* Free all storage and unlink the marker. */
+ if (gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ if (gm->text)
+ XtFree ((char *)gm->text);
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ gm_unlink (gm);
+ XtFree ((char *)gm);
+
+ /* Redraw any markers that were obscured by the deleted marker. */
+ update_transients (w, old_region);
+
+ XDestroyRegion (old_region);
+ XDestroyRegion (cur_region);
+
+ /* Recompute the marker focus. */
+ gm_refocus (w);
+
+ return (OK);
+}
+
+
+/* GmCopy -- Copy a marker.
+ */
+Marker
+GmCopy (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register Marker nm;
+
+ if (!(nm = (Marker) XtCalloc (1, sizeof (struct marker))))
+ return (NULL);
+
+ *nm = *gm;
+ nm->parent = gm;
+ nm->old_region = NULL;
+ nm->cur_region = NULL;
+ nm->points = NULL;
+ nm->pgon = NULL;
+ nm->text = NULL;
+
+ /* Copy region descriptors. */
+ if ((char *)(nm->old_region = XCreateRegion()) == NULL)
+ goto fail;
+ if ((char *)(nm->cur_region = XCreateRegion()) == NULL)
+ goto fail;
+ XUnionRegion (nm->old_region, gm->cur_region, nm->cur_region);
+
+ /* Copy any polypoint data. */
+ if (gm->pgon) {
+ nm->pgon = (DPoint *) XtMalloc (gm->npoints * sizeof(DPoint));
+ if (nm->pgon == NULL)
+ goto fail;
+ memmove (nm->pgon, gm->pgon, gm->npoints * sizeof(DPoint));
+ }
+
+ /* Copy region polygon. */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (!(nm->points = (XPoint *) XtMalloc (gm->npoints * sizeof(XPoint))))
+ goto fail;
+ memmove (nm->points, gm->points, gm->npoints * sizeof(XPoint));
+ }
+
+ /* Copy any text data. */
+ if (gm->text) {
+ int nchars = strlen (gm->text);
+ if (!(nm->text = XtMalloc (nchars + 1)))
+ goto fail;
+ memmove (nm->text, gm->text, nchars + 1);
+ }
+
+ gm_linkafter (nm, w->gterm.gm_tail);
+ return (nm);
+
+fail:
+ if (nm->text)
+ XtFree (nm->text);
+ if (nm->pgon)
+ XtFree ((char *)nm->pgon);
+ if (nm->points && nm->points != nm->point_data)
+ XtFree ((char *)nm->points);
+ if ((char *)nm->cur_region)
+ XDestroyRegion (nm->cur_region);
+ if ((char *)nm->old_region)
+ XDestroyRegion (nm->old_region);
+
+ XtFree ((char *)nm);
+ return (NULL);
+}
+
+
+/* GmAddCallback -- Add a callback to a marker.
+ */
+GmAddCallback (gm, events, func, client_data)
+ register Marker gm;
+ int events; /* events callback is to receive */
+ GmIMethod func; /* function to be called */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i;
+
+ /* Find an empty callback slot. */
+ for (i=0; i < GM_MAXCALLBACKS; i++)
+ if (!gm->callback[i].events)
+ break;
+
+ /* Register the callback. */
+ if (i < GM_MAXCALLBACKS) {
+ cb = &gm->callback[i];
+ cb->events = events;
+ cb->func = func;
+ cb->client_data = client_data;
+ gm->ncallbacks = max (gm->ncallbacks, i + 1);
+ }
+
+ if (events & GmEvConstraint)
+ gm->constraints++;
+}
+
+
+/* GmDeleteCallback -- Delete a previously posted callback given the
+ * function pointer and client data passed when the callback was registered.
+ */
+GmDeleteCallback (gm, func, client_data)
+ register Marker gm;
+ GmIMethod func; /* callback function */
+ XtPointer client_data; /* client data for above */
+{
+ register struct markerCallback *cb;
+ register int i, n;
+
+ for (i=n=0; i < GM_MAXCALLBACKS; i++) {
+ cb = &gm->callback[i];
+
+ if (cb->func == func && cb->client_data == client_data) {
+ if (cb->events & GmEvConstraint)
+ gm->constraints--;
+ cb->events = (int)NULL;
+ cb->func = (GmIMethod)NULL;
+ cb->client_data = (XtPointer)NULL;
+ } else if (cb->events)
+ n = i;
+ }
+
+ gm->ncallbacks = n + 1;
+}
+
+
+/* GmSelect -- Scan the marker list to see if the given pointer coordinates
+ * are within an active marker. If so, the marker descriptor is returned as
+ * the function value, and the "what" argument is set to indicate what part
+ * of the marker was selected.
+ */
+Marker
+GmSelect (w, x, y, what)
+ GtermWidget w;
+ int x, y;
+ GmSelection what;
+{
+ register int flags = (Gm_Activated|Gm_Visible|Gm_Sensitive);
+ register XRectangle *r;
+ register Marker gm;
+
+ for (gm = w->gterm.gm_tail; gm; gm = gm->prev) {
+ if (!((gm->flags & (flags|Gm_BeingDestroyed)) == flags))
+ continue;
+ r = &gm->cur_rect;
+ if (x < (int)r->x || x >= (int)(r->x + r->width) ||
+ y < (int)r->y || y >= (int)(r->y + r->height))
+ continue;
+ if (gm->select (gm, x, y, what))
+ return (gm);
+ }
+
+ return (NULL);
+}
+
+
+/* GmMarkpos -- Save the current marker position, e.g., prior to modifying
+ * the marker. This is used to erase the old marker when the modified
+ * marker is later redrawn.
+ */
+GmMarkpos (gm)
+ register Marker gm;
+{
+ gm->markpos (gm);
+}
+
+
+/* GmRedraw -- Redraw a marker using the given drawing function. If the erase
+ * flag is not set (as when in rubber-band mode) the marker is merely drawn
+ * to the screen. Otherwise if the old marker position has been saved the
+ * old marker is first erased, then any markers affected by the erase are
+ * redrawn, and finally the current marker is redrawn at the new location.
+ */
+GmRedraw (gm, func, erase)
+ Marker gm;
+ int func;
+ int erase;
+{
+ register Marker mm;
+ register XRectangle *o, *n, *r;
+ int flags = (Gm_Activated|Gm_Visible);
+ Region clip_region, temp_region, temp;
+ GtermWidget w = gm->w;
+ int outside;
+
+ /* Recompute marker polygon if any attributes have changed. */
+ gm->update (gm);
+
+ clip_region = XCreateRegion();
+ temp_region = XCreateRegion();
+
+ /* Erase the previously marked region (old position). */
+ if (erase) {
+ XUnionRegion (gm->old_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+ gm_erase (gm);
+ }
+
+ if (!erase && func == GXxor)
+ gm->redraw (gm, func);
+ else {
+ /* Draw the marker and any markers it intersects, clipping to the
+ * new marker region.
+ */
+ o = &gm->old_rect;
+ n = &gm->cur_rect;
+
+ XUnionRegion (gm->cur_region, clip_region, temp_region);
+ temp = clip_region; clip_region = temp_region; temp_region = temp;
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, clip_region);
+
+ for (mm = gm->w->gterm.gm_head; mm; mm = mm->next) {
+ if (!((mm->flags & flags) == flags))
+ continue;
+
+ /* Redraw a marker if it intersects either the old rect or the
+ * new rect.
+ */
+ if (mm != gm) {
+ r = &mm->cur_rect;
+ outside = 0;
+ if ((int)r->x >= (int)o->x + (int)o->width ||
+ (int)r->x + (int)r->width <= (int)o->x ||
+ (int)r->y >= (int)o->y + (int)o->height ||
+ (int)r->y + (int)r->height <= (int)o->y)
+ outside++;
+ if ((int)r->x >= (int)n->x + (int)n->width ||
+ (int)r->x + (int)r->width <= (int)n->x ||
+ (int)r->y >= (int)n->y + (int)n->height ||
+ (int)r->y + (int)r->height <= (int)n->y)
+ outside++;
+ if (outside == 2)
+ continue;
+ }
+ mm->redraw (mm, func);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ }
+
+ if (erase)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+ XDestroyRegion (clip_region);
+ XDestroyRegion (temp_region);
+
+ if (func != GXxor && gm->width > 0 && gm->height > 0) {
+ /* Redraw callback. */
+ gm_do_callbacks (gm, GmEvRedraw, NULL, NULL, 0);
+
+ /* Generate moveResize callback, if marker was moved or resized.
+ */
+ if (gm->old_rect.x != gm->cur_rect.x ||
+ gm->old_rect.y != gm->cur_rect.y ||
+ gm->old_rect.width != gm->cur_rect.width ||
+ gm->old_rect.height != gm->cur_rect.height) {
+
+ char x[32], y[32];
+ char width[32], height[32];
+ char *argv[5];
+ int argc;
+
+ /* If the marker was just created (old_rect null) or the marker
+ * moved and we did a full erase and redraw, any old markpos is
+ * obsolete so we may as well update the saved position.
+ */
+ if (erase || !gm->old_rect.width || !gm->old_rect.height)
+ GmMarkpos (gm);
+
+ sprintf (x, "%d", gm->x);
+ sprintf (y, "%d", gm->y);
+ sprintf (width, "%d", gm->width);
+ sprintf (height, "%d", gm->height);
+ argv[0] = x;
+ argv[1] = y;
+ argv[2] = width;
+ argv[3] = height;
+ argv[4] = NULL;
+ argc = 4;
+
+ gm_do_callbacks (gm, GmEvMoveResize, NULL, argv, argc);
+ }
+ }
+}
+
+
+/* GmRedisplay -- Redisplay the markers in the given region, or redisplay
+ * the entire window if the region is given as (char *)NULL.
+ */
+GmRedisplay (w, region)
+ GtermWidget w;
+ Region region;
+{
+ register int flags = (Gm_Activated|Gm_Visible);
+ register XRectangle *r;
+ register Marker gm;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Set the clip mask to only draw in the affected region. */
+ if (region)
+ XSetRegion (w->gterm.display, w->gterm.gm_drawGC, region);
+
+ /* Draw all markers that intersect the target region. */
+ for (gm = w->gterm.gm_head; gm; gm = gm->next) {
+ if (!((gm->flags & flags) == flags))
+ continue;
+
+ if ((char *)region) {
+ gm->update (gm);
+ r = &gm->cur_rect;
+ if (XRectInRegion (region,
+ r->x, r->y, r->width, r->height) == RectangleOut)
+ continue;
+ }
+
+ gm->redraw (gm, GXcopy);
+ }
+
+ XSetClipMask (w->gterm.display, w->gterm.gm_drawGC, None);
+ w->gterm.gm_redisplay = False;
+}
+
+
+/* GmRaise -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn above the second.
+ */
+GmRaise (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already on top? */
+ if (gm == w->gterm.gm_tail || ref_gm && ref_gm->next == gm)
+ return;
+
+ /* Raise it. */
+ gm_unlink (gm);
+ gm_linkafter (gm, ref_gm ? ref_gm : w->gterm.gm_tail);
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmLower -- Change the stacking order of a marker relative to another
+ * marker, causing the first marker to be drawn below the second.
+ */
+GmLower (gm, ref_gm)
+ register Marker gm, ref_gm;
+{
+ register GtermWidget w = gm->w;
+ int erase;
+
+ /* Already lowered? */
+ if (gm == w->gterm.gm_head || ref_gm && ref_gm->prev == gm)
+ return;
+
+ /* Lower it. */
+ gm_unlink (gm);
+ if (ref_gm && ref_gm->prev)
+ gm_linkafter (gm, ref_gm->prev);
+ else {
+ gm->next = w->gterm.gm_head;
+ w->gterm.gm_head = gm;
+ if (gm->next)
+ gm->next->prev = gm;
+ if (!w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ }
+
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (w);
+}
+
+
+/* GmNotify -- Notify any clients that have registered callbacks that the
+ * given marker events have occurred.
+ */
+GmNotify (gm, events, event, params, nparams)
+ register Marker gm;
+ int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ gm_do_callbacks (gm, events, event, params, nparams);
+}
+
+
+/* GmAddPt -- Add a point to a marker.
+ */
+GmAddPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->addPt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->addPt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmDeletePt -- Delete a point from a marker.
+ */
+GmDeletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->deletePt) {
+ GmMarkpos (gm);
+ gm->deletePt (gm, x, y);
+ GmRedraw (gm, GXcopy, erase=True);
+ gm_refocus (gm->w);
+ }
+}
+
+
+/* GmMovePt -- Move a point within a marker.
+ */
+GmMovePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->movePt) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->movePt (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmMove -- Move a marker.
+ */
+GmMove (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->move) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->move (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmResize -- Resize a marker.
+ */
+GmResize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->resize) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->resize (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmRotate -- Rotate a marker.
+ */
+GmRotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ int erase;
+ if (gm->rotate) {
+ GmRedraw (gm, GXxor, erase=False);
+ gm->rotate (gm, x, y);
+ GmRedraw (gm, GXxor, erase=False);
+ }
+}
+
+
+/* GmSetAttributes -- Set a list of attributes. Requires that all attribute
+ * values be specified in the same type. Autoredraw, if enabled, is suspended
+ * until all attributes have been changed.
+ */
+GmSetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+ int autoredraw, erase;
+ int status = OK;
+
+ if (autoredraw = (gm->flags & Gm_AutoRedraw)) {
+ gm->flags &= ~Gm_AutoRedraw;
+ GmMarkpos (gm);
+ }
+
+ for (i=0; i < nargs; i++) {
+ status |= GmSetAttribute (gm, args[i].name, args[i].value, argtype);
+ if (strcmp (args[i].name, GmAutoRedraw) == 0)
+ autoredraw = gm_getint (args[i].value, argtype);
+ }
+
+ if (autoredraw) {
+ gm->flags |= Gm_AutoRedraw;
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* GmSetAttribute -- Set the value of a marker attribute.
+ */
+GmSetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int marker_type, atType;
+ int erase, n, i;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmMarkpos (gm);
+
+ switch (atType = gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ marker_type = GmStrToType ((char *)value);
+ break;
+ case Gt_Int:
+ marker_type = gm_getint (value, type);
+ break;
+ default:
+ return (ERR);
+ }
+
+ marker_type = max(1, min(Gm_NTypes, marker_type));
+ (gm_classinit[marker_type-1]) (gm, False);
+ gm->flags |= Gm_Modified;
+ break;
+
+ case Ga_Activated:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Activated)) {
+ gm->flags |= Gm_Activated;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Activated;
+ }
+ return (OK);
+
+ case Ga_Visible:
+ if (gm_getint (value, type)) {
+ if (!(gm->flags & Gm_Visible)) {
+ gm->flags |= Gm_Visible;
+ GmRedraw (gm, GXcopy, erase=False);
+ }
+ } else if (gm->flags & Gm_Visible) {
+ GmMarkpos (gm);
+ gm_erase (gm);
+ gm->flags &= ~Gm_Visible;
+ }
+ return (OK);
+
+ case Ga_Sensitive:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_Sensitive;
+ else
+ gm->flags &= ~Gm_Sensitive;
+ return (OK);
+
+ case Ga_AutoRedraw:
+ if (gm_getint (value, type))
+ gm->flags |= Gm_AutoRedraw;
+ else
+ gm->flags &= ~Gm_AutoRedraw;
+ return (OK);
+
+ case Ga_Translations:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->translations = XtParseTranslationTable ((char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+
+ case Ga_X:
+ gm->x = gm_getint (value, type);
+ break;
+ case Ga_Y:
+ gm->y = gm_getint (value, type);
+ break;
+
+ case Ga_Width:
+ case Ga_Height:
+ /* For a text marker a size can be specified either in integer
+ * pixels or in characters, e.g., "40ch" or "40 chars".
+ */
+ if (gm->type == Gm_Text && type == XtRString) {
+ XFontStruct *fp = gm->font;
+ int char_width, char_height;
+ int l_pix, r_pix;
+ char *ip;
+
+ for (n=0, ip=(char *)value; *ip && isdigit(*ip); ip++)
+ n = n * 10 + (*ip - '0');
+
+ while (isspace (*ip))
+ ip++;
+ if (ip[0] == 'c' && ip[1] == 'h') {
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+
+ if (atType == Ga_Width)
+ n = n * char_width + l_pix + r_pix;
+ else
+ n = n * char_height + l_pix * 2;
+ }
+ } else
+ n = gm_getint (value, type);
+
+ if (atType == Ga_Width)
+ gm->width = n;
+ else
+ gm->height = n;
+ break;
+
+ case Ga_Rotangle: /* MF022 */
+ gm->rotangle = gm_getfloat (value, type) * (M_PI / (double) 180.0);
+ break;
+
+ case Ga_HighlightColor:
+ gm->highlightColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineColor:
+ gm->lineColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_LineWidth:
+ gm->lineWidth = gm_getint (value, type);
+ break;
+ case Ga_LineStyle:
+ gm->lineStyle = gm_getint (value, type);
+ break;
+
+ case Ga_KnotColor:
+ gm->knotColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_KnotSize:
+ gm->knotSize = gm_getint (value, type);
+ break;
+
+ case Ga_Fill:
+ gm->fill = gm_getint (value, type);
+ break;
+ case Ga_FillColor:
+ gm->fillColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillBgColor:
+ gm->fillBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ gm->fillStyle = gm_getfillstyle (w, value, type);
+ break;
+ default:
+ break;
+ }
+ break;
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ gm->fillPattern = (Pixmap) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ gm->textColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBgColor:
+ gm->textBgColor = gm_getpixel (w, value, type);
+ break;
+ case Ga_TextBorder:
+ gm->textBorder = gm_getint (value, type);
+ break;
+ case Ga_ImageText:
+ gm->imageText = gm_getint (value, type);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ i = gm_getint (value, type);
+ if (i >= 0 && i < NDialogFonts)
+ gm->font = w->gterm.dialog_fonts[i];
+ break;
+ case Gt_Pointer:
+ gm->font = (XFontStruct *) (value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ case Gt_String:
+ if (gm->text)
+ XtFree (gm->text);
+ if (!(gm->text = XtMalloc (strlen((char *)value) + 1)))
+ return (ERR);
+ strcpy (gm->text, (char *)value);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ gm->rotIndicator = gm_getint (value, type);
+ break;
+
+ default:
+ return (ERR);
+ }
+
+ gm->flags |= Gm_Modified;
+
+ if (gm->flags & Gm_AutoRedraw)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ /* Notify client that a marker attribute has changed. */
+ { char *argv[2];
+ int argc;
+
+ argv[0] = attribute;
+ argv[1] = NULL;
+ argc = 1;
+
+ gm_do_callbacks (gm, GmEvModify, NULL, argv, argc);
+ }
+
+ return (OK);
+}
+
+
+/* GmGetAttributes -- Get a list of attributes. Requires that all attribute
+ * values be specified in the same type.
+ */
+GmGetAttributes (gm, args, nargs, argtype)
+ register Marker gm;
+ ArgList args;
+ int nargs;
+ char *argtype;
+{
+ register int i;
+
+ for (i=0; i < nargs; i++)
+ GmGetAttribute (gm, args[i].name, args[i].value, argtype);
+}
+
+
+/* GmGetAttribute -- Get the value of a marker attribute.
+ */
+GmGetAttribute (gm, attribute, value, type)
+ register Marker gm;
+ char *attribute;
+ XtArgVal value;
+ char *type;
+{
+ GtermWidget w = gm->w;
+ int i;
+
+ switch (gm_getattribute (attribute)) {
+ case Ga_Type:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->type) {
+ case Gm_Text:
+ strcpy ((char *)value, GmText);
+ break;
+ case Gm_Line:
+ strcpy ((char *)value, GmLine);
+ break;
+ case Gm_Polyline:
+ strcpy ((char *)value, GmPolyline);
+ break;
+ case Gm_Rectangle:
+ strcpy ((char *)value, GmRectangle);
+ break;
+ case Gm_Box:
+ strcpy ((char *)value, GmBox);
+ break;
+ case Gm_Circle:
+ strcpy ((char *)value, GmCircle);
+ break;
+ case Gm_Ellipse:
+ strcpy ((char *)value, GmEllipse);
+ break;
+ case Gm_Polygon:
+ strcpy ((char *)value, GmPolygon);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->type, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_Activated:
+ if (gm_putint ((gm->flags & Gm_Activated) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Visible:
+ if (gm_putint ((gm->flags & Gm_Visible) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Sensitive:
+ if (gm_putint ((gm->flags & Gm_Sensitive) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_AutoRedraw:
+ if (gm_putint ((gm->flags & Gm_AutoRedraw) != 0, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_X:
+ if (gm_putint (gm->x, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Y:
+ if (gm_putint (gm->y, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Width:
+ if (gm_putint (gm->width, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Height:
+ if (gm_putint (gm->height, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Rotangle: /* MF022 */
+ if (gm_putfloat(((double)180.0/M_PI)*(gm->rotangle),value,type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_HighlightColor:
+ if (gm_putint ((int)gm->highlightColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineColor:
+ if (gm_putint ((int)gm->lineColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineWidth:
+ if (gm_putint (gm->lineWidth, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_LineStyle:
+ if (gm_putint (gm->lineStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotColor:
+ if (gm_putint ((int)gm->knotColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_KnotSize:
+ if (gm_putint (gm->knotSize, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_Fill:
+ if (gm_putint (gm->fill, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillColor:
+ if (gm_putint ((int)gm->fillColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_FillBgColor:
+ if (gm_putint ((int)gm->fillBgColor, value, type) == ERR)
+ return (ERR);
+ break;
+
+ case Ga_FillStyle:
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ switch (gm->fillStyle) {
+ case FillSolid:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ case FillTiled:
+ strcpy ((char *)value, "FillTiled");
+ break;
+ case FillStippled:
+ strcpy ((char *)value, "FillStippled");
+ break;
+ case FillOpaqueStippled:
+ strcpy ((char *)value, "FillOpaqueStippled");
+ break;
+ default:
+ strcpy ((char *)value, "FillSolid");
+ break;
+ }
+ break;
+ case Gt_Int:
+ if (gm_putint (gm->fillStyle, value, type) == ERR)
+ return (ERR);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_FillPattern:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *(Pixmap *)value = gm->fillPattern;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+
+ case Ga_TextColor:
+ if (gm_putint ((int)gm->textColor, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_TextBorder:
+ if (gm_putint (gm->textBorder, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_ImageText:
+ if (gm_putint (gm->imageText, value, type) == ERR)
+ return (ERR);
+ break;
+ case Ga_Font:
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ for (i=0; i < NDialogFonts; i++)
+ if (gm->font == w->gterm.dialog_fonts[i]) {
+ if (gm_putint (i, value, type) == ERR)
+ return (ERR);
+ break;
+ }
+ break;
+ case Gt_Pointer:
+ *(XFontStruct **)value = gm->font;
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_Text:
+ switch (gm_gettype (type)) {
+ case Gt_Pointer:
+ *((char **)value) = gm->text;
+ break;
+ case Gt_String:
+ strcpy ((char *)value, gm->text);
+ break;
+ default:
+ return (ERR);
+ }
+ break;
+ case Ga_RotIndicator: /* MF020 */
+ if (gm_putint (gm->rotIndicator, value, type) == ERR)
+ return (ERR);
+ break;
+
+
+ default:
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/* GmSetVertices -- Set the vertices of a "poly" type object.
+ */
+GmSetVertices (gm, points, first, npts)
+ Marker gm;
+ DPoint *points; /* input array of points */
+ int first; /* first point to be set */
+ int npts; /* number of points to set */
+{
+ register DPoint *ip, *pp;
+ register XPoint *op;
+ register int i;
+ int erase;
+
+ /* The point vector is automatically extended if more space is needed.
+ * Small vectors are stored directly in the marker descriptor in the
+ * point_data array.
+ */
+ if (first + npts != gm->npoints) { /* MF013 */
+ if (gm->npoints > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *) XtRealloc ((char *)gm->points,
+ first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (first + npts > GM_MAXVERTICES) {
+ if ((gm->points = (XPoint *)
+ XtMalloc (first + npts)) == (XPoint *)NULL)
+ return;
+ } else if (!gm->points)
+ gm->points = gm->point_data;
+
+ gm->npoints = first + npts;
+ }
+
+ /* Copy the point data. */
+ ip = points;
+ op = &gm->points[first];
+ for (i=0; i < npts; i++) {
+ op->x = (int) ip->x + 0.5;
+ op->y = (int) ip->y + 0.5;
+ ip++, op++;
+ }
+
+ /* If we're defining the vertices of a 'poly' marker update the
+ * pgon[] array with the new set of points. Polygons are initialized
+ * with a unit rectangle and since vertices can't be set as an attribute
+ * the must be set with a setVertices call so we need to update the
+ * structure here.
+ */
+ if (gm->type == Gm_Polygon) { /* MF018 */
+
+ if (gm->pgon) /* MF018 */
+ XtFree ((char *)gm->pgon);
+ gm->pgon = (DPoint *) XtCalloc (first+npts+1, sizeof(DPoint));
+
+ /* Copy the point data to the polygon array. */
+ op = &gm->points[0];
+ pp = &gm->pgon[0];
+ for (i=0; i< gm->npoints; i++, pp++, op++) {
+ pp->x = (double)op->x - gm->x;
+ pp->y = (double)op->y - gm->y;
+ }
+ gm->points[first+npts] = gm->points[0]; /* Close the polygon. */
+
+ gm->npoints = gm->pgon_npts = first + npts + 1;
+ gm->rotangle = 0.0; /* reset rotation angle */
+ gm->flags |= Gm_Modified; /* marker has been modified */
+ }
+
+ /* Redraw the marker if autoredraw is enabled. */
+ if (gm->flags & Gm_AutoRedraw) {
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, erase=True);
+ }
+}
+
+
+/* GmGetVertices -- Get the vertices of a "poly" type object. The actual
+ * number of points output is returned as the function value.
+ */
+GmGetVertices (gm, points, first, maxpts)
+ register Marker gm;
+ register DPoint *points; /* output array of points */
+ int first; /* first point to be returned */
+ int maxpts; /* max number of points to return */
+{
+ register XPoint *ip;
+ register DPoint *op;
+ register int i;
+ int top, nout;
+
+ if (first >= gm->npoints)
+ return (0);
+ top = min (first + maxpts, gm->npoints);
+ nout = top - first;
+
+ /* In the case of a poly object don't return the closing segment. */
+ if (gm->type == Gm_Polygon) /* MF027 */
+ --nout;
+
+ if (points) {
+ ip = &gm->points[first];
+ op = points;
+ for (i=0; i < nout; i++) {
+ op->x = ip->x;
+ op->y = ip->y;
+ ip++, op++;
+ }
+ }
+
+ return (nout);
+}
+
+
+/* GmGetBoundingBox -- Returns a rect large enough to completely enclose a
+ * marker, regardless of its type or orientation.
+ */
+GmGetBoundingBox (gm, x, y, width, height)
+ register Marker gm;
+ int *x, *y;
+ int *width, *height;
+{
+ register XRectangle *r = &gm->cur_rect;
+
+ *x = r->x;
+ *y = r->y;
+ *width = r->width;
+ *height = r->height;
+}
+
+
+/* GmStrToType -- Convert a marker type string to a marker type code.
+ */
+GmStrToType (marker_type)
+register char *marker_type;
+{
+ register int type;
+
+ if (strcmp (marker_type, GmText) == 0)
+ type = Gm_Text;
+ else if (strcmp (marker_type, GmLine) == 0)
+ type = Gm_Line;
+ else if (strcmp (marker_type, GmPolyline) == 0)
+ type = Gm_Polyline;
+ else if (strcmp (marker_type, GmRectangle) == 0)
+ type = Gm_Rectangle;
+ else if (strcmp (marker_type, GmBox) == 0)
+ type = Gm_Box;
+ else if (strcmp (marker_type, GmCircle) == 0)
+ type = Gm_Circle;
+ else if (strcmp (marker_type, GmEllipse) == 0)
+ type = Gm_Ellipse;
+ else if (strcmp (marker_type, GmPolygon) == 0)
+ type = Gm_Polygon;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToEvent -- Convert a marker event type string to a marker event code.
+ */
+GmStrToEvent (event_type)
+register char *event_type;
+{
+ register int type;
+
+ if (strcmp (event_type, "notify") == 0)
+ type = GmEvNotify;
+ else if (strcmp (event_type, "moveResize") == 0)
+ type = GmEvMoveResize;
+ else if (strcmp (event_type, "modify") == 0)
+ type = GmEvModify;
+ else if (strcmp (event_type, "redraw") == 0)
+ type = GmEvRedraw;
+ else if (strcmp (event_type, "destroy") == 0)
+ type = GmEvDestroy ;
+ else if (strcmp (event_type, "input") == 0)
+ type = GmEvInput;
+ else if (strcmp (event_type, "focusIn") == 0)
+ type = GmEvFocusIn;
+ else if (strcmp (event_type, "focusOut") == 0)
+ type = GmEvFocusOut;
+ else if (strcmp (event_type, "constraint") == 0)
+ type = GmEvConstraint;
+ else
+ type = 0;
+
+ return (type);
+}
+
+
+/* GmStrToFunction -- Convert a drawing function string to the corresponding
+ * XLIB function code.
+ */
+GmStrToFunction (function)
+register char *function;
+{
+ register int code;
+
+ if (strcmp (function, "clear") == 0)
+ code = GXclear;
+ else if (strcmp (function, "and") == 0)
+ code = GXand;
+ else if (strcmp (function, "andReverse") == 0)
+ code = GXandReverse;
+ else if (strcmp (function, "copy") == 0)
+ code = GXcopy;
+ else if (strcmp (function, "andInverted") == 0)
+ code = GXandInverted;
+ else if (strcmp (function, "noop") == 0)
+ code = GXnoop;
+ else if (strcmp (function, "xor") == 0)
+ code = GXxor;
+ else if (strcmp (function, "or") == 0)
+ code = GXor;
+ else if (strcmp (function, "nor") == 0)
+ code = GXnor;
+ else if (strcmp (function, "equiv") == 0)
+ code = GXequiv;
+ else if (strcmp (function, "invert") == 0)
+ code = GXinvert;
+ else if (strcmp (function, "orReverse") == 0)
+ code = GXorReverse;
+ else if (strcmp (function, "copyInverted") == 0)
+ code = GXcopyInverted;
+ else if (strcmp (function, "orInverted") == 0)
+ code = GXorInverted;
+ else if (strcmp (function, "nand") == 0)
+ code = GXnand;
+ else if (strcmp (function, "set") == 0)
+ code = GXset;
+ else
+ code = -1;
+
+ return (code);
+}
+
+
+/* Internal procedures for above code.
+ * ------------------------------------
+ */
+
+static int
+gm_getint (value, type)
+ XtArgVal value;
+ char *type;
+{
+ register int ch;
+
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ ch = *((char *)value);
+ if (ch == 'T' || ch == 't')
+ return (1);
+ else if (ch == 'F' || ch == 'f')
+ return (0);
+ else
+ return (atoi((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static Pixel
+gm_getpixel (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ XrmValue from, to;
+ Pixel pixel;
+ char *str;
+
+ switch (gm_gettype (type)) {
+ case Gt_Int:
+ /* Pixel value (colormap index). */
+ return ((Pixel)value);
+
+ case Gt_String:
+ /* The pixel is expressed either as a pixel number input as a string,
+ * or as a color name. The latter case requires a type conversion.
+ */
+ str = (char *)value;
+ if (isdigit(str[0]) && (int)strlen(str) <= 3) {
+ int index = atoi (str);
+ pixel = w->gterm.cmap[index];
+ return (pixel);
+ }
+
+ if (w->gterm.useDefaultCM || !w->gterm.haveColormap) {
+ /* Allocate color from default colormap.
+ */
+ from.size = strlen ((char *)value) + 1;
+ from.addr = (char *)value;
+ to.addr = (caddr_t) &pixel;
+ to.size = sizeof(pixel);
+
+ if (!XtConvertAndStore ((Widget)w, XtRString, &from, XtRPixel, &to))
+ pixel = w->gterm.cmap[1];
+
+ } else {
+ /* Allocate closest match from custom colormap. This is crude,
+ * but for the standard colors this will return an exact match.
+ */
+ int index, min_dist, dist, i;
+ XColor exact, best, *cp;
+
+ pixel = w->gterm.cmap[1];
+ if (XLookupColor (w->gterm.display,
+ get_colormap(w), str, &exact, &best)) {
+ min_dist = 9999;
+ index = 1;
+
+ for (i=0; i < w->gterm.ncolors; i++) {
+ cp = &w->gterm.color[i];
+ dist = abs((int)exact.red - (int)cp->red) +
+ abs((int)exact.green - (int)cp->green) +
+ abs((int)exact.blue - (int)cp->blue);
+ if (dist == 0) {
+ index = i;
+ break;
+ } else if (dist < min_dist) {
+ index = i;
+ min_dist = dist;
+ }
+ }
+
+ pixel = w->gterm.color[index].pixel;
+ }
+ }
+ return (pixel);
+
+ default:
+ return (w->gterm.cmap[1]);
+ }
+}
+
+
+static int
+gm_getfillstyle (w, value, type)
+ GtermWidget w;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_String:
+ if (strcmp ((char *)value, "FillSolid") == 0)
+ return (FillSolid);
+ else if (strcmp ((char *)value, "FillTiled") == 0)
+ return (FillTiled);
+ else if (strcmp ((char *)value, "FillStippled") == 0)
+ return (FillStippled);
+ else if (strcmp ((char *)value, "FillOpaqueStippled") == 0)
+ return (FillOpaqueStippled);
+ break;
+ default:
+ break;
+ }
+
+ return (FillSolid);
+}
+
+
+static double
+gm_getfloat (value, type)
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ return ((int)value);
+ case Gt_DFloatP:
+ return (*(double *)value);
+ case Gt_String:
+ return (atof((char *)value));
+ default:
+ return (0);
+ }
+}
+
+
+static char *
+gm_getstring (value, type)
+ XtArgVal value;
+ char *type;
+{
+ if (strcmp (type, XtRString) == 0)
+ return ((char *)value);
+ else
+ return ("");
+}
+
+
+static int
+gm_putint (ival, value, type)
+ int ival;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = ival;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = (double) ival;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%d", ival);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_putfloat (fval, value, type)
+ double fval;
+ XtArgVal value;
+ char *type;
+{
+ switch (gm_gettype (type)) {
+ case Gt_Bool:
+ case Gt_Int:
+ *(int *)value = (int) fval;
+ break;
+ case Gt_DFloatP:
+ *(double *)value = fval;
+ break;
+ case Gt_String:
+ sprintf ((char *)value, "%g", fval);
+ break;
+ default:
+ return (ERR);
+ }
+ return (OK);
+}
+
+
+static int
+gm_gettype (type)
+ char *type;
+{
+ if (strcmp (type, XtRBool) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRInt) == 0)
+ return (Gt_Int);
+ else if (strcmp (type, XtRFloat) == 0)
+ return (Gt_DFloatP);
+ else if (strcmp (type, XtRPointer) == 0)
+ return (Gt_Pointer);
+ else if (strcmp (type, XtRString) == 0)
+ return (Gt_String);
+ else
+ return (ERR);
+}
+
+
+static int
+gm_getattribute (attribute)
+ char *attribute;
+{
+ if (strcmp (attribute, GmType) == 0)
+ return (Ga_Type);
+ else if (strcmp (attribute, GmActivated) == 0)
+ return (Ga_Activated);
+ else if (strcmp (attribute, GmVisible) == 0)
+ return (Ga_Visible);
+ else if (strcmp (attribute, GmSensitive) == 0)
+ return (Ga_Sensitive);
+ else if (strcmp (attribute, GmAutoRedraw) == 0)
+ return (Ga_AutoRedraw);
+ else if (strcmp (attribute, GmTranslations) == 0)
+ return (Ga_Translations);
+ else if (strcmp (attribute, GmX) == 0)
+ return (Ga_X);
+ else if (strcmp (attribute, GmY) == 0)
+ return (Ga_Y);
+ else if (strcmp (attribute, GmWidth) == 0)
+ return (Ga_Width);
+ else if (strcmp (attribute, GmHeight) == 0)
+ return (Ga_Height);
+ else if (strcmp (attribute, GmRotangle) == 0)
+ return (Ga_Rotangle);
+ else if (strcmp (attribute, GmHighlightColor) == 0)
+ return (Ga_HighlightColor);
+ else if (strcmp (attribute, GmLineColor) == 0)
+ return (Ga_LineColor);
+ else if (strcmp (attribute, GmLineWidth) == 0)
+ return (Ga_LineWidth);
+ else if (strcmp (attribute, GmLineStyle) == 0)
+ return (Ga_LineStyle);
+ else if (strcmp (attribute, GmKnotColor) == 0)
+ return (Ga_KnotColor);
+ else if (strcmp (attribute, GmKnotSize) == 0)
+ return (Ga_KnotSize);
+ else if (strcmp (attribute, GmFill) == 0)
+ return (Ga_Fill);
+ else if (strcmp (attribute, GmFillColor) == 0)
+ return (Ga_FillColor);
+ else if (strcmp (attribute, GmFillBgColor) == 0)
+ return (Ga_FillBgColor);
+ else if (strcmp (attribute, GmFillPattern) == 0)
+ return (Ga_FillPattern);
+ else if (strcmp (attribute, GmFillStyle) == 0)
+ return (Ga_FillStyle);
+ else if (strcmp (attribute, GmTextColor) == 0)
+ return (Ga_TextColor);
+ else if (strcmp (attribute, GmTextBgColor) == 0)
+ return (Ga_TextBgColor);
+ else if (strcmp (attribute, GmTextBorder) == 0)
+ return (Ga_TextBorder);
+ else if (strcmp (attribute, GmImageText) == 0)
+ return (Ga_ImageText);
+ else if (strcmp (attribute, GmFont) == 0)
+ return (Ga_Font);
+ else if (strcmp (attribute, GmText) == 0)
+ return (Ga_Text);
+ else if (strcmp (attribute, GmRotIndicator) == 0) /* MF020 */
+ return (Ga_RotIndicator);
+ else
+ return (ERR);
+}
+
+static void
+gm_linkafter (gm, prev)
+ register Marker gm;
+ register Marker prev;
+{
+ register GtermWidget w = gm->w;
+
+ gm->prev = prev;
+ gm->next = prev ? prev->next : NULL;
+ if (prev)
+ prev->next = gm;
+
+ if (!w->gterm.gm_tail || prev == w->gterm.gm_tail)
+ w->gterm.gm_tail = gm;
+ if (!w->gterm.gm_head)
+ w->gterm.gm_head = gm;
+
+ w->gterm.preserve_screen++;
+}
+
+
+static void
+gm_unlink (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+
+ if (gm->prev)
+ gm->prev->next = gm->next;
+ if (gm->next)
+ gm->next->prev = gm->prev;
+ if (w->gterm.gm_head == gm)
+ w->gterm.gm_head = gm->next;
+ if (w->gterm.gm_tail == gm)
+ w->gterm.gm_tail = gm->prev;
+
+ gm->prev = gm->next = NULL;
+ if (!w->gterm.gm_head)
+ w->gterm.preserve_screen = 0;
+}
+
+
+/* gm_do_callbacks -- Call any client callbacks registered for the given
+ * event type.
+ */
+static int
+gm_do_callbacks (gm, events, event, params, nparams)
+ Marker gm;
+ register int events;
+ XEvent *event;
+ String *params;
+ Cardinal nparams;
+{
+ register int n;
+ register struct markerCallback *cb;
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ int ncallbacks, status;
+
+ /* Copy the callbacks list into local memory to ensure that it is not
+ * changed by executing a callback.
+ */
+ ncallbacks = gm->ncallbacks;
+ memmove ((char *)callback, (char *)gm->callback,
+ sizeof (struct markerCallback) * GM_MAXCALLBACKS);
+
+ for (n = ncallbacks, cb = callback; --n >= 0; cb++)
+ if (cb->events & events) {
+ status = cb->func (cb->client_data,
+ gm, events, event, params, nparams);
+ if (status)
+ return (status);
+ }
+
+ return (0);
+}
+
+
+/* gm_constraint -- Handle the constraint callback. This is a client
+ * callback called when a marker position or size attribute is changed
+ * interactively at runtime. The purpose of the callback is to allow the
+ * client to apply any constraints, e.g. to keep the marker within a
+ * certain area or range of sizes, to forbid rotation, and so on.
+ */
+static int
+gm_constraint (gm, new_gm, what)
+ register Marker gm, new_gm;
+ register int what;
+{
+ register char *ip, *op;
+ char argbuf[2048];
+ char *argv[30];
+ int argc = 0;
+
+ /* Return immediately if there are no constraint callbacks. */
+ if (!gm->constraints)
+ return;
+
+ /* Prepare an argument list listing the marker attributes being changed
+ * and their old and new values. Each attribute is passed as three
+ * arg strings: name old-value new-value. Each argument string is
+ * allocated a fixed amount of space of SZ_NUMBER characters.
+ */
+ op = argbuf;
+ if (what & Gb_X) {
+ strcpy (argv[argc++]=op, "x"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->x); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->x); op += SZ_NUMBER;
+ }
+ if (what & Gb_Y) {
+ strcpy (argv[argc++]=op, "y"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->y); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->y); op += SZ_NUMBER;
+ }
+ if (what & Gb_Width) {
+ strcpy (argv[argc++]=op, "width"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->width); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->width); op += SZ_NUMBER;
+ }
+ if (what & Gb_Height) {
+ strcpy (argv[argc++]=op, "height"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", gm->height); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%d", new_gm->height); op += SZ_NUMBER;
+ }
+ if (what & Gb_Rotangle) { /* MF022 */
+ double rot = (gm->rotangle * ((double)180.0 / M_PI));
+ double new_rot = (new_gm->rotangle * ((double)180.0 / M_PI));
+ strcpy (argv[argc++]=op, "rotangle"); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", rot); op += SZ_NUMBER;
+ sprintf (argv[argc++]=op, "%g", new_rot); op += SZ_NUMBER;
+ }
+
+ /* Call any constraint callbacks. The argv value strings are modified
+ * in place.
+ */
+ gm_do_callbacks (gm, GmEvConstraint, NULL, argv, argc);
+
+ /* Copy the possibly edited values back into the new_gm struct.
+ */
+ ip = argbuf + SZ_NUMBER * 2;
+ if (what & Gb_X) {
+ new_gm->x = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Y) {
+ new_gm->y = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Width) {
+ new_gm->width = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Height) {
+ new_gm->height = atoi (ip); ip += SZ_NUMBER*3;
+ }
+ if (what & Gb_Rotangle) {
+ new_gm->rotangle = atof (ip); ip += SZ_NUMBER*3;
+
+ /* Convert back to radians.... */
+ new_gm->rotangle *= (M_PI / (double)180.0); /* MF022 */
+ }
+}
+
+
+static void
+gm_erase (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ register XRectangle *r = &gm->old_rect;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ /* Any clipping to the marker border is set outside this routine. */
+ if ((gm->flags & Gm_Visible) && !NullRect(r))
+ XCopyArea (w->gterm.display, w->gterm.pixmap, w->gterm.window,
+ w->gterm.exposeGC, r->x, r->y, r->width, r->height, r->x, r->y);
+}
+
+
+/* Marker actions.
+ * -------------------------
+ */
+
+
+/* M_create -- Create a marker.
+ */
+static void
+M_create (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int interactive, type;
+ gmSelection what;
+
+ savepos (w, event);
+
+ /* If the marker has already been created in interactive mode the event
+ * merely initializes the marker, otherwise we create and initialize a
+ * new marker.
+ */
+ if (!(gm = w->gterm.gm_create)) {
+ type = w->gterm.gm_defaultType;
+ if (*nparams == 1) {
+ if (!(type = GmStrToType (params[0])))
+ type = w->gterm.gm_defaultType;
+ }
+ gm = GmCreate (w, type, interactive=True);
+ }
+
+ gm->x = ev->x;
+ gm->y = ev->y;
+ gm->flags |= Gm_Activated;
+ w->gterm.gm_create = NULL;
+
+ what.type = (gm->type == Gm_Polygon) ? Ge_Marker : Ge_Point;
+ what.vertex = 0;
+ gm_focusin (w, gm, &what);
+}
+
+
+/* M_destroy -- Destroy a marker.
+ */
+static void
+M_destroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmDestroy (gm);
+}
+
+
+/* M_destroyNull -- Destroy a marker if it is null sized.
+ */
+static void
+M_destroyNull (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (gm && gm->width <= 2 && gm->height <= 2)
+ GmDestroy (gm);
+}
+
+
+/* M_set -- Set a marker attribute.
+ */
+static void
+M_set (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0; i < *nparams; i += 2)
+ GmSetAttribute (gm,
+ params[i], (XtArgVal)params[i+1], XtRString); /* MF010 */
+}
+
+
+/* M_raise -- Raise a marker to the top of the display list.
+ */
+static void
+M_raise (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmRaise (gm, NULL);
+}
+
+
+/* M_lower -- Lower a marker to the bottom of the display list.
+ */
+static void
+M_lower (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmLower (gm, NULL);
+}
+
+
+/* M_notify -- Notify any clients that have registered callbacks for the
+ * specified type of events.
+ */
+static void
+M_notify (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int events, i;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ for (i=0, events=0; i < *nparams; i++)
+ if (strcmp (params[i], "notify") == 0)
+ events |= GmEvNotify;
+ else if (strcmp (params[i], "moveResize") == 0)
+ events |= GmEvMoveResize;
+ else if (strcmp (params[i], "modify") == 0)
+ events |= GmEvModify;
+ else if (strcmp (params[i], "redraw") == 0)
+ events |= GmEvRedraw;
+ else if (strcmp (params[i], "destroy") == 0)
+ events |= GmEvDestroy;
+ else if (strcmp (params[i], "input") == 0)
+ events |= GmEvInput;
+ else if (strcmp (params[i], "focusIn") == 0)
+ events |= GmEvFocusIn;
+ else if (strcmp (params[i], "focusOut") == 0)
+ events |= GmEvFocusOut;
+
+ GmNotify (gm, events, event, params + 1, *nparams - 1);
+}
+
+
+/* M_input -- Notify any clients that have registered a input callback
+ * that a input event has occurred.
+ */
+static void
+M_input (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XKeyEvent *ev = (XKeyEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmNotify (gm, GmEvInput, event, params, *nparams);
+}
+
+
+/* M_markpos -- Mark the current position of the marker, e.g., so that it
+ * can later be erased.
+ */
+static void
+M_markpos (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ GmMarkpos (gm);
+}
+
+
+/* M_markposAdd -- Execute either the markpos or add action, depending upon
+ * the pointer location. If the pointer is over an active marker at a
+ * location where the add action can be executed this is done, otherwise the
+ * markpos action is executed.
+ */
+static void
+M_markposAdd (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Get marker and type of active portion of marker. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Always do a markpos whether we Add or not. */
+ GmMarkpos (gm);
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_redraw -- Redraw a marker.
+ */
+static void
+M_redraw (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+ int erase;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ /* This redraw undoes the final Xor draw. */
+ GmRedraw (gm, GXxor, erase=False);
+
+ /* Redraw the full marker. */
+ GmRedraw (gm, GXcopy, erase=True);
+}
+
+
+/* M_addPt -- Add a point.
+ */
+static void
+M_addPt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Add a point if possible for the given marker and pointer location. */
+ if (what->type == Ge_Edge &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmAddPt (gm, ev->x, ev->y);
+}
+
+
+/* M_deletePt -- Delete a point.
+ */
+static void
+M_deletePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (what->type == Ge_Point)
+ GmDeletePt (gm, ev->x, ev->y);
+}
+
+
+/* M_movePt -- Move a point.
+ */
+static void
+M_movePt (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ /* Move a point (vertex) if supported by marker type. */
+ if (what->type == Ge_Point &&
+ (gm->type == Gm_Polyline || gm->type == Gm_Polygon))
+ GmMovePt (gm, ev->x, ev->y);
+}
+
+
+/* M_deleteDestroy -- Delete a point or destroy a marker, depending upon the
+ * pointer position.
+ */
+static void
+M_deleteDestroy (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ switch (what->type) {
+ case Ge_Point:
+ GmDeletePt (gm, ev->x, ev->y);
+ break;
+ case Ge_Marker:
+ GmDestroy (gm);
+ break;
+ }
+}
+
+
+/* M_move -- Move a marker.
+ */
+static void
+M_move (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmMove (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_resize -- Resize a marker.
+ */
+static void
+M_resize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmResize (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_moveResize -- Move a point or marker, or resize a marker, depending
+ * upon the pointer position.
+ */
+static void
+M_moveResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, what)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Marker:
+ GmMove (gm, ev->x, ev->y);
+ break;
+ case Ge_Point:
+ if (gm->type == Gm_Polygon || gm->type == Gm_Polyline)
+ GmMovePt (gm, ev->x, ev->y);
+ else
+ goto resize;
+ break;
+ case Ge_Edge:
+resize: GmResize (gm, ev->x, ev->y);
+ break;
+ }
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotate -- Rotate a marker.
+ */
+static void
+M_rotate (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ GmRotate (gm, ev->x, ev->y);
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/* M_rotateResize -- Rotate or resize a marker.
+ */
+static void
+M_rotateResize (widget, event, params, nparams)
+ Widget widget;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register GtermWidget w = (GtermWidget)widget;
+ register XButtonEvent *ev = (XButtonEvent *) event;
+ GmSelection what = &w->gterm.gm_selection;
+ register Marker gm;
+
+ savepos (w, event);
+
+ /* Determine which marker gets this event. */
+ if (!(gm = w->gterm.gm_active))
+ if (!(gm = GmSelect (w, ev->x, ev->y, NULL)))
+ return;
+
+ if (ev->time - gm->time > GM_UPDATE) {
+ switch (what->type) {
+ case Ge_Point:
+ GmRotate (gm, ev->x, ev->y);
+ break;
+ case Ge_Edge:
+ if (gm->flags & Gm_Smooth)
+ GmRotate (gm, ev->x, ev->y);
+ else
+ GmResize (gm, ev->x, ev->y);
+ break;
+ default:
+ GmResize (gm, ev->x, ev->y);
+ break;
+ }
+
+ XFlush (w->gterm.display);
+ gm->time = ev->time;
+ }
+}
+
+
+/*
+ * Marker class code.
+ * ---------------------
+ * Each marker class implements a subset of the following procedures. The
+ * first set of procedures are required. The second set are optional and
+ * may be set to NULL in the marker descriptor if not implemented by the
+ * marker class.
+ *
+ * gm_xxxx_init (gm, interactive)
+ * bool = gm_xxxx_select (gm, x, y, &what)
+ * gm_xxxx_markpos (gm)
+ * gm_xxxx_redraw (gm, func)
+ * gm_xxxx_update (gm)
+ *
+ * gm_xxxx_addPt (gm, x, y)
+ * gm_xxxx_deletePt (gm, x, y)
+ * gm_xxxx_movePt (gm, x, y)
+ * gm_xxxx_move (gm, x, y)
+ * gm_xxxx_resize (gm, x, y)
+ * gm_xxxx_rotate (gm, x, y)
+ *
+ * where xxxx is the 4 character marker class name.
+ */
+
+/* Marker class TEXT.
+ */
+static int gm_text_select();
+static void gm_text_move(), gm_text_resize();
+static void gm_text_markpos(), gm_text_redraw();
+static void gm_text_update(), gm_text_updatePolygon();
+
+static void
+gm_text_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Text;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_TextLineColor;
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->textColor = w->gterm.gm_TextColor;
+ gm->textBgColor = w->gterm.gm_TextBgColor;
+ gm->textBorder = w->gterm.gm_TextBorder;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->font = w->gterm.gm_TextFont;
+ gm->imageText = False;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->npoints = 4 + 1;
+ gm->points = gm->point_data;
+
+ gm->select = gm_text_select;
+ gm->markpos = gm_text_markpos;
+ gm->redraw = gm_text_redraw;
+ gm->update = gm_text_update;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_text_move;
+ gm->resize = gm_text_resize;
+ gm->rotate = NULL;
+
+ if (w->gterm.gm_TextString) {
+ if (gm->text)
+ XtFree (gm->text);
+ gm->text = (char *) XtMalloc (strlen(w->gterm.gm_TextString)+1);
+ strcpy (gm->text, w->gterm.gm_TextString);
+ } else
+ gm->text = NULL;
+}
+
+static int
+gm_text_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+
+static void
+gm_text_markpos (gm)
+ register Marker gm;
+{
+ gm_markpos (gm);
+}
+
+
+static void
+gm_text_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+ int char_width, char_height, xsize, ysize;
+ int breakline, l_pix, r_pix, maxch, x, y;
+ XFontStruct *fp = gm->font;
+ char *ip, *op, *otop;
+ char *l_ip, *l_op;
+ char line[1024];
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ /* In rubber-band mode just draw the outline of the text region. */
+ if (function == GXxor) {
+ int save_lineWidth = gm->lineWidth;
+
+ if (gm->lineWidth <= 0)
+ gm->lineWidth = 1;
+ gm_redraw (gm, function);
+ gm->lineWidth = save_lineWidth;
+ return;
+ }
+
+ /* General case. First draw the text box. */
+ gm_redraw (gm, function);
+
+ /* Now draw the text. */
+ if (!gm->text)
+ return;
+
+ char_width = fp->max_bounds.width;
+ char_height = fp->max_bounds.ascent + fp->max_bounds.descent;
+ xsize = gm->width;
+ ysize = gm->height;
+
+ l_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1;
+ r_pix = (gm->lineWidth + 1) / 2 + gm->textBorder - 1 -
+ (fp->max_bounds.width - fp->max_bounds.rbearing);
+ if ((maxch = (xsize - l_pix - r_pix) / char_width) < 1)
+ return;
+
+ x = gm->x + (gm->lineWidth + 1) / 2 + gm->textBorder + 1;
+ y = gm->y + (gm->lineWidth + 1) / 2 + gm->textBorder +
+ fp->max_bounds.ascent;
+
+ XSetForeground (w->gterm.display, w->gterm.gm_drawGC, gm->textColor);
+ XSetBackground (w->gterm.display, w->gterm.gm_drawGC, gm->textBgColor);
+ XSetFont (w->gterm.display, w->gterm.gm_drawGC, fp->fid);
+
+ /* Fill lines in a multiline text box.
+ */
+ l_ip = l_op = NULL;
+ otop = line + maxch;
+ breakline = 0;
+
+ for (ip = gm->text, op=line; *ip || op > line; ) {
+ if (! *ip) {
+ breakline++;
+ } else if (*ip == ' ' || *ip == '\t') {
+ l_ip = ip;
+ l_op = op;
+ *op++ = ' ';
+ ip++;
+ } else if (*ip == '\n') {
+ ip++;
+ breakline++;
+ } else
+ *op++ = *ip++;
+
+ if (breakline || op > otop) {
+ if (op > otop) {
+ if (l_ip && l_op) {
+ ip = l_ip + 1;
+ *l_op = '\0';
+ } else {
+ while (op > otop) {
+ if (ip > gm->text && isprint (*(ip-1)))
+ --ip;
+ --op;
+ }
+ *op = '\0';
+ }
+ } else
+ *op = '\0';
+
+ if (gm->imageText) {
+ while (op < otop)
+ *op++ = ' ';
+ *op = '\0';
+ XDrawImageString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ } else {
+ XDrawString (w->gterm.display, w->gterm.window,
+ w->gterm.gm_drawGC, x, y, line, strlen(line));
+ }
+
+ y += char_height;
+ if (breakline)
+ y += gm->textBorder;
+ if (y + fp->max_bounds.descent > gm->y + ysize)
+ break;
+
+ op = line;
+ l_ip = l_op = NULL;
+ breakline = 0;
+ }
+ }
+}
+
+
+static void
+gm_text_update (gm)
+ register Marker gm;
+{
+ register GtermWidget w = gm->w;
+ int flags = (Gm_Activated|Gm_Visible);
+
+ if (!((gm->flags & flags) == flags))
+ return;
+ if (gm->width <= 0 || gm->height <= 0)
+ return;
+
+ if (gm->flags & Gm_Modified) {
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_text_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = max (0, x - gm->width / 2);
+ new_gm.y = max (0, y - gm->height / 2);
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y); /* corner */
+
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = abs (x - gm->x);
+ new_gm.height = abs (y - gm->y);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+ gm_text_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_text_updatePolygon (gm)
+ register Marker gm;
+{
+ register XPoint *p = gm->points;
+ int xsize = gm->width;
+ int ysize = gm->height;
+
+ p[0].x = gm->x; p[0].y = gm->y;
+ p[1].x = gm->x; p[1].y = gm->y + ysize;
+ p[2].x = gm->x + xsize; p[2].y = gm->y + ysize;
+ p[3].x = gm->x + xsize; p[3].y = gm->y;
+ p[4].x = gm->x; p[4].y = gm->y;
+}
+
+
+/* Marker class LINE.
+ */
+static void
+gm_line_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Line;
+ /* stub out for now */
+}
+
+
+/* Marker class POLYLINE.
+ */
+static void
+gm_plin_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ gm->type = Gm_Polyline;
+ /* stub out for now */
+}
+
+
+/* Marker class RECTANGLE.
+ */
+static int gm_rect_select();
+static void gm_rect_move(), gm_rect_resize(), gm_rect_rotate();
+static void gm_rect_update(), gm_rect_updatePolygon();
+
+static void
+gm_rect_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Rectangle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_rect_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_rect_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_rect_move;
+ gm->resize = gm_rect_resize;
+ gm->rotate = gm_rect_rotate;
+}
+
+static void
+gm_rect_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_rect_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_rect_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+ int ox = x, oy = y;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ if (rx < 0)
+ new_gm.x = gm->x - (-rx - gm->width) / 2;
+ else
+ new_gm.x = gm->x + (rx - gm->width) / 2;
+
+ if (ry < 0)
+ new_gm.y = gm->y - (-ry - gm->height) / 2;
+ else
+ new_gm.y = gm->y + (ry - gm->height) / 2;
+
+ new_gm.width = gm->width + (abs(rx) - gm->width) / 2;
+ new_gm.height = gm->height + (abs(ry) - gm->height) / 2;
+
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y|Gb_Width|Gb_Height);
+ gm->x = new_gm.x;
+ gm->y = new_gm.y;
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_rect_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+
+ /* V1.1 These eqns have the effect of allowing a marker to be grabbed by
+ * any corner but doing so resets the rotation angle the first time the
+ * marker is rotated.
+
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_rect_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_rect_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle);*/
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class BOX. A box marker is like a rectangle except that it is
+ * described and resized by the center and radius (width/height), like
+ * the other "centered" marker types (circle, ellipse, etc.).
+ */
+static int gm_boxx_select();
+static void gm_boxx_move(), gm_boxx_resize(), gm_boxx_rotate();
+static void gm_boxx_update(), gm_boxx_updatePolygon();
+
+static void
+gm_boxx_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Box;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_RectLineColor;
+ gm->knotColor = w->gterm.gm_RectKnotColor;
+ gm->knotSize = w->gterm.gm_RectKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = 4 + 1;
+
+ gm->select = gm_boxx_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_boxx_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_boxx_move;
+ gm->resize = gm_boxx_resize;
+ gm->rotate = gm_boxx_rotate;
+}
+
+static void
+gm_boxx_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_boxx_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Edge)
+ what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_boxx_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ struct marker new_gm;
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_boxx_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ double alpha, theta;
+ struct marker new_gm;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+ /* V1.1
+ theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));
+ alpha = atan2 ((double)gm->height, (double)gm->width);
+ new_gm.rotangle = gm_niceAngle (theta + alpha);
+ */
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_boxx_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_boxx_updatePolygon (gm)
+ Marker gm;
+{
+ register x, y;
+ register XPoint *p = gm->points;
+ double cos_rotangle, sin_rotangle;
+
+ double alpha = atan2 ((double)gm->height, (double)gm->width);
+
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ x = gm->width;
+ y = gm->height;
+
+ p[0].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[0].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[1].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[1].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y;
+ p[2].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[2].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x;
+ p[3].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[3].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ p[4] = p[0];
+}
+
+
+/* Marker class CIRCLE.
+ */
+static int gm_circ_select();
+static void gm_circ_move(), gm_circ_resize(), gm_circ_rotate();
+static void gm_circ_update(), gm_circ_updatePolygon();
+
+static void
+gm_circ_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Circle;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_CircleLineColor;
+ gm->knotColor = w->gterm.gm_CircleKnotColor;
+ gm->knotSize = w->gterm.gm_CircleKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ gm->width = gm->height = (gm->width + gm->height) / 2.0;
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_circ_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_circ_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_circ_move;
+ gm->resize = gm_circ_resize;
+ gm->rotate = NULL;
+}
+
+static void
+gm_circ_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_circ_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_circ_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.width = new_gm.height =
+ sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+
+ gm->width = gm->height = new_gm.width;
+ gm_circ_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_circ_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double theta, x, y;
+
+ /*npts = (gm->npoints - 1) / 4;*/
+ npts = gm->npoints / 4; /* MF028 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x + gm->x;
+ p[npts*0+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x + gm->x;
+ p[npts*1+j].y = y + gm->y;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x + gm->x;
+ p[npts*2+j].y = y + gm->y;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x + gm->x;
+ p[npts*3+j].y = y + gm->y;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class ELLIPSE.
+ */
+static int gm_elip_select();
+static void gm_elip_move(), gm_elip_resize(), gm_elip_rotate();
+static void gm_elip_update(), gm_elip_updatePolygon();
+
+static void
+gm_elip_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+
+ gm->type = Gm_Ellipse;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_EllipseLineColor;
+ gm->knotColor = w->gterm.gm_EllipseKnotColor;
+ gm->knotSize = w->gterm.gm_EllipseKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+ gm->flags |= Gm_Smooth;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+/* gm->npoints = GM_NPTSCIRCLE + 1;*/
+ gm->npoints = GM_NPTSCIRCLE; /* MF015 */
+
+ gm->select = gm_elip_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_elip_update;
+ gm->redraw = gm_redraw;
+ gm->addPt = NULL;
+ gm->deletePt = NULL;
+ gm->movePt = NULL;
+ gm->move = gm_elip_move;
+ gm->resize = gm_elip_resize;
+ gm->rotate = gm_elip_rotate;
+}
+
+static void
+gm_elip_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static int
+gm_elip_select (gm, x, y, what)
+ register Marker gm;
+ int x, y;
+ GmSelection what;
+{
+ if (gm_select (gm, x, y, what)) {
+ if (what && what->type == Ge_Point)
+ what->type = Ge_Edge;
+ return (1);
+ } else
+ return (0);
+}
+
+static void
+gm_elip_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_resize (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+/* double theta = -(gm->rotangle);*/
+ double theta = (gm->rotangle); /* MF019 */
+ int rx, ry;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos(theta) - y * sin(theta);
+ ry = x * sin(theta) + y * cos(theta);
+
+ /* Compute new width and height. */
+ new_gm.width = abs(rx);
+ new_gm.height = abs(ry);
+
+ gm_constraint (gm, &new_gm, Gb_Width|Gb_Height);
+ gm->width = new_gm.width;
+ gm->height = new_gm.height;
+
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_elip_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+ double theta;
+
+ if (x == gm->x && y == gm->y)
+ gm->rotangle = 0;
+ else {
+/* theta = atan2 ((double)(y - gm->y), (double)(x - gm->x));*/
+ theta = atan2 ((double)(gm->y - y), (double)(x - gm->x)); /* MF019 */
+ new_gm.rotangle = gm_niceAngle (theta);
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm_elip_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+}
+
+static void
+gm_elip_updatePolygon (gm)
+ Marker gm;
+{
+ register XPoint *p = gm->points;
+ register int npts, i, j;
+ double cos_rotangle, sin_rotangle;
+ double theta, x, y;
+
+ npts = (gm->npoints - 1) / 4 + 1; /* MF017 */
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+
+ for (i=0; i < npts; i++) {
+ theta = PI_2 / npts * i;
+ x = gm->width * cos(theta);
+ y = gm->height * sin(theta);
+
+ j = i;
+ p[npts*0+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*0+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*1+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*1+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ y = -y; j = i;
+ p[npts*2+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*2+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+
+ x = -x; j = npts-1 - i;
+ p[npts*3+j].x = x * cos_rotangle - y * sin_rotangle + gm->x + 0.5;
+ p[npts*3+j].y = x * sin_rotangle + y * cos_rotangle + gm->y + 0.5;
+ }
+
+ /*p[gm->npoints-1] = p[0];*/ /* MF015 */
+}
+
+
+/* Marker class POLYGON.
+ */
+static int gm_pgon_select();
+static void gm_pgon_addPt(), gm_pgon_deletePt(), gm_pgon_movePt();
+static void gm_pgon_move(), gm_pgon_resize(), gm_pgon_rotate();
+static void gm_pgon_redraw(), gm_pgon_update(), gm_pgon_updatePolygon();
+
+static void
+gm_pgon_init (gm, interactive)
+ register Marker gm;
+ int interactive;
+{
+ register GtermWidget w = gm->w;
+ register DPoint *p;
+
+ gm->type = Gm_Polygon;
+ if (!(gm->flags & Gm_Activated)) {
+ gm->lineWidth = w->gterm.gm_lineWidth;
+ gm->lineStyle = w->gterm.gm_lineStyle;
+ gm->highlightColor = w->gterm.gm_highlightColor;
+ gm->lineColor = w->gterm.gm_PgonLineColor;
+ gm->knotColor = w->gterm.gm_PgonKnotColor;
+ gm->knotSize = w->gterm.gm_PgonKnotSize;
+ gm->fill = w->gterm.gm_fill;
+ gm->fillStyle = w->gterm.gm_fillStyle;
+ gm->fillColor = w->gterm.gm_fillColor;
+ gm->fillBgColor = w->gterm.gm_fillBgColor;
+
+ gm->npoints = gm->pgon_npts = 4 + 1;
+ gm->points = gm->point_data;
+ if (gm->pgon)
+ XtFree ((char *)gm->pgon);
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+ gm->x = w->gterm.last_x;
+ gm->y = w->gterm.last_y;
+
+ if (p) {
+ p[0].x = -1; p[0].y = -1;
+ p[1].x = -1; p[1].y = 1;
+ p[2].x = 1; p[2].y = 1;
+ p[3].x = 1; p[3].y = -1;
+ p[4].x = -1; p[4].y = -1;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+
+ if (interactive)
+ gm->flags |= Gm_PgonInit;
+ }
+
+ if (gm->points && gm->npoints > GM_MAXVERTICES)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ /* The following gets executed when an existing non-polygon marker is
+ * turned into a polygon marker.
+ */
+ if (gm->pgon && gm->pgon_npts)
+ gm->npoints = gm->pgon_npts;
+ else {
+ gm->npoints = gm->pgon_npts = 4 + 1;
+
+ /* Start out with a small square polygon. */
+ gm->pgon = p = (DPoint *) XtMalloc (5 * sizeof (DPoint));
+
+ if (p) {
+ p[0].x = -gm->width; p[0].y = -gm->height;
+ p[1].x = -gm->width; p[1].y = gm->height;
+ p[2].x = gm->width; p[2].y = gm->height;
+ p[3].x = gm->width; p[3].y = -gm->height;
+ p[4].x = -gm->width; p[4].y = -gm->height;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ }
+ }
+
+ gm->select = gm_select;
+ gm->markpos = gm_markpos;
+ gm->update = gm_pgon_update;
+ gm->redraw = gm_pgon_redraw;
+ gm->addPt = gm_pgon_addPt;
+ gm->deletePt = gm_pgon_deletePt;
+ gm->movePt = gm_pgon_movePt;
+ gm->move = gm_pgon_move;
+ gm->resize = gm_pgon_resize;
+ gm->rotate = gm_pgon_rotate;
+}
+
+static void
+gm_pgon_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ /* The PgonInit flag is set when a polygon marker is interactively created
+ * to cause any pointer motion event to resize the marker. The first
+ * pointer up causes a redraw which clears the flag.
+ */
+ if (function != GXxor && gm->width > 1 && gm->height > 1)
+ gm->flags &= ~Gm_PgonInit;
+
+ gm_redraw (gm, function);
+}
+
+static void
+gm_pgon_update (gm)
+ register Marker gm;
+{
+ if (gm->flags & Gm_Modified) {
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+ gm->flags &= ~Gm_Modified;
+ }
+}
+
+static void
+gm_pgon_addPt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ int vertex, nbytes;
+ double rx, ry;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Add the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ nbytes = (gm->npoints + 1) * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+
+ gm->pgon = pv;
+ memmove (&pv[vertex+2], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ pv[vertex+1].x = rx;
+ pv[vertex+1].y = ry;
+ gm->npoints++;
+
+ nbytes = gm->npoints * sizeof (XPoint);
+ if (gm->npoints > GM_MAXVERTICES) {
+ if (gm->points != gm->point_data)
+ gm->points = (XPoint *) XtRealloc ((char *)gm->points, nbytes);
+ else
+ gm->points = (XPoint *) XtMalloc (nbytes);
+ } else
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_deletePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *pv;
+ register GtermWidget w = gm->w;
+ int vertex, nbytes;
+
+ if (gm->npoints <= 2)
+ return;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Delete the point. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ pv = gm->pgon;
+
+ memmove (&pv[vertex], &pv[vertex+1],
+ (gm->npoints - vertex - 1) * sizeof(DPoint));
+ gm->npoints--;
+
+ nbytes = gm->npoints * sizeof (DPoint);
+ if ((pv = (DPoint *)
+ XtRealloc ((char *)gm->pgon, nbytes)) == (DPoint *)NULL)
+ return;
+ gm->pgon = pv;
+
+ if (gm->npoints <= GM_MAXVERTICES && gm->points != gm->point_data)
+ XtFree ((char *)gm->points);
+ gm->points = gm->point_data;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_movePt (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+/* double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle)); */
+ double cos_rotangle = cos ((gm->rotangle)); /* MF019 */
+ double sin_rotangle = sin ((gm->rotangle)); /* MF019 */
+ double rx, ry;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get vertex. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+
+ /* Edit point. */
+ p->x = rx;
+ p->y = ry;
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_move (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ struct marker new_gm;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ new_gm.x = x; new_gm.y = y;
+ gm_constraint (gm, &new_gm, Gb_X|Gb_Y);
+ gm->x = new_gm.x; gm->y = new_gm.y;
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_resize (gm, x, y)
+ Marker gm;
+ int x, y;
+{
+ register DPoint *p, *q;
+ GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double theta, scale, slope, rx, ry, x1, y1, x2, y2, xi;
+ int vertex, i;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+
+ /* Get first vertex of nearest edge. */
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+ p = &gm->pgon[vertex];
+ q = p + 1;
+
+ /* Rotate reference frame so that intercept is at y=0. */
+ if (abs(rx) + abs(ry) < 1.0)
+ scale = 1.0;
+ else {
+ theta = atan2 (ry, rx);
+ cos_rotangle = cos (-theta);
+ sin_rotangle = sin (-theta);
+
+ x1 = p->x * cos_rotangle - p->y * sin_rotangle;
+ y1 = p->x * sin_rotangle + p->y * cos_rotangle;
+ x2 = q->x * cos_rotangle - q->y * sin_rotangle;
+ y2 = q->x * sin_rotangle + q->y * cos_rotangle;
+
+ /* Compute scale factor. */
+ if (y1 == y2 || x1 == x2)
+ scale = 1.0;
+ else {
+ slope = (y2 - y1) / (x2 - x1);
+ xi = x1 - y1 / slope;
+ scale = sqrt (SQR(rx) + SQR(ry)) / xi;
+ }
+ }
+
+ /* Rescale the polygon. */
+ for (i=0, p=gm->pgon; i < gm->npoints; i++, p++) {
+ p->x *= scale;
+ p->y *= scale;
+ }
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_rotate (gm, x, y)
+ register Marker gm;
+ int x, y;
+{
+ register DPoint *p;
+ register GtermWidget w = gm->w;
+ double cos_rotangle = cos (-(gm->rotangle));
+ double sin_rotangle = sin (-(gm->rotangle));
+ double alpha, beta, rx, ry;
+ double theta = atan2 ((double)(gm->y - y), (double)(x - gm->x));/* MF019 */
+ struct marker new_gm;
+ int vertex;
+
+ if (gm->flags & Gm_PgonInit) {
+ gm_pgon_resize (gm, x, y);
+ return;
+ }
+
+ if (x == gm->x && y == gm->y)
+ return;
+
+ /* Translate to the marker reference frame. */
+ x = x - gm->x;
+ y = y - gm->y;
+
+ /* Rotate back to the unrotated reference frame. */
+ rx = x * cos_rotangle - y * sin_rotangle;
+ ry = x * sin_rotangle + y * cos_rotangle;
+ if (abs(rx) + abs(ry) < 1.0)
+ return;
+
+ vertex = w->gterm.gm_selection.vertex;
+ if (vertex < 0 || vertex >= gm->npoints)
+ return;
+
+ p = &gm->pgon[vertex];
+ alpha = atan2 (p->y, p->x); /* angle btw origin & selected vertex */
+ beta = atan2 (ry, rx); /* angle btw origin & cursor position */
+
+ new_gm.rotangle = gm_niceAngle (gm->rotangle + (beta - alpha));
+
+ new_gm.rotangle = gm_niceAngle (theta); /* MF019 */
+
+ gm_constraint (gm, &new_gm, Gb_Rotangle);
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+ gm->rotangle = new_gm.rotangle;
+ gm_rotate_indicator (gm, GXxor); /* MF020 */
+
+ gm_pgon_updatePolygon (gm);
+ gm_setCurRect (gm);
+}
+
+static void
+gm_pgon_updatePolygon (gm)
+ Marker gm;
+{
+ register npts, i;
+ register DPoint *ip = gm->pgon;
+ register XPoint *op = gm->points;
+ double cos_rotangle, sin_rotangle;
+ int width, height, xp, xn, yp, yn;
+
+ npts = gm->npoints;
+/* cos_rotangle = cos (gm->rotangle);
+ sin_rotangle = sin (gm->rotangle); */
+ cos_rotangle = cos (-gm->rotangle); /* MF019 */
+ sin_rotangle = sin (-gm->rotangle); /* MF019 */
+ xp = xn = yp = yn = 0;
+
+ for (i=0; i < npts; i++, ip++, op++) {
+ /* Compute the rotated point. */
+ op->x = ip->x * cos_rotangle - ip->y * sin_rotangle + gm->x + 0.5;
+ op->y = ip->x * sin_rotangle + ip->y * cos_rotangle + gm->y + 0.5;
+
+ /* Compute a width/height estimate for the polygon.
+ */
+ if (ip->x > xp)
+ xp = ip->x;
+ else if (ip->x < xn)
+ xn = ip->x;
+
+ if (ip->y > yp)
+ yp = ip->y;
+ else if (ip->y < yn)
+ yn = ip->y;
+
+ gm->width = (xp + -xn) / 2;
+ gm->height = (yp + -yn) / 2;
+ }
+
+ gm->points[npts-1] = gm->points[0];
+ gm->pgon_npts = gm->npoints;
+}
+
+
+/* Internal procedures for above code.
+ * -----------------------------------
+ */
+
+/* gm_select -- Determine if a point is within or near a marker, and if so,
+ * determine whether the point selects a vertex, edge, or the entire marker.
+ */
+static int
+gm_select (gm, x, y, what)
+ Marker gm;
+ register int x, y;
+ GmSelection what;
+{
+ register XPoint *p, *ptop;
+ GtermWidget w = gm->w;
+ int v_dist = w->gterm.gm_nearVertex;
+ int e_dist = w->gterm.gm_nearEdge;
+ double seglen, d1, d2, s, K, frac;
+ int ncrossings, x0, y0;
+ XPoint *q;
+ int n;
+ int use_old_method = 0;
+
+ /* Determine if the point is near a vertex. */
+ for (p = gm->points, n = gm->npoints - 1; --n >= 0; p++)
+ if (abs (x - p->x) < v_dist && abs (y - p->y) < v_dist) {
+ if (what) {
+ what->type = Ge_Point;
+ what->vertex = p - gm->points;
+ }
+ return (1);
+ }
+
+ /* Determine if the point is near an edge. The test is based on the
+ * observation that when a point is near a line segment, the sum of the
+ * distances from the point to either end-point of the line segment is
+ * nearly the same as the length of the line segment.
+ */
+ p = gm->points;
+
+ ptop = p + (gm->npoints - 1); /* MF014 */
+ x0 = p->x; y0 = p->y;
+ d1 = sqrt ((double)(SQR(x - x0) + SQR(y - y0)));
+
+ for (p++; p < ptop; p++) {
+ seglen = sqrt ((double)(SQR(p->x - x0) + SQR(p->y - y0)));
+ d2 = sqrt ((double)(SQR(x - p->x) + SQR(y - p->y)));
+
+ if (abs(d1 + d2 - seglen) < e_dist) { /* MF028 */
+ if (what) {
+ what->type = Ge_Edge;
+ what->vertex = (p - 1) - gm->points;
+ }
+ return (1);
+ }
+
+ d1 = d2;
+ x0 = p->x; y0 = p->y;
+ }
+
+ /* If the marker is one of the closed polygon types, determine if the
+ * point is inside the marker.
+ */
+ switch (gm->type) {
+ case Gm_Line:
+ case Gm_Polyline:
+ return (0);
+ break;
+ case Gm_Circle:
+ d1 = sqrt ((double)(SQR(x - gm->x) + SQR(y - gm->y)));
+ if (d1 < gm->width) {
+ if (what) what->type = Ge_Marker;
+ return (1);
+ } else
+ return (0);
+ break;
+ }
+
+ if (use_old_method) {
+ for (p = gm->points, ncrossings=0; p < ptop; p++) {
+ /* Scan forward until we find a line segment that crosses Y.
+ */
+ if (p->y > y) {
+ for (p++; p < ptop && p->y >= y; p++)
+ ;
+ --p;
+ } else if (p->y < y) {
+ for (p++; p < ptop && p->y <= y; p++)
+ ;
+ --p;
+ }
+
+ /* The line segment p[0]:p[1] crosses the Y plane. If this lies
+ * entirely to the left of the X plane we can ignore it. If any
+ * portion of the line segment lies to the right of X we compute
+ * the point where the line intersects the Y plane. If this point
+ * is to the right of the X plane we have a crossing.
+ */
+ q = p + 1;
+ if (q < ptop && p->x > x || q->x > x) {
+ if (q->y == p->y)
+ frac = (double) 0.0;
+ else
+ frac = (double)(y - p->y) / (double)(q->y - p->y);
+ if ((frac * (q->x - p->x) + p->x) >= x)
+ ncrossings++;
+ }
+ }
+
+ } else {
+ float xp[64], yp[64];
+ int i;
+
+ for (i=0, p=gm->points, ncrossings=0; p <= ptop; p++, i++) {
+ xp[i] = (float) p->x;
+ yp[i] = (float) p->y;
+ }
+ ncrossings = point_in_poly (gm->npoints, xp, yp, (float)x, (float)y);
+ }
+
+ if (ncrossings & 1) {
+ if (what)
+ what->type = Ge_Marker;
+ return (1);
+ }
+
+ return (0);
+}
+
+point_in_poly (npol, xp, yp, x, y)
+int npol;
+float *xp, *yp, x, y;
+{
+ int i, j, c = 0;
+
+ for (i = 0, j = npol-1; i < npol; j = i++) {
+ if ((((yp[i] <= y) && (y < yp[j])) ||
+ ((yp[j] <= y) && (y < yp[i]))) &&
+ (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
+
+ c = !c;
+ }
+ return c;
+}
+
+
+
+
+/* gm_markpos -- Mark the current position of a marker.
+ */
+static void
+gm_markpos (gm)
+ register Marker gm;
+{
+ gm->old_rect = gm->cur_rect;
+ XUnionRegion (gm->cur_region, null_region, gm->old_region);
+}
+
+
+/* gm_redraw -- Redraw a marker expressed as a list of vertices.
+ */
+static void
+gm_redraw (gm, function)
+ register Marker gm;
+ int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ int flags = (Gm_Activated|Gm_Visible);
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+ if (!((gm->flags & flags) == flags))
+ return;
+
+ /* Fill the polygon area if indicated. */
+ if (gm->fill && function != GXxor) {
+ if (gm->fillPattern) {
+ XSetStipple (display, gc, gm->fillPattern);
+ XSetForeground (display, gc, gm->fillColor);
+ XSetBackground (display, gc, gm->fillBgColor);
+ XSetFillStyle (display, gc, gm->fillStyle);
+ } else {
+ XSetForeground (display, gc, gm->fillColor);
+ XSetFillStyle (display, gc, FillSolid);
+ }
+
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Nonconvex, CoordModeOrigin);
+ }
+
+ /* Set up the drawing GC. */
+ if (function != GXxor) {
+ XSetFunction (display, gc, function);
+ XSetFillStyle (display, gc, FillSolid);
+ XSetForeground (display, gc, (gm == w->gterm.gm_active) ?
+ gm->highlightColor : gm->lineColor);
+
+ XSetLineAttributes (display, gc,
+ gm->lineWidth +
+ ((gm == w->gterm.gm_active) ? w->gterm.gm_highlightWidth : 0),
+ gm->lineStyle,
+ CapButt,
+ (gm->type == Gm_Polygon || gm->type == Gm_Polyline) ?
+ JoinBevel : JoinMiter);
+ }
+
+ /* Draw the marker outline. */
+ if (gm->lineWidth > 0) {
+ if (gm->type == Gm_Circle ||
+ (gm->type == Gm_Ellipse && abs(gm->rotangle) < 0.01)) {
+
+ /* Special case - use X arc drawing primitive. We could use the
+ * gm->points polygon instead, as this outline polygon is
+ * maintained for all classes of marker.
+ */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+ }
+ XDrawArc (display, window, gc,
+ gm->x - gm->width, gm->y - gm->height,
+ gm->width * 2, gm->height * 2, 0, 360 * 64);
+
+ } else {
+ /* Draw marker expressed as a polygon. */
+ if (w->gterm.gm_xorFill && function == GXxor) {
+ XFillPolygon (display, window, gc,
+ gm->points, gm->npoints, Convex, CoordModeOrigin);
+ }
+ XDrawLines (display, window, gc,
+ gm->points, gm->npoints, CoordModeOrigin);
+ }
+ }
+
+ /* Draw the knots if enabled. */
+ if (function != GXxor && gm->knotSize > 0) {
+ int knotsize = gm->knotSize;
+ int halfsize = gm->knotSize / 2;
+ int i;
+
+ XSetForeground (display, gc, gm->knotColor);
+ for (i=0; i < gm->npoints; i++) {
+ XFillRectangle (display, window, gc,
+ gm->points[i].x - halfsize, gm->points[i].y - halfsize,
+ gm->knotSize, gm->knotSize);
+ }
+ }
+}
+
+
+/* gm_rotate_indicator -- Draw a line indicating the rotation angle.
+ */
+static void
+gm_rotate_indicator (gm, function) /* MF020 */
+Marker gm;
+int function;
+{
+ GtermWidget w = gm->w;
+ Display *display = w->gterm.display;
+ Window window = w->gterm.window;
+ GC gc = (function == GXxor) ? w->gterm.gm_rubberGC : w->gterm.gm_drawGC;
+
+ if (!gm->rotIndicator)
+ return ;
+
+ if (function == GXxor) {
+ if (gm->type == Gm_Polygon ||
+ gm->type == Gm_Ellipse ||
+ gm->type == Gm_Box ||
+ gm->type == Gm_Rectangle) {
+ int x, y, x2, y2;
+ double ar, cos_rotangle, sin_rotangle;
+ double alpha = atan2 ((double)gm->height,(double)gm->width);
+
+ cos_rotangle = cos ((double)(-gm->rotangle - alpha));
+ sin_rotangle = sin ((double)(-gm->rotangle - alpha));
+ ar = (double) gm->height / (double) gm->width;
+ x = (int) (ar * (gm->width / 2));
+ y = (int) (ar * (gm->height / 2));
+ x2 = x * cos_rotangle - y * sin_rotangle + gm->x;
+ y2 = x * sin_rotangle + y * cos_rotangle + gm->y;
+
+ XDrawLine (display, window, gc, gm->x, gm->y, x2, y2);
+ }
+ } else {
+ ; /* no-op at present */
+ }
+}
+
+
+/* gm_setCurRect -- Compute a bounding rectangle which completely encloses
+ * a marker (assumes that the marker is expressed as list of points).
+ */
+static void
+gm_setCurRect (gm)
+Marker gm;
+{
+ int border;
+
+ XDestroyRegion (gm->cur_region);
+ gm->cur_rect = null_rect;
+
+ if (gm->npoints <= 0)
+ gm->cur_region = XCreateRegion();
+ else {
+ gm->cur_region = XPolygonRegion (gm->points, gm->npoints, EvenOddRule);
+ border = (max (gm->lineWidth, gm->knotSize) + 1) / 2;
+ border = max (border, BORDER);
+ XShrinkRegion (gm->cur_region, -border, -border);
+ XClipBox (gm->cur_region, &gm->cur_rect);
+ }
+}
+
+
+/* gm_niceAngle -- Round a rotation angle to a "nice" value.
+ */
+static double
+gm_niceAngle (alpha)
+ double alpha;
+{
+ double tol = 0.003;
+ double beta;
+
+ if ( abs (alpha - PI_2*0) < tol)
+ beta = PI_2*0;
+ else if (abs (alpha - PI_2*1) < tol)
+ beta = PI_2*1;
+ else if (abs (alpha - PI_2*2) < tol)
+ beta = PI_2*2;
+ else if (abs (alpha - PI_2*3) < tol)
+ beta = PI_2*3;
+ else if (abs (alpha - PI_2*4) < tol)
+ beta = PI_2*0;
+ else
+ beta = alpha;
+
+ return (beta);
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/GtermP.h b/vendor/x11iraf/obm/ObmW/GtermP.h
new file mode 100644
index 00000000..9b104a05
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermP.h
@@ -0,0 +1,598 @@
+#ifndef _GtermP_h
+#define _GtermP_h
+
+#include "Gterm.h"
+
+/*
+ * GtermP -- Private definitions for the Gterm graphics widget.
+ */
+
+#define DEF_WIDTH 640
+#define DEF_HEIGHT 480
+#define MAX_RASTERS 512
+#define MAX_MAPPINGS 32
+#define SZ_NUMBER 64
+#define SZ_STATIC_CMAP 10 /* bg+fg+NColors */
+#define SZ_DYNAMIC_CMAP 201 /* bg+fg+NColors */
+#define SZ_OVERLAY_CMAP 18 /* bg+fg+NColors */
+#define MAX_SZCMAP 256 /* max size colormap */
+#define DEF_MAXCOLORS 216 /* max dynamic colors */
+#define MAX_WMWIN 32 /* max WM colormaps */
+#define MAX_REGIONS 64 /* setMapping regions */
+#define MAX_AUXTRANS 8 /* auxiliary translations */
+#define DEF_BASEPIXEL 38 /* base of custom colormap */
+#define DEF_CMAPUPDATE 60 /* seconds */
+#define DEF_CMAPSHADOW 10 /* seconds */
+#define DEF_COPYONRESIZE True /* copy pixmap on resize */
+#define DEF_WARPCURSOR False /* enable warp cursor */
+#define DEF_RAISEWINDOW False /* enable raise window */
+#define DEF_DEICONIFYWINDOW False /* enable deiconfify window */
+#define DEF_USETIMERS True /* ok to use timers */
+#define MAX_DRAW 64 /* max mappings for a draw */
+#define MAX_POINTS 4096 /* max points in polyline */
+#define GM_MAXVERTICES 64 /* max GM points w/o malloc */
+#define GM_NPTSCIRCLE 48 /* npoints circle or ellipse */
+#define GM_MAXCALLBACKS 16 /* max GM callbacks */
+#define GM_UPDATE 30 /* marker update interval */
+#define MAXNDC 32767 /* GKI/NDC scale factor */
+#define V_DIST 4 /* Close to vertex, pixels */
+#define E_DIST 1 /* Close to edge, pixels */
+
+
+#define RasterDepth 8
+#define ColormapDepth 8
+#define RGBDepth 24
+
+#define NAlphaFonts 8
+#define NDialogFonts 8
+#define NColors 8
+
+typedef void (*GmVMethod)();
+typedef int (*GmIMethod)();
+#define uchar unsigned char
+#define ushort unsigned short
+
+/* Raster definitions. */
+#define ImageRaster 1
+#define PixmapRaster 2
+
+struct raster {
+ int type;
+ int delete;
+ int width, height, depth;
+ union {
+ Pixmap pixmap;
+ XImage *ximage;
+ } r;
+ Pixmap shadow_pixmap; /* 8-bit shadow pixmap */
+};
+
+/* Colormap structure. */
+struct colormap {
+ int map;
+ int ncells;
+ struct colormap *next;
+ unsigned short r[MAX_SZCMAP];
+ unsigned short g[MAX_SZCMAP];
+ unsigned short b[MAX_SZCMAP];
+};
+
+/* mapExtent - Range of dst pixels affected by a src pixel. */
+typedef struct {
+ Position lo;
+ Position hi;
+} mapExtent, *MapExtent;
+
+/* Mappings map a source to a destination. A src or dst of zero refers to
+ * the window, a nonzero value is the raster number.
+ */
+struct mapping {
+ int mapping; /* mapping number */
+ int enabled; /* update destination */
+ int defined; /* mapping is defined */
+ int updated; /* internal params ready */
+ int refresh; /* refresh entire dest */
+ int rop; /* rasterop */
+ int src; /* source rect */
+ int st;
+ int sx, sy;
+ int snx, sny;
+ int dst; /* destination rect */
+ int dt;
+ int dx, dy;
+ int dnx, dny;
+ int scaling; /* internal parameters */
+ float xscale, yscale;
+ mapExtent *x_extent, *y_extent;
+ int *x_srcpix, *y_srcpix;
+ float *x_src, *y_src;
+ uchar *mapdata;
+ int datalen;
+ struct mapping *prev; /* previous in stack order */
+ struct mapping *next; /* next in stack order */
+};
+
+#define M_NOSCALING 0
+#define M_ZOOM 1
+#define M_INTZOOM 2
+#define M_DEZOOM 3
+
+/* The drawing context defines what happens when a drawing operation (e.g.
+ * polyline) takes place. In the simplest case (raster=0) one simply draws
+ * into the display window with no transformation or clipping. When a
+ * raster provides the drawing context, the graphics are drawn once for each
+ * active mapping defined on the raster, using the scaling and drawable
+ * defined by the mapping.
+ */
+struct drawContext {
+ int valid;
+ int raster;
+ struct raster *rp;
+ int nmappings;
+ struct mappingContext {
+ int mapping;
+ struct mapping *mp;
+ int scale;
+ float xoffset, xscale;
+ float yoffset, yscale;
+ int use_backing_store;
+ Pixmap pixmap;
+ GC drawGC;
+ int GC_private;
+ } mapContext[MAX_DRAW];
+};
+
+/* Graphics Markers. A marker is an active graphics object displayed on
+ * top of a drawing to mark a region. Markers can respond to events and
+ * move, resize, or modify themselves, optionally executing callback
+ * procedures when the marker changes state.
+ */
+
+/* Callback descriptor. */
+struct markerCallback {
+ int events;
+ GmIMethod func;
+ XtPointer client_data;
+};
+
+/* Marker selection. */
+struct markerSelection {
+ int type;
+ int vertex;
+};
+
+/* Main Marker descriptor. */
+struct marker {
+ GtermWidget w; /* backpointer to widget */
+ int type; /* marker type */
+ int flags; /* bitflags */
+ int x, y; /* position */
+ int width, height; /* size */
+ double rotangle; /* orientation */
+ XtTranslations translations; /* marker translations */
+ XRectangle old_rect; /* old bounding box */
+ Region old_region; /* old screen region */
+ XRectangle cur_rect; /* current bounding box */
+ Region cur_region; /* current screen region */
+ Time time; /* time of last marker edit */
+ struct marker *next; /* next marker */
+ struct marker *prev; /* previous marker */
+ struct marker *parent; /* set if copy */
+
+ int lineColor, lineWidth, lineStyle; /* marker attributes */
+ int highlightColor;
+ int knotColor, knotSize;
+ int fill, fillStyle;
+ int fillColor, fillBgColor;
+ Pixmap fillPattern;
+ int imageText, textBorder;
+ int textColor, textBgColor;
+ int rotIndicator; /* MF020 */
+ XFontStruct *font;
+
+ int npoints; /* marker data */
+ XPoint *points;
+ XPoint point_data[GM_MAXVERTICES+1];
+ struct dPoint *pgon;
+ int pgon_npts;
+ char *text;
+
+ GmIMethod select; /* class methods */
+ GmVMethod markpos;
+ GmVMethod redraw;
+ GmVMethod update;
+ GmVMethod addPt;
+ GmVMethod deletePt;
+ GmVMethod movePt;
+ GmVMethod move;
+ GmVMethod resize;
+ GmVMethod rotate;
+
+ int ncallbacks; /* callbacks */
+ struct markerCallback callback[GM_MAXCALLBACKS];
+ XtIntervalId focus_id;
+ int constraints;
+};
+
+/* Graphics marker bitflags.
+*/
+#define Gm_Activated 000001
+#define Gm_Visible 000002
+#define Gm_Sensitive 000004
+#define Gm_AutoRedraw 000010
+#define Gm_PgonInit 000020
+#define Gm_Smooth 000040
+#define Gm_Modified 000100
+#define Gm_BeingDestroyed 000200
+
+/* Attribute value type codes.
+*/
+#define Gt_Bool 1
+#define Gt_Int 2
+#define Gt_DFloatP 3
+#define Gt_Pointer 4
+#define Gt_String 5
+
+/* Attribute name codes.
+*/
+#define Ga_Type 1
+#define Ga_Activated 2
+#define Ga_Visible 3
+#define Ga_Sensitive 4
+#define Ga_AutoRedraw 5
+#define Ga_Translations 6
+#define Ga_X 7
+#define Ga_Y 8
+#define Ga_Width 9
+#define Ga_Height 10
+#define Ga_Rotangle 11
+#define Ga_HighlightColor 12
+#define Ga_LineColor 13
+#define Ga_LineWidth 14
+#define Ga_LineStyle 15
+#define Ga_KnotColor 16
+#define Ga_KnotSize 17
+#define Ga_Fill 18
+#define Ga_FillColor 19
+#define Ga_FillBgColor 20
+#define Ga_FillPattern 21
+#define Ga_FillStyle 22
+#define Ga_TextColor 23
+#define Ga_TextBgColor 24
+#define Ga_TextBorder 25
+#define Ga_ImageText 26
+#define Ga_Font 27
+#define Ga_Text 28
+#define Ga_RotIndicator 29 /* MF020 */
+
+/* Bitflags for selected attributes.
+*/
+#define Gb_X 00001
+#define Gb_Y 00002
+#define Gb_Width 00004
+#define Gb_Height 00010
+#define Gb_Rotangle 00020
+
+/* Codes for marker selection types.
+*/
+#define Ge_Marker 1
+#define Ge_Point 2
+#define Ge_Edge 3
+
+/* Auxiliary translation tables.
+*/
+#define T_replace 0
+#define T_augment 1
+#define T_override 2
+
+typedef struct raster *Raster;
+typedef struct mapping *Mapping;
+typedef struct drawContext *DrawContext;
+typedef struct mappingContext *MappingContext;
+typedef struct marker *Marker;
+typedef struct markerSelection gmSelection;
+typedef struct markerSelection *GmSelection;
+
+
+/* Gterm callbacks.
+*/
+typedef void (*GtCallbackProc)();
+struct gtCallback {
+ GtCallbackProc proc;
+ XtPointer client_data;
+ struct gtCallback *next;
+};
+typedef struct gtCallback GtCallback;
+
+
+/* Main Gterm widget instance descriptor.
+ */
+typedef struct {
+ /* resources */
+ XFontStruct *alphaFont1; /* graphics fonts */
+ XFontStruct *alphaFont2;
+ XFontStruct *alphaFont3;
+ XFontStruct *alphaFont4;
+ XFontStruct *alphaFont5;
+ XFontStruct *alphaFont6;
+ XFontStruct *alphaFont7;
+ XFontStruct *alphaFont8;
+
+ XFontStruct *dialogFont1; /* dialog fonts */
+ XFontStruct *dialogFont2;
+ XFontStruct *dialogFont3;
+ XFontStruct *dialogFont4;
+ XFontStruct *dialogFont5;
+ XFontStruct *dialogFont6;
+ XFontStruct *dialogFont7;
+ XFontStruct *dialogFont8;
+
+ Pixel dialogBgColor; /* default colors */
+ Pixel dialogFgColor;
+ Pixel idleCursorBgColor;
+ Pixel idleCursorFgColor;
+ Pixel busyCursorBgColor;
+ Pixel busyCursorFgColor;
+ Pixel ginmodeCursorBgColor;
+ Pixel ginmodeCursorFgColor;
+ int ginmodeBlinkInterval;
+ XColor ginmodeColors[2];
+ Pixel crosshairCursorColor;
+ String idleCursor;
+ String busyCursor;
+ String ginmodeCursor;
+ Boolean warpCursor;
+ Boolean raiseWindow;
+ Boolean deiconifyWindow;
+ Boolean useTimers;
+
+ Pixel color0;
+ Pixel color1;
+ Pixel color2;
+ Pixel color3;
+ Pixel color4;
+ Pixel color5;
+ Pixel color6;
+ Pixel color7;
+ Pixel color8;
+ Pixel color9;
+
+ String cacheRasters;
+ int maxRasters; /* raster display stuff */
+ int maxMappings;
+ int maxColors;
+
+ /* private state */
+ Display *display;
+ Screen *screen;
+ Window window;
+ Window root;
+ Visual* visual; /* ptr to non-default visual */
+ int forcePseudo8; /* force use of Pseudo 8 vis */
+
+ int w_depth; /* screen depth and visual */
+ int w_visual_class;
+
+ int raster; /* used for drawing context */
+ int delay; /* wait for display */
+ Pixmap pixmap; /* used to refresh window */
+ Pixmap d_pixmap; /* used to erase dialog area */
+ int d_saved; /* set when d_pixmap filled */
+ int d_raster; /* current display raster */
+
+ GC clearGC; /* clear pixmap */
+ GC clear8GC; /* 8-bit clear pixmap */
+ GC exposeGC; /* copy pixmap to window */
+ GC expose8GC; /* */
+ GC drawGC; /* graphics drawing */
+ GC dialogGC; /* dialog box */
+ GC cursorGC; /* crosshair cursor */
+
+ int cursor_type; /* type of cursor to display */
+ Cursor cursor; /* current cursor */
+ int full_crosshair; /* crosshair enabled */
+ int preserve_screen; /* cursor preserves screen */
+ int preserve_valid; /* saved data is valid */
+ Cursor idle_cursor; /* application is idle */
+ Cursor busy_cursor; /* application is busy */
+ Cursor ginmode_cursor; /* graphics input mode */
+ Cursor crosshair_cursor; /* graphics input mode */
+ int cursor_drawn; /* crosshair cursor drawn */
+ int cur_x, cur_y; /* crosshair cursor coords */
+ int old_width, old_height; /* size before resize */
+ int save_root; /* root window of saved cur */
+ int save_x, save_y; /* saved cursor location */
+ int last_x, last_y; /* x,y of last event */
+ int interactive; /* set if cursor read */
+ int char_size; /* not used */
+ int data_level; /* draw or erase graphics */
+ int line_style; /* solid or patterned line */
+ int line_width; /* width of line in pixels */
+ int fill_type; /* not used */
+ int color_index; /* current color index */
+ int xres, yres; /* tek logical resolution */
+ int d_xoff, d_yoff; /* dialog area offset */
+ int d_height; /* dialog area height */
+ int optcols, optrows; /* optimum screen size, chars */
+ int alpha_font; /* current alpha font index */
+ int dialog_font; /* current dialog font index */
+
+ int ncolors; /* current cmap size */
+ int haveColormap; /* colormap initialized */
+ Boolean copyOnResize; /* copy old pixmap on resize */
+ int useDefaultCM; /* use default colormap */
+ Pixel base_pixel; /* used for custom colormap */
+ String cmapName; /* private colormap name */
+ Boolean useGlobalCmap; /* use global data struct? */
+ Boolean cmapInitialize; /* forcibly install colormap */
+ Atom cmapAtom; /* atom for cmap property */
+ int cmapShadow; /* update default colormap */
+ Time cmapLastShadow; /* time of last update */
+ Boolean cmapInterpolate; /* interpolate colormap */
+ int cmapUpdate; /* update interval, seconds */
+ Time cmapLastUpdate; /* time of last update */
+
+ Pixel *cmap; /* map color number to pixval */
+ XColor *color; /* RGB color assignments */
+
+ ushort iomap[MAX_SZCMAP]; /* client i/o color map */
+ Pixel cmap_in[MAX_SZCMAP]; /* umap and cmap combined */
+ Pixel cmap_out[MAX_SZCMAP]; /* umap and cmap combined */
+ int cmap_in_valid; /* set when cmap_in computed */
+ int cmap_out_valid; /* set when cmap_out computed */
+ struct colormap *colormaps; /* list of client colormaps */
+ Window wmTop; /* top level window */
+ Window wmWindows[MAX_WMWIN]; /* custom colormap windows */
+ int n_wmWindows; /* number of WM windows */
+ int in_window; /* pointer is in window */
+ XWindowAttributes wa; /* window attributes */
+ int wa_defined; /* set when above is defined */
+
+
+ XFontStruct *alpha_fonts[NAlphaFonts]; /* alpha font index */
+ XFontStruct *dialog_fonts[NDialogFonts];/* dialog font index */
+
+ GtCallback *resetCallback; /* client setGterm callbacks */
+ GtCallback *resizeCallback; /* client resize callback */
+ GtCallback *inputCallback; /* client event input cb */
+
+ Raster rasters; /* raster descriptors */
+ int nrasters; /* number of alloced rasters */
+ Mapping mappings; /* mapping descriptors */
+ int nmappings; /* number of mappings */
+ Mapping mp_head; /* head of mapping list */
+ Mapping mp_tail; /* tail of mapping list */
+ struct drawContext draw; /* drawing context */
+
+ /* Markers */
+ Marker gm_head; /* head of marker list */
+ Marker gm_tail; /* head of marker list */
+ Marker gm_create; /* set if creating marker */
+ Marker gm_active; /* marker that has focus */
+ gmSelection gm_selection; /* active portion of marker */
+ GC gm_drawGC; /* marker drawing GC */
+ GC gm_rubberGC; /* marker rubber-band GC */
+ Cursor gm_markerCursor; /* pointer in marker */
+ Cursor gm_edgeCursor; /* pointer on marker edge */
+ Cursor gm_pointCursor; /* pointer near marker point */
+ int gm_redisplay; /* redisplay needed */
+ int gm_initialized; /* set after init */
+
+ XtTranslations defTranslations; /* gterm translations */
+ XtTranslations auxTrans[MAX_AUXTRANS]; /* auxiliary translations */
+ int auxTType[MAX_AUXTRANS]; /* translation type */
+ int nauxTrans; /* number of auxilary trans */
+ String gm_translations; /* Marker translations */
+ XtTranslations gm_defTranslations; /* default marker trans */
+ Marker gm_curTranslations; /* current translations */
+ Marker gm_reqTranslations; /* requested translations */
+ XtIntervalId gm_timer_id; /* translation request timer */
+
+ String gm_defaultMarker; /* default marker type name */
+ int gm_defaultType; /* default marker type */
+ int gm_nearEdge; /* defines area near edge */
+ int gm_nearVertex; /* defines area near Vertex */
+
+ int gm_lineWidth; /* shared attributes */
+ int gm_lineStyle;
+ Boolean gm_fill;
+ Pixel gm_fillColor;
+ Pixel gm_fillBgColor;
+ int gm_fillStyle;
+ Boolean gm_xorFill; /* fill with GXxor */
+ int gm_xorFillColor; /* xor-fill color */
+ int gm_xorFillBgColor; /* xor-fill background color */
+ int gm_highlightWidth; /* highlight width, pixels */
+ int gm_highlightColor; /* highlight color */
+ Pixel gm_cursorFgColor; /* marker cursors */
+ Pixel gm_cursorBgColor; /* marker cursors */
+
+ Pixel gm_LineLineColor; /* Lines, Polylines */
+ Pixel gm_LineKnotColor;
+ int gm_LineKnotSize;
+ Pixel gm_TextLineColor; /* Text markers */
+ Pixel gm_TextColor;
+ Pixel gm_TextBgColor; /* bkg color, image text */
+ int gm_TextBorder; /* border around text */
+ XFontStruct *gm_TextFont; /* default font */
+ String gm_TextString; /* default text */
+
+ Pixel gm_RectLineColor; /* Rectangle markers */
+ Pixel gm_RectKnotColor;
+ int gm_RectKnotSize;
+ Pixel gm_BoxLineColor; /* Box markers */
+ Pixel gm_BoxKnotColor;
+ int gm_BoxKnotSize;
+ Pixel gm_CircleLineColor; /* Circle markers */
+ Pixel gm_CircleKnotColor;
+ int gm_CircleKnotSize;
+ Pixel gm_EllipseLineColor; /* Ellipse markers */
+ Pixel gm_EllipseKnotColor;
+ int gm_EllipseKnotSize;
+ Pixel gm_PgonLineColor; /* Polygon markers */
+ Pixel gm_PgonKnotColor;
+ int gm_PgonKnotSize;
+
+ /* Deep Frame */
+ String dialogBgColorStr; /* default colors */
+ String dialogFgColorStr;
+ String idleCursorBgColorStr;
+ String idleCursorFgColorStr;
+ String busyCursorBgColorStr;
+ String busyCursorFgColorStr;
+ String ginmodeCursorBgColorStr;
+ String ginmodeCursorFgColorStr;
+ String crosshairCursorColorStr;
+
+ String color0Str;
+ String color1Str;
+ String color2Str;
+ String color3Str;
+ String color4Str;
+ String color5Str;
+ String color6Str;
+ String color7Str;
+ String color8Str;
+ String color9Str;
+
+ String gm_highlightColorStr; /* highlight color */
+ String gm_fillColorStr;
+ String gm_fillBgColorStr;
+ String gm_cursorFgColorStr; /* marker cursors */
+ String gm_cursorBgColorStr;
+ String gm_LineLineColorStr; /* Lines, Polylines */
+ String gm_LineKnotColorStr;
+ String gm_TextLineColorStr; /* Text markers */
+ String gm_TextColorStr;
+ String gm_TextBgColorStr; /* bkg color, image text */
+ String gm_RectLineColorStr; /* Rectangle markers */
+ String gm_RectKnotColorStr;
+ String gm_BoxLineColorStr; /* box */
+ String gm_BoxKnotColorStr;
+ String gm_CircleLineColorStr; /* Circle markers */
+ String gm_CircleKnotColorStr;
+ String gm_EllipseLineColorStr; /* Ellipse markers */
+ String gm_EllipseKnotColorStr;
+ String gm_PgonLineColorStr; /* Polygon markers */
+ String gm_PgonKnotColorStr;
+ String gm_PointLineColorStr; /* Point markers */
+ String gm_PointKnotColorStr;
+ /* Deep Frame */
+
+} GtermPart;
+
+typedef struct _GtermRec {
+ CorePart core;
+ GtermPart gterm;
+} GtermRec;
+
+typedef struct {int dummy;} GtermClassPart;
+
+typedef struct _GtermClassRec {
+ CoreClassPart core_class;
+ GtermClassPart gterm_class;
+} GtermClassRec;
+
+extern GtermClassRec gtermClassRec;
+
+#endif /* _GtermP_h */
diff --git a/vendor/x11iraf/obm/ObmW/GtermUtil.c b/vendor/x11iraf/obm/ObmW/GtermUtil.c
new file mode 100644
index 00000000..6bc0e720
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermUtil.c
@@ -0,0 +1,52 @@
+
+static XImage *cached_ximage = NULL; /* MF004 BEGIN */
+
+/* GetCachedXImage --
+ */
+static XImage *
+GetCachedXImage (w, pixmap, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((cached_ximage != NULL)) {
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ return (cached_ximage);
+ }
+ }
+ return(NULL);
+}
+
+
+/* DestroyCachedXImage --
+ */
+static void
+DestroyCachedXImage ()
+{
+ if (cached_ximage != NULL) {
+ XDestroyImage (cached_ximage);
+ cached_ximage = NULL;
+ }
+}
+
+
+/* NewCachedXImage --
+ */
+static void
+NewCachedXImage (w, xin, pixmap, width, height)
+ GtermWidget w;
+ XImage *xin;
+ Pixmap pixmap;
+ int width;
+ int height;
+{
+ if ((pixmap == w->gterm.pixmap) &&
+ (width == w->core.width) &&
+ (height == w->core.height)) {
+ DestroyCachedXImage();
+ cached_ximage = xin;
+ }
+} /* MF004 END */
diff --git a/vendor/x11iraf/obm/ObmW/HTML-PSformat.c b/vendor/x11iraf/obm/ObmW/HTML-PSformat.c
new file mode 100644
index 00000000..011651ab
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTML-PSformat.c
@@ -0,0 +1,1544 @@
+/* HTML-PSformat.c - Module for NCSA's Mosaic software
+ *
+ * Purpose: to parse Hypertext widget contents into appropriate PostScript
+ *
+ * Author: Ameet A. Raval & Frans van Hoesel
+ * (aar@gfdl.gov & hoesel@chem.rug.nl).
+ * send bugreports to hoesel@chem.rug.nl
+ *
+ * Institution: for Ameet A. Raval:
+ * Geophysical Fluid Dynamics Laboratory,
+ * National Oceanic and Atmospheric Administration,
+ * U.S. Department of Commerce
+ * P.O. Box 308
+ * Princeton, NJ 08542
+ * for Frans van Hoesel:
+ * Xtreme graphics software
+ * Herepoortenmolendrift 36
+ * 9711 DH Groningen
+ * The Netherlands
+ *
+ * Date: 1 aug 1993
+ * Modification: 8 nov 1993
+ * o added support for bold/italics courier
+ * o removed unused or no longer needed stuff
+ * o fixed the font alignment problem
+ * 23 nov 1993
+ * o added support for horizontal ruler
+ * o on request of Ameet, added a specific
+ * line about whome to send bugreports to
+ *
+ * Copyright: This work is the product of the United States Government,
+ * and is precluded from copyright protection. It is hereby
+ * released into the public domain.
+ *
+ * WE MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
+ * WARRANTY. WE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE
+ * USERS OF THIS SOFTWARE.
+ *
+ * pieces of code are taken from xvps by kind
+ * permission of John Bradley.
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include "HTMLP.h"
+
+#ifdef _GNU_SOURCE
+#define USE_STDARG
+#endif
+#if defined(__APPLE__) || (__APPLE_CC__ > 1151) || defined(USE_STDARG)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+
+/* Workaround for our old varargs handling on LinuxPPC systems.
+#if defined(linux) && defined(__powerpc__)
+#undef va_start
+#undef va_alist
+#undef va_dcl
+
+#define va_start(AP) __va_start_common (AP, 1)
+#define va_alist __va_1st_arg
+#define va_dcl register int va_alist; ...
+#endif
+*/
+#endif
+
+#if !defined(__DARWIN__)
+#include <malloc.h>
+#endif
+
+
+/* Fix thanks to robm. */
+/* We don't have this on our system at NOAO...
+ * #ifdef __alpha
+ * #include <Xm/VaSimple.h>
+ * #endif
+ */
+
+#define CR '\015'
+#define LF '\012'
+
+extern int SwapElements();
+
+/* the next page sizes are a compromise between letter sized paper
+ * (215.9 x 279.4 mm) and european standard A4 sized paper (210.0 x 297.0 mm).
+ * Note that PAGE_WIDTH is not the actual width of the paper
+ */
+#define TOP_MARGIN (10*72)
+#define BOT_MARGIN (0.7*72)
+#define LEFT_MARGIN (0.6*72)
+#define PAGE_HEIGHT (TOP_MARGIN - BOT_MARGIN)
+#define PAGE_WIDTH (8*72)
+
+#define F_FULLCOLOR 0
+#define F_GREYSCALE 1
+#define F_BWDITHER 2
+#define F_REDUCED 3
+
+#define L_PAREN '('
+#define R_PAREN ')'
+#define B_SLASH '\\'
+#define MAX_ASCII '\177'
+
+#ifdef _NO_PROTO
+# define ARG0(v0) ()
+# define ARG1(t1,v1) (v1) t1 v1;
+# define ARG2(t1,v1,t2,v2) (v1,v2) t1 v1;t2 v2;
+# define ARG3(t1,v1,t2,v2,t3,v3) (v1,v2,v3) t1 v1;t2 v2;t3 v3;
+# define ARG4(t1,v1,t2,v2,t3,v3,t4,v4) (v1,v2,v3,v4) t1 v1;t2 v2;t3 v3;t4 v4;
+# define ARG5(t1,v1,t2,v2,t3,v3,t4,v4,t5,v5) (v1,v2,v3,v4,v5) t1 v1;t2 v2;t3 v3;t4 v4; t5 v5;
+# define ARG1V(t1,v1,e2) (v1) t1 v1;
+#else
+# define ARG0(v0) (v0)
+# define ARG1(t1,v1) (t1 v1)
+# define ARG2(t1,v1,t2,v2) (t1 v1, t2 v2)
+# define ARG3(t1,v1,t2,v2,t3,v3) (t1 v1, t2 v2, t3 v3)
+# define ARG4(t1,v1,t2,v2,t3,v3,t4,v4) (t1 v1, t2 v2, t3 v3, t4 v4)
+# define ARG5(t1,v1,t2,v2,t3,v3,t4,v4,t5,v5) (t1 v1, t2 v2, t3 v3, t4 v4, t5 v5)
+# define ARG1V(t1,v1,e2) (t1 v1, e2)
+#endif /* _NO_PROTO */
+
+/* MONO returns total intensity of r,g,b components .33R+ .5G+ .17B */
+#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 13)
+
+/* PSconst_out outputs to the postscript buffer an array of constant
+ * strings
+ */
+#define PSconst_out(txt) {\
+ int n=(sizeof txt)/(sizeof txt[0]); \
+ int i; \
+ for (i=0; i<n; i++) { \
+ PSprintf("%s\n", txt[i]) ; \
+ } \
+}
+
+
+/* for regular-font, bold-font, italic-font, fixed-font */
+typedef enum { RF, BF, IF, FF, FB, FI } PS_fontstyle;
+
+static int PS_size, PS_len, PS_offset, PS_curr_page, PS_start_y, PS_hexi;
+static int PS_page_offset;
+static char *PS_string;
+static float Points_Pixel;
+static int Pixels_Page;
+static PS_fontstyle PS_oldfn = RF;
+static int PS_fontascent = 0;
+static int PS_oldfs = 0;
+
+static XColor fg_color, bg_color;
+
+
+/*__________________________________________________________________________
+ |
+ | GetDpi - return Dots-per-inch of the screen
+ |
+ | calculate the pixel density in dots per inch on the current widget
+ | screen
+ |
+*/
+
+static float GetDpi ARG1(HTMLWidget, hw) {
+ Screen *s = XtScreen(hw);
+ float dpi;
+
+ dpi = 25.4 * WidthOfScreen(s) / WidthMMOfScreen(s);
+ /* no earthly monitor does this */
+ if (dpi<1.0 || dpi>10000.0)
+ dpi = 72.0;
+ return dpi;
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSprintf - dynamic string concatenation function.
+ |
+ | In successive calls, the formatted string will be appended to the global
+ | output string Sp.
+ | It assumes that on each call, the length of the text appended to Sp
+ | is less than 1024.
+ | The format string is used as in printf, so you can use additional
+ | arguments.
+ |
+ | When successful, PSprintf returns the number of characters printed
+ | in this call, otherwise it returns EOF (just as printf does)
+ |
+*/
+
+#ifdef BROKEN_SOLARIS_COMPILER_STDARG
+/* "Looks like there's a bug in Sun's C compiler and the stdarg.h use
+ of va_start() in HTML-PSformat.c. Until the SunPro folks can take a
+ look at the problem, the following pre-ANSI code should workaround
+ the problem." */
+static int PSprintf ARG1V(char *,format, ...) {
+ va_dcl
+ va_list args;
+ int len;
+ char *s;
+
+ if (PS_size - PS_len < 1024) {
+ PS_size += 1024;
+ if ((s = (char *) realloc(PS_string, PS_size)) == NULL) {
+ fprintf(stderr, "PSprintf malloc failed\n");
+ return(EOF);
+ }
+ PS_string = s;
+ }
+ va_start(args);
+ len = vsprintf(PS_string+PS_len, format, args);
+ /* this is a hack to make it work on systems were vsprintf(s,.)
+ * returns s, instead of the len.
+ */
+ if (len != EOF && len != NULL)
+ PS_len += strlen(PS_string+PS_len);
+ va_end(args);
+ return(len);
+}
+#else /* not BROKEN_SOLARIS_COMPILER_STDARG */
+
+#if defined(__APPLE__) || (__APPLE_CC__ > 1151) || defined(USE_STDARG)
+static int PSprintf (char *format, ... )
+#else
+static int PSprintf (format, va_alist)
+char* format;
+va_dcl
+#endif
+{
+ int len;
+ char *s;
+ va_list args;
+
+ if (PS_size - PS_len < 1024) {
+ PS_size += 1024;
+ if ((s = (char *) realloc(PS_string, PS_size)) == NULL) {
+ fprintf(stderr, "PSprintf malloc failed\n");
+ return(EOF);
+ }
+ PS_string = s;
+ }
+#if defined(__APPLE__) || (__APPLE_CC__ > 1151) || defined(USE_STDARG)
+ va_start(args,format);
+#else
+ va_start(args);
+#endif
+ len = vsprintf(PS_string+PS_len, format, args);
+ /* this is a hack to make it work on systems were vsprintf(s,...)
+ * returns s, instead of the len.
+ */
+ if (len != EOF && len != 0)
+ PS_len += strlen(PS_string+PS_len);
+ va_end(args);
+ return(len);
+}
+#endif /* not BROKEN_SOLARIS_COMPILER_STDARG */
+
+/*__________________________________________________________________________
+ |
+ | PShex - output hex byte
+ |
+ | Append the byte "val" to an internal string buffer in hexadecimal
+ | format. If the argument "flush" is True, or if the buffer has filled
+ | up, flush the buffer to the larger postscript output buffer (using
+ | PSprintf).
+ |
+*/
+
+static int PShex ARG2(unsigned char,val, int,flush) {
+
+ static unsigned char hexline[80];
+ static char digit[] = "0123456789abcdef";
+
+ if (!flush) {
+ hexline[PS_hexi++] = (char) digit[((unsigned) val >>
+ (unsigned) 4) & (unsigned) 0x0f];
+ hexline[PS_hexi++] = (char) digit[(unsigned) val &
+ (unsigned) 0x0f];
+ }
+
+ /* Changed from ">78" to ">77" on advice of
+ debra@info.win.tue.nl (Paul De Bra). */
+ if ((flush && PS_hexi) || (PS_hexi>77)) {
+ hexline[PS_hexi] = '\0';
+ PS_hexi=0;
+ return (PSprintf("%s\n", hexline));
+ }
+ return (0);
+}
+
+
+/*__________________________________________________________________________
+ | PSfont - change font
+ |
+ | change local font in buf to "font"
+ | fontfamily indicates if the overall style is times, helvetica, century
+ | schoolbook or lucida.
+ |
+*/
+
+static void PSfont ARG3( HTMLWidget,hw, XFontStruct *,font, int,fontfamily) {
+
+ PS_fontstyle fn;
+ int style, size;
+ int fs;
+
+ static PS_fontstyle fontstyle[17] = {
+ RF, IF, BF, FF, BF, BF, BF, BF, BF,
+ BF, IF, FF, FF, FB, FI, FB, FI
+ };
+
+ static char fnchar[6][3] = {"RF", "BF", "IF", "FF", "FB", "FI"};
+
+ /* fontsizes as set in gui.c and in HTML.c (listing font is only
+ * defined in HTML.c)
+ */
+ static int fontsizes[4][3][17] = {
+ /* times font sizes */
+ 14, 14, 14, 14, 18, 17, 14, 12, 10, 8, 14, 12, 12, 14, 14, 12, 12,
+ 17, 17, 17, 17, 24, 18, 17, 14, 12, 10, 17, 14, 12, 17, 17, 14, 14,
+ 20, 20, 20, 20, 25, 24, 20, 18, 17, 14, 20, 18, 12, 20, 20, 18, 18,
+ /* helvetica sizes */
+ 14, 14, 14, 14, 18, 17, 14, 12, 10, 8,
+ 14, 12, 12, 14, 14, 12, 12,
+ 17, 17, 17, 17, 24, 18, 17, 14, 12, 10,
+ 17, 14, 12, 17, 17, 14, 14,
+ 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
+ 20, 18, 12, 20, 20, 18, 18,
+ /* new century schoolbook sizes */
+ 14, 14, 14, 14, 18, 17, 14, 12, 10, 8,
+ 14, 12, 12, 14, 14, 12, 12,
+ 18, 18, 18, 18, 24, 18, 17, 14, 12, 10,
+ 18, 14, 12, 18, 18, 14, 14,
+ 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
+ 20, 18, 12, 20, 20, 18, 18,
+ /* lucida sizes */
+ 14, 14, 14, 14, 18, 17, 14, 12, 11, 10,
+ 14, 12, 12, 14, 14, 12, 12,
+ 17, 17, 17, 17, 24, 18, 17, 14, 12, 10,
+ 17, 14, 12, 17, 17, 14, 14,
+ 20, 20, 20, 20, 25, 24, 20, 18, 17, 14,
+ 20, 18, 12, 20, 20, 18, 18
+ };
+
+ /* next is for each fontfamily the ascent value as given by the
+ * medium sized bold x-font (the regular font has the same
+ * ascent value for both the medium and the large size Century
+ * font).
+ * it is use in the check for the fontsize (small, medium, large)
+ */
+ static int medium_fontascent[4] = {
+ 14, 14, 16, 15
+ };
+
+ /* for each fontfamily, for each fontsize, and for each font style
+ * give the ascent value, so the output from Postscript is correct.
+ * If the value is given between parenthesis, then it is different
+ * from the value as stored in the x-font.
+ * Note that this is a fix, and need to be changed, if the browser
+ * is fixed (in the current version 1.2 the baseline of various fonts
+ * is not aligned very well).
+ */
+ static int fontascent[4][3][17] = {
+ /*rg, itl, bld, fix, h1, h2, h3, h4, h5, h6,
+ add, pla, lis, fixbold, fixital, plabold, plaital, */
+ /* times */
+ 12 ,(11), 12 ,(10),(15),(14), 12 ,(10), (8), (6),
+ 11 , (9), 10, 10 , 10 , (9), (9),
+ (13),(13),(14),(12),(20),(15),(14), 12 ,(10), (8),
+ 13 ,(10), 10 ,(12),(12),(10),(10),
+ (16),(15),(15),(13),(21),(20),(15),(15),(14), 12 ,
+ 15 ,(13), 10,(13),(13),(13),(13),
+ /* helvetica */
+ (12),(12),(12),(10),(15),(14),(12),(10), (9), (7),
+ (12), (9), 10 ,(10),(10), (9), (9),
+ (14),(14),(14),(12),(22),(15),(14),(12),(10), (9),
+ (14),(10), 10 ,(12),(12),(10),(10),
+ (16),(16),(16),(13),(22),(22),(16),(15),(14),(12),
+ (16),(13), 10 ,(13),(13),(13),(13),
+ /* new century schoolbook */
+ (12),(12), 13 ,(10),(16), 14 , 13 ,(10), (9), (7),
+ (12), (9), 10 ,(10),(10), (9), (9),
+ (16),(14),(16),(13),(22),(16), 14 , 13 ,(10), (9),
+ (14),(10), 10 ,(13),(13),(10),(10),
+ (17),(16),(17),(13),(22),(22),(17),(16), 14 , 13 ,
+ (16),(13), 10 ,(13),(13),(13),(13),
+ /* lucida bright */
+ 11 ,(11), 11 ,(11),(15),(14), 11 ,(10), (9), (7),
+ 11 , (9), 10, 11 , 10 , (9), (9),
+ (14),(15),(14),(13),(20),(15),(14), 11 ,(10), (7),
+ 15 ,(11), 10 ,(13),(13),(11),(10),
+ (17),(17),(17),(16),(21),(20),(17),(15),(14), 11 ,
+ 17 ,(14), 10,(16),(13),(14),(13)
+ };
+
+ /* NULL case - reflush old font or the builtin default: */
+ if (hw==NULL || font==NULL) {
+ if (PS_oldfs != 0)
+ PSprintf( "%2s %d SF\n", fnchar[PS_oldfn], PS_oldfs);
+ return;
+ }
+ /* added the next line in case xmosaic version 199.4 has more fonts */
+ style = 3;
+
+ if (font == hw->html.font) {
+ style = 0;
+ } else if (font == hw->html.italic_font) {
+ style = 1;
+ } else if (font == hw->html.bold_font) {
+ style = 2;
+ } else if (font == hw->html.fixed_font) {
+ style = 3;
+ } else if (font == hw->html.header1_font) {
+ style = 4;
+ } else if (font == hw->html.header2_font) {
+ style = 5;
+ } else if (font == hw->html.header3_font) {
+ style = 6;
+ } else if (font == hw->html.header4_font) {
+ style = 7;
+ } else if (font == hw->html.header5_font) {
+ style = 8;
+ } else if (font == hw->html.header6_font) {
+ style = 9;
+ } else if (font == hw->html.address_font) {
+ style = 10;
+ } else if (font == hw->html.plain_font) {
+ style = 11;
+ } else if (font == hw->html.listing_font) {
+ style = 12;
+ } else if (font == hw->html.fixedbold_font) {
+ style = 13;
+ } else if (font == hw->html.fixeditalic_font) {
+ style = 14;
+ } else if (font == hw->html.plainbold_font) {
+ style = 15;
+ } else if (font == hw->html.plainitalic_font) {
+ style = 16;
+ }
+
+ /* check size, by looking at the size of the regular font */
+ size = 1;
+ if (hw->html.bold_font->ascent > medium_fontascent[fontfamily]) {
+ /* large font */
+ size = 2;
+ } else if (hw->html.bold_font->ascent < medium_fontascent[fontfamily]) {
+ /* small font */
+ size = 0;
+ }
+ fn = fontstyle[style];
+ fs = fontsizes[fontfamily][size][style];
+ PS_fontascent = fontascent[fontfamily][size][style];
+
+ if (fn != PS_oldfn || fs != PS_oldfs) {
+ PSprintf( "%2s %d SF\n", fnchar[fn], fs);
+ PS_oldfn=fn, PS_oldfs=fs;
+ }
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSshowpage - end of page function
+ |
+ | show the current page and restore any changes to the printer state
+ |
+*/
+
+static void PSshowpage ARG0(void) {
+
+ PSprintf("showpage restore\n");
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSnewpage - begin a fresh page
+ |
+ | increment the page count and handle the structured comment
+ | conventions
+ |
+*/
+
+static void PSnewpage ARG0(void) {
+
+ PS_curr_page++;
+
+ /* the PostScript reference Manual states that the Page: Tag
+ should have a label and a ordinal; otherwise programs like
+ psutils fail -gustaf */
+ PSprintf("%%%%Page: %d %d\n", PS_curr_page, PS_curr_page);
+ PSprintf("save\nNP\n");
+ PSfont( NULL, NULL, 0); /* force re-flush of last font used */
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSinit_latin1 - handle ISO encoding
+ |
+ | print out initializing PostScript text for ISO Latin1 font encoding
+ | This code is copied from the Idraw program (from Stanford's InterViews
+ | package), courtesy of Steinar Kjaernsr|d, steinar@ifi.uio.no
+ |
+*/
+
+static void PSinit_latin1 ARG0(void) {
+
+ static char *txt[] = {
+
+ "/reencodeISO {",
+ "dup dup findfont dup length dict begin",
+ "{ 1 index /FID ne { def }{ pop pop } ifelse } forall",
+ "/Encoding ISOLatin1Encoding D",
+ "currentdict end definefont",
+ "} D",
+ "/ISOLatin1Encoding [",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright",
+ "/parenleft/parenright/asterisk/plus/comma/minus/period/slash",
+ "/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon",
+ "/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N",
+ "/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright",
+ "/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m",
+ "/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef",
+ "/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve",
+ "/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut",
+ "/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar",
+ "/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot",
+ "/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior",
+ "/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine",
+ "/guillemotright/onequarter/onehalf/threequarters/questiondown",
+ "/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla",
+ "/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex",
+ "/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis",
+ "/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute",
+ "/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis",
+ "/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave",
+ "/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex",
+ "/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis",
+ "/yacute/thorn/ydieresis",
+ "] D",
+ "[RF BF IF FF FB FI] {reencodeISO D} forall"
+ };
+
+ PSconst_out(txt);
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSinit - initialize Postscript output
+ |
+ | does the initialization per html document
+ |
+*/
+
+static void PSinit ARG0(void) {
+ PS_size = PS_len = PS_offset = PS_hexi = PS_page_offset = 0;
+ PS_start_y = 0;
+ PS_string = (char *) malloc(1);
+ PS_oldfs = 0;
+ PS_oldfn = RF;
+ PS_curr_page = 0 ;
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSheader - initialize Postscript output
+ |
+ | prints out the prolog
+ |
+*/
+
+static void PSheader ARG2(char *,title, int,font) {
+
+ static char *fontname[] = {
+ /* in order: regular, bold, italic */
+ "Times-Roman", "Times-Bold", "Times-Italic",
+ "Helvetica", "Helvetica-Bold", "Helvetica-Oblique",
+ "NewCenturySchlbk-Roman", "NewCenturySchlbk-Bold",
+ "NewCenturySchlbk-Italic",
+ /* this is a nasty trick, I have put Times in place of
+ * Lucida, becaus emost printers don't have Lucida font
+ */
+ "Times-Roman", "Times-Bold", "Times-Italic"
+ /* "Lucida", "Lucida-Bold", "Lucida-Italic" */
+ };
+
+ static char *txt[] = {
+
+ "%%Creator: NCSA Mosaic, Postscript by Ameet Raval & Frans van Hoesel",
+ "%%Pages: (atend)",
+ "%%EndComments",
+ "save",
+ "/D {def} def /E {exch} D",
+ "/M {moveto} D",
+ "/S {show} D",
+ "/R {rmoveto} D",
+ "/L {lineto} D",
+ "/RL {rlineto} D",
+ "/SQ {newpath 0 0 M 0 1 L 1 1 L 1 0 L closepath} D",
+ "/U {gsave currentpoint currentfont /FontInfo get /UnderlinePosition get",
+ " 0 E currentfont /FontMatrix get dtransform E pop add newpath moveto",
+ " dup stringwidth rlineto stroke grestore S } D",
+ "/B {/r E D gsave -13 0 R currentpoint ",
+ " newpath r 0 360 arc closepath fill grestore } D",
+ "/OB {/r E D gsave -13 0 R currentpoint ",
+ " newpath r 0 360 arc closepath stroke grestore } D",
+ "/NP {xmargin topmargin translate scalfac dup scale } D",
+ "/HR {/l E D gsave l 0 RL stroke grestore } D",
+ "/SF {E findfont E scalefont setfont } D",
+ "/FF {/Courier } D",
+ "/FB {/Courier-Bold } D",
+ "/FI {/Courier-Oblique } D"
+ };
+
+
+ PSprintf("%%!PS-Adobe-1.0\n");
+ if (title)
+ {
+ char *tmp;
+ for (tmp = title; *tmp; tmp++)
+ if (*tmp == CR || *tmp == LF)
+ *tmp = ' ';
+ PSprintf("%%%%Title: %s\n", title);
+ }
+ PSprintf("%%%%DocumentFonts: %s %s %s Courier Courier-Bold Courier-Oblique\n",
+ fontname[font*3], fontname[font*3+1], fontname[font*3+2]);
+ PSconst_out(txt);
+ PSprintf("/RF {/%s} D\n", fontname[font*3]);
+ PSprintf("/BF {/%s} D\n", fontname[font*3+1]);
+ PSprintf("/IF {/%s} D\n", fontname[font*3+2]);
+
+ PSinit_latin1();
+
+ PSprintf("/xmargin %d D\n", (int) LEFT_MARGIN);
+ PSprintf("/topmargin %d D\n", (int) TOP_MARGIN);
+ PSprintf("/scalfac %.5f D\n", Points_Pixel);
+ PSprintf("%%%%EndProlog\n");
+
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PStrailer - write postscript trailer
+ |
+*/
+
+static void PStrailer ARG0(void) {
+
+ PSprintf("%%%%Trailer\n");
+ PSprintf("restore\n");
+ PSprintf("%%%%Pages: %d\n", PS_curr_page);
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PStext - output text
+ |
+ | show text "t", and protect special characters if needed
+ | if Underline is non-zero, the text is underlined.
+ |
+*/
+
+static void PStext ARG2(String,t, int,underline) {
+ String tp, t2;
+ int nspecial=0, nisochar=0;
+
+ tp=t;
+ /* count # of special char's in text */
+ while (*tp != '\0') {
+ if (*tp == L_PAREN || *tp == R_PAREN || *tp == B_SLASH)
+ nspecial++;
+ else if (*(unsigned char *)tp > (unsigned char )MAX_ASCII)
+ nisochar++;
+ tp++;
+ }
+
+ if (nspecial == 0 && nisochar == 0) {
+ /* no special char's, send out original string */
+ PSprintf("(%s)%c\n", t, (underline)?'U':'S');
+ return;
+ }
+ /* create t2 to hold original text + "\"'s */
+ t2 = (String) malloc((tp-t) + nspecial + 3*nisochar + 1);
+
+ if (t2==NULL) {
+ fprintf(stderr, "PStext malloc failed\n");
+ return;
+ }
+
+ /* for each char in t, if it is a special char, insert "\"
+ * into the new string t2, then insert the actual char
+ */
+ tp = t2;
+ while (*t != '\0') {
+ if (*t == L_PAREN || *t == R_PAREN || *t == B_SLASH) {
+ *(tp++) = B_SLASH;
+ *(tp++) = *t;
+ } else if (*(unsigned char *)t > (unsigned char) MAX_ASCII) {
+ /* convert to octal */
+ *(tp++) = B_SLASH;
+ *(tp++) = ((int)(*(unsigned char *)t)>>6 & 007) + '0';
+ *(tp++) = ((int)(*(unsigned char *)t)>>3 & 007) + '0';
+ *(tp++) = ((int)(*(unsigned char *)t) & 007) + '0';
+ } else {
+ *(tp++) = *t;
+ }
+ t++;
+ }
+ *(tp) = '\0';
+ PSprintf("(%s)%c\n", t2, (underline)?'U':'S');
+
+ free(t2);
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSbullet - output a bullet
+ |
+ | the bullet is normally filled, except for a bullet with an indent level
+ | of two. The size of the higher level bullets is just somewhat smaller
+ |
+*/
+
+static void PSbullet ARG2( int, level, int, size) {
+
+ if (size < 6) size = 6;
+
+ if (level <2 )
+ PSprintf( " %f B\n", size/5.5);
+ else if (level == 2)
+ PSprintf( " %f OB\n", size/5.5);
+ else
+ PSprintf(" %f B\n", size/7.5);
+}
+
+/*__________________________________________________________________________
+ |
+ | PShrule - draw a horizontal line with the given width
+ |
+ | nothing special, just draw a line, from the current position to
+ | the right side of the paper.
+ |
+*/
+
+static void PShrule ARG1(int, length) {
+
+ PSprintf("%d HR\n", length);
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSmoveto - move to new x,y location
+ |
+ | if the Y value does not fit on the current page, begin a new page
+ | (I think in the current implementation, this never happens)
+ |
+*/
+
+static void PSmoveto ARG2( int,x, int,y) {
+
+ if (y > PS_start_y + Pixels_Page) {
+ PS_start_y = y;
+ PSshowpage();
+ PSnewpage();
+ }
+ PS_offset = 0;
+ PSprintf( "%d %d M\n", x, -(y - PS_start_y));
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSmove_offset - set Y-offset
+ |
+ | do a relative vertical move, whenever the offset changes
+ |
+*/
+
+static void PSmove_offset ARG1( int, offset) {
+
+ if (offset != PS_offset) {
+ PSprintf("0 %d R\n", PS_offset - offset );
+ PS_offset = offset;
+ }
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSrle_encode - perform run length encoding
+ |
+ | does the run-length encoding. This is done to reduce the file size and
+ | therefore the time to send the file to the printer. You get longer
+ | processing time instead.
+ |
+ | rle is encoded as such:
+ | <count> <value> # 'run' of count+1 equal pixels
+ | <count | 0x80> <count+1 data bytes> # count+1 non-equal pixels
+ | count can range between 0 and 127
+ |
+ | returns length of the rleline vector
+ |
+*/
+
+static int PSrle_encode ARG3(unsigned char *, scanline,
+ unsigned char *,rleline,
+ int,wide)
+{
+ int i, j, blocklen, isrun, rlen;
+ unsigned char block[256], pix;
+
+ blocklen = isrun = rlen = 0;
+
+ for (i=0; i<wide; i++) {
+ /* there are 5 possible states:
+ * 0: block empty.
+ * 1: block is a run, current pix == previous pix
+ * 2: block is a run, current pix != previous pix
+ * 3: block not a run, current pix == previous pix
+ * 4: block not a run, current pix != previous pix
+ */
+
+ pix = scanline[i];
+
+ if (!blocklen) {
+ /* case 0: empty */
+ block[blocklen++] = pix;
+ isrun = 1;
+ } else if (isrun) {
+ if (pix == block[blocklen-1]) {
+ /* case 1: isrun, prev==cur */
+ block[blocklen++] = pix;
+ } else {
+ /* case 2: isrun, prev!=cur */
+ if (blocklen>1) {
+ /* we have a run block to flush */
+ rleline[rlen++] = blocklen-1;
+ rleline[rlen++] = block[0];
+ /* start new run block with pix */
+ block[0] = pix;
+ blocklen = 1;
+ } else {
+ isrun = 0;
+ /* blocklen<=1, turn into non-run */
+ block[blocklen++] = pix;
+ }
+ }
+ } else {
+ /* not a run */
+ if (pix == block[blocklen-1]) {
+ /* case 3: non-run, prev==cur */
+ if (blocklen>1) {
+ /* have a non-run block to flush */
+ rleline[rlen++] = (blocklen-1) | 0x80;
+ for (j=0; j<blocklen; j++)
+ rleline[rlen++] = block[j];
+ /* start new run block with pix */
+ block[0] = pix;
+ blocklen = isrun = 1;
+ } else {
+ isrun = 1;
+ /* blocklen<=1 turn into a run */
+ block[blocklen++] = pix;
+ }
+ } else {
+ /* case 4: non-run, prev!=cur */
+ block[blocklen++] = pix;
+ }
+ }
+
+ if (blocklen == 128) { /* max block length. flush */
+ if (isrun) {
+ rleline[rlen++] = blocklen-1;
+ rleline[rlen++] = block[0];
+ } else {
+ rleline[rlen++] = (blocklen-1) | 0x80;
+ for (j=0; j<blocklen; j++)
+ rleline[rlen++] = block[j];
+ }
+ blocklen = 0;
+ }
+ }
+
+ if (blocklen) { /* flush last block */
+ if (isrun) {
+ rleline[rlen++] = blocklen-1;
+ rleline[rlen++] = block[0];
+ } else {
+ rleline[rlen++] = (blocklen-1) | 0x80;
+ for (j=0; j<blocklen; j++)
+ rleline[rlen++] = block[j];
+ }
+ }
+
+ return rlen;
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PScolor_image - created postscript colorimage operator
+ |
+ | spits out code that checks if the PostScript device in question
+ | knows about the 'colorimage' operator. If it doesn't, it defines
+ | 'colorimage' in terms of image (ie, generates a greyscale image from
+ | RGB data)
+ |
+*/
+
+static void PScolor_image ARG0(void) {
+
+ static char *txt[] = {
+
+ "% define 'colorimage' if it isn't defined",
+ "% ('colortogray' and 'mergeprocs' come from xwd2ps",
+ "% via xgrab)",
+ "/colorimage where % do we know about 'colorimage'?",
+ " { pop } % yes: pop off the 'dict' returned",
+ " { % no: define one",
+ " /colortogray { % define an RGB->I function",
+ " /rgbdata exch store % call input 'rgbdata'",
+ " rgbdata length 3 idiv",
+ " /npixls exch store",
+ " /rgbindx 0 store",
+ " /grays npixls string store % str to hold the result",
+ " 0 1 npixls 1 sub {",
+ " grays exch",
+ " rgbdata rgbindx get 20 mul % Red",
+ " rgbdata rgbindx 1 add get 32 mul % Green",
+ " rgbdata rgbindx 2 add get 12 mul % Blue",
+ " add add 64 idiv % I = .5G + .31R + .18B",
+ " put",
+ " /rgbindx rgbindx 3 add store",
+ " } for",
+ " grays",
+ " } bind def\n",
+ /* Utility procedure for colorimage operator.
+ * This procedure takes two procedures off the
+ * stack and merges them into a single procedure
+ */
+ " /mergeprocs { % def",
+ " dup length",
+ " 3 -1 roll dup length dup 5 1 roll",
+ " 3 -1 roll add array cvx dup",
+ " 3 -1 roll 0 exch putinterval",
+ " dup 4 2 roll putinterval",
+ " } bind def\n",
+ " /colorimage { % def",
+ /* remove 'false 3' operands */
+ " pop pop",
+ " {colortogray} mergeprocs",
+ " image",
+ " } bind def",
+ /* end of 'false' case */
+ " } ifelse"
+ };
+
+ PSconst_out(txt);
+}
+
+/*__________________________________________________________________________
+ |
+ | PScolormap - write colormap
+ |
+ | spits out code for the colormap of the following image
+ | if !color, it spits out a mono-ized graymap
+ |
+*/
+
+static void PScolormap ARG5(int,color,
+ int,nc,
+ int *,rmap,
+ int *,gmap,
+ int *,bmap) {
+
+ int i;
+
+ /* define the colormap */
+ PSprintf("/cmap %d string def\n\n\n", nc * ((color) ? 3 : 1));
+
+ /* load up the colormap */
+ PSprintf("currentfile cmap readhexstring\n");
+
+ for (i=0; i<nc; i++) {
+ if (color)
+ PSprintf("%02x%02x%02x ", rmap[i]>>8,
+ gmap[i]>>8, bmap[i]>>8);
+ else
+ PSprintf("%02x ", MONO(rmap[i], gmap[i], bmap[i]));
+ if ((i%10) == 9)
+ PSprintf("\n");
+ }
+ PSprintf("\n");
+ PSprintf("pop pop\n"); /* lose return values from readhexstring */
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSrle_cmapimage - define rlecmapimage operator
+ |
+*/
+
+static void PSrle_cmapimage ARG1(int,color) {
+
+ static char *txt[] = {
+
+ /* rlecmapimage expects to have 'w h bits matrix' on stack */
+ "/rlecmapimage {",
+ " /buffer 1 string def",
+ " /rgbval 3 string def",
+ " /block 384 string def",
+ " { currentfile buffer readhexstring pop",
+ " /bcount exch 0 get store",
+ " bcount 128 ge",
+ " { ",
+ " 0 1 bcount 128 sub",
+ " { currentfile buffer readhexstring pop pop"
+ };
+
+ static char *txt_color[] = {
+ " /rgbval cmap buffer 0 get 3 mul 3 getinterval store",
+ " block exch 3 mul rgbval putinterval",
+ " } for",
+ " block 0 bcount 127 sub 3 mul getinterval",
+ " }",
+ " { ",
+ " currentfile buffer readhexstring pop pop",
+ " /rgbval cmap buffer 0 get 3 mul 3 getinterval store",
+ " 0 1 bcount { block exch 3 mul rgbval putinterval } for",
+ " block 0 bcount 1 add 3 mul getinterval",
+ " } ifelse",
+ " }",
+ " false 3 colorimage",
+ "} bind def"
+ };
+
+ static char *txt_gray[] = {
+ " /rgbval cmap buffer 0 get 1 getinterval store",
+ " block exch rgbval putinterval",
+ " } for",
+ " block 0 bcount 127 sub getinterval",
+ " }",
+ " { ",
+ " currentfile buffer readhexstring pop pop",
+ " /rgbval cmap buffer 0 get 1 getinterval store",
+ " 0 1 bcount { block exch rgbval putinterval } for",
+ " block 0 bcount 1 add getinterval",
+ " } ifelse",
+ " }",
+ " image",
+ "} bind def"
+ };
+
+ PSconst_out(txt);
+ if (color) {
+ PSconst_out(txt_color);
+ } else {
+ PSconst_out(txt_gray);
+ }
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSwrite_bw - write B&W image
+ |
+ | Write the given image array 'pic' (B/W stippled, 1 byte per pixel,
+ | 0=blk,1=wht) out as hexadecimal, max of 72 hex chars per line. If
+ | 'flipbw', then 0=white, 1=black. Returns '0' if everythings fine,
+ | 'EOF' if writing failed.
+ |
+*/
+
+static int PSwrite_bw ARG4(unsigned char *,pic, int,w, int,h, int,flipbw) {
+
+ int i, j;
+ int err=0;
+ unsigned char outbyte, bitnum, bit;
+
+ outbyte = bitnum = 0;
+ for (i=0; i<h && err != EOF; i++) {
+ for (j=0; j<w && err != EOF; j++) {
+ bit = *(pic++);
+ outbyte = (outbyte<<1) | ((bit)&0x01);
+ bitnum++;
+
+ if (bitnum==8) {
+ if (flipbw)
+ outbyte = ~outbyte & 0xff;
+ err=PShex(outbyte, False);
+ outbyte = bitnum = 0;
+ }
+ }
+ if (bitnum) { /* few bits left over in this row */
+ outbyte <<= 8-bitnum;
+ if (flipbw)
+ outbyte = ~outbyte & 0xff;
+ err=PShex(outbyte, False);
+ outbyte = bitnum = 0;
+ }
+ }
+ err=PShex('\0', True); /* Flush the hex buffer if needed */
+
+ return err;
+}
+
+
+/*__________________________________________________________________________
+ |
+ | PSimage - generate image Postscript code
+ |
+ | Draw the image, unless there was no image, in which case an empty grey
+ | rectangle is shown.
+ | If anchor is set, a black border is shown around the image.
+ | Positioning is not exactly that of Xmosaic's screen, but close enough.
+ |
+*/
+
+static void PSimage ARG2( ImageInfo *,img , int, anchor) {
+
+ int ncolors = img->num_colors;
+ int i, j;
+ int w = img->width;
+ int h = img->height;
+ unsigned char *imgp;
+ int slen, colorps, colortype, bits;
+ int err=0;
+ int extra = 0;
+
+ imgp = img->image_data;
+
+ /* Isgray returns true if the nth color index is a gray value */
+# define Isgray(i,n) (i->reds[n]==i->greens[n] && i->reds[n]==i->blues[n])
+ /* Is_bg returns true if the nth color index is the screen background */
+# define Is_bg(i,n) (i->reds[n]==bg_color.red && \
+ i->greens[n]==bg_color.green && i->blues[n]==bg_color.blue)
+ /* Is_fg returns true if the nth color index is the screen foreground */
+# define Is_fg(i,n) (i->reds[n]==fg_color.red && \
+ i->greens[n]==fg_color.green && i->blues[n]==fg_color.blue)
+
+
+ if (anchor) {
+ /* draw an outline by drawing a slightly larger black square
+ * below the actual image
+ */
+ PSprintf("gsave currentpoint %d sub translate ", h);
+ PSprintf("0 -2 translate %d %d scale\n", w+4, h+4);
+ PSprintf("SQ fill\n");
+ PSprintf("grestore\n");
+ extra = 4;
+ }
+
+ if (imgp == NULL) {
+ /* image was not available... do something instead
+ * draw an empty square for example
+ */
+ PSprintf("gsave currentpoint %d sub translate", h);
+ if (anchor)
+ PSprintf(" 2 0 translate");
+ else
+ PSprintf(" 0 2 translate");
+ PSprintf(" %d %d scale\n", w, h);
+ PSprintf("0.9 setgray SQ fill\n");
+ PSprintf("grestore\n");
+ /* move currentpoint just right of image */
+ PSprintf("%d 0 R\n", w+extra);
+ return;
+ }
+
+ /* this is a hack to see if the image is Black & White,
+ * Greyscale or 8 bit color
+ * assume it's bw if it has only one or two colors, both some grey's
+ * assume it's greyscale if all the colors (>2) are grey
+ * Images with only one color do occur too.
+ */
+
+ if ((ncolors == 2 && ( (Isgray(img,0) && Isgray(img,1)) ||
+ (Is_bg(img,0) && Is_fg(img,1)) ||
+ (Is_fg(img,0) && Is_bg(img,1)) )) ||
+ ncolors == 1 && (Isgray(img,0) || Is_bg(img,0) ||
+ Is_fg(img,0))) {
+ colortype = F_BWDITHER;
+ slen = (w+7)/8;
+ bits = 1;
+ colorps = 0;
+ } else {
+ colortype = F_GREYSCALE;
+ slen = w;
+ bits = 8;
+ colorps = 0;
+ for (i=0; i<ncolors; i++) {
+ if (!Isgray(img,i)) {
+ colortype = F_REDUCED;
+ slen = w*3;
+ bits = 8;
+ colorps = 1;
+ break;
+ }
+ }
+ }
+
+ /* build a temporary dictionary */
+ PSprintf("20 dict begin\n\n");
+
+ /* define string to hold a scanline's worth of data */
+ PSprintf("/pix %d string def\n\n", slen);
+
+ /* position and scaling */
+ PSprintf("gsave currentpoint %d sub translate", h);
+ if (anchor)
+ PSprintf(" 2 0 translate");
+ else
+ PSprintf(" 0 2 translate");
+ PSprintf(" %d %d scale\n", w, h);
+
+ if (colortype == F_BWDITHER) {
+ /* 1-bit dither code uses 'image' */
+ int flipbw = 0;
+
+ /* set if color#0 is 'white' */
+ if ((ncolors == 2 &&
+ MONO(img->reds[0], img->greens[0],img->blues[0]) >
+ MONO(img->reds[1], img->greens[1], img->blues[1])) ||
+ (ncolors == 1 &&
+ MONO(img->reds[0], img->greens[0],img->blues[0]) >
+ MONO(127, 127, 127) )) {
+ flipbw=1;
+ }
+
+ /* dimensions of data */
+ PSprintf("%d %d %d\n", w, h, bits);
+
+ /* mapping matrix */
+ PSprintf("[%d 0 0 %d 0 %d]\n\n", w, -h, h);
+
+ PSprintf("{currentfile pix readhexstring pop}\n");
+ PSprintf("image\n");
+
+ /* write the actual image data */
+ err = PSwrite_bw(imgp, w, h, flipbw);
+ } else {
+ /* all other formats */
+ unsigned char *rleline = (unsigned char *) NULL;
+ int rlen;
+
+ /* if we're using color, make sure 'colorimage' is defined */
+ if (colorps)
+ PScolor_image();
+
+ PScolormap(colorps, ncolors, img->reds, img->greens, img->blues);
+ PSrle_cmapimage(colorps);
+
+ /* dimensions of data */
+ PSprintf("%d %d %d\n", w, h, bits);
+ /* mapping matrix */
+ PSprintf("[%d 0 0 %d 0 %d]\n", w, -h, h);
+ PSprintf("rlecmapimage\n");
+
+ rleline = (unsigned char *) malloc(w * 2);
+ if (!rleline) {
+ fprintf(stderr,"failed to malloc space for rleline\n");
+ return;
+ }
+
+ for (i=0; i<h && err != EOF; i++) {
+ rlen = PSrle_encode(imgp, rleline, w);
+ imgp += w;
+ for (j=0; j<rlen && err != EOF; j++)
+ err=PShex(rleline[j], False);
+ err=PShex('\0', True); /* Flush the hex buffer */
+ }
+ free(rleline);
+ }
+
+ /* stop using temporary dictionary */
+ PSprintf("end\n");
+ PSprintf("grestore\n");
+
+ /* move currentpoint just right of image */
+ PSprintf("%d 0 R\n", w + extra);
+
+ /* forget about the macro's */
+# undef Isgray
+# undef Is_fg
+# undef Is_bg
+}
+
+/*__________________________________________________________________________
+ |
+ | ParseTextToPSString - entry point for postscript output
+ |
+ | Parse all the formatted text elements from start to end
+ | into an ascii text string, and return it.
+ | Very like ParseTextToString() except the text is prettied up
+ | into Postscript to show headers and the like.
+ | space_width and lmargin tell us how many spaces
+ | to indent lines.
+ | Because this routine is only used to print whole documents,
+ | some parameters are not needed at all!
+ | Also it assumes that you are indeed printing the whole document, and
+ | not just a selected portion of it. It therefore can assume that
+ | only for the first page the initialization is needed, and only
+ | the last page has the trailers. You cannot use ParseTextToPSString()
+ | as you can use ParseTextToString() because of this initialization code.
+ |
+*/
+
+String ParseTextToPSString(hw, elist, startp, endp, start_pos, end_pos,
+ space_width, lmargin, fontfamily)
+ HTMLWidget hw;
+ struct ele_rec *elist;
+ struct ele_rec *startp;
+ struct ele_rec *endp;
+ int start_pos, end_pos;
+ int space_width;
+ int lmargin;
+ int fontfamily;
+ {
+
+ /* the fontfamily parameter is new
+ * The font is encoded as:
+ * 0: times (default for now)
+ * 1: helvetica
+ * 2: new century schoolbook
+ * 3: lucida
+ */
+
+ int xpos, ypos, epos;
+ int height;
+ int pagewidth;
+ int line = -1;
+ struct ele_rec *eptr;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ struct ele_rec *last;
+ struct ele_rec *tmpptr;
+
+ if (startp == NULL)
+ return(NULL);
+
+
+ /*
+ * Get the foreground and background colors so we can check later
+ * for black&white documents
+ */
+ {
+ unsigned long fg_pixel, bg_pixel;
+
+
+ XtVaGetValues (hw->html.view,
+#ifdef MOTIF
+ XtNforeground, &fg_pixel,
+#endif
+ XtNbackground, &bg_pixel,
+ NULL);
+#ifndef MOTIF
+ XtVaGetValues ((Widget)hw,
+ XtNforeground, &fg_pixel,
+ NULL);
+#endif
+ fg_color.pixel = fg_pixel;
+ bg_color.pixel = bg_pixel;
+ XQueryColor (XtDisplay (hw->html.view),
+ DefaultColormap (XtDisplay (hw->html.view),
+ DefaultScreen (XtDisplay (hw->html.view))),
+ &fg_color);
+ XQueryColor (XtDisplay (hw->html.view),
+ DefaultColormap (XtDisplay (hw->html.view),
+ DefaultScreen (XtDisplay (hw->html.view))),
+ &bg_color);
+ }
+
+ /* this piece of code is needed if the user selects a portion
+ * of the document with the mouse.
+ * I think it will never be used, but I left it in anyway. F.
+ */
+ if (SwapElements(startp, endp, start_pos, end_pos)) {
+ start = endp;
+ end = startp;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ } else {
+ start = startp;
+ end = endp;
+ }
+
+ /* Calculate the number of Postscript points per pixel of current
+ * screen, and the height of the page in pixels (used in figuring
+ * when we've hit the bottom of the page).
+ */
+ Points_Pixel = 72.0 / GetDpi(hw);
+#ifdef OLD
+ pagewidth = hw->html.doc_width;
+#else /* gustaf fix */
+ pagewidth = hw->html.view_width; /* seems more reasonable */
+#endif /* gustaf fix */
+
+ /* reduce the scaling if the width used for formatting is greater
+ * than 8 * 72 pixels (8 inch)
+ * In theory, this is not what you want for A4 paper (only 8.27 inch
+ * wide), but I guess that the hw->html.doc_width includes some
+ * left and right margins, so it seems to work in practice.
+ */
+ if (pagewidth > PAGE_WIDTH)
+ Points_Pixel = Points_Pixel * (float) PAGE_WIDTH / pagewidth;
+ Pixels_Page = (int) (PAGE_HEIGHT / Points_Pixel);
+
+
+ PSinit();
+ PSheader(hw->html.title, fontfamily);
+ PSnewpage();
+
+ last = start;
+ eptr = start;
+
+ while ((eptr != NULL) && (eptr != end)) {
+ /* Skip the special internal text added for multi-page
+ * documents.
+ */
+ if (eptr->internal == True) {
+ if (eptr->type == E_LINEFEED) {
+ PS_page_offset += eptr->line_height;
+ }
+ eptr = eptr->next;
+ continue;
+ }
+ /* check if this is a newline */
+ if (line != eptr->line_number) {
+ /* calculate max height */
+ height = 0;
+ line = eptr->line_number;
+ tmpptr = eptr;
+ while (tmpptr != NULL && tmpptr->line_number == line) {
+ if (tmpptr->line_height > height)
+ height = tmpptr->line_height;
+ tmpptr = tmpptr->next;
+ }
+ ypos = eptr->y - PS_page_offset ;
+ xpos = eptr->x - lmargin;
+ if (xpos < 0)
+ xpos = 0;
+
+ /* check if line fits completly on page */
+ if (ypos + height > PS_start_y + Pixels_Page) {
+ PS_start_y = ypos;
+ PSshowpage();
+ PSnewpage();
+ }
+ PSmoveto( xpos, ypos);
+ }
+
+ switch(eptr->type) {
+
+ case E_TEXT: {
+ String tptr;
+ int ascent;
+
+ if (eptr == start)
+ tptr = (String)(eptr->edata + start_pos);
+ else
+ tptr = (String)eptr->edata;
+
+ PSfont(hw, eptr->font, fontfamily); /* set font */
+ if (PS_fontascent == 0)
+ ascent = eptr->font->ascent;
+ else
+ ascent = PS_fontascent;
+ PSmove_offset(eptr->y_offset + ascent);
+ PStext(tptr, eptr->underline_number); /* insert text */
+ break;
+ }
+
+ case E_BULLET: {
+ int width;
+ int offset;
+
+ PSfont(hw, eptr->font, fontfamily);
+ width = eptr->font->max_bounds.lbearing +
+ eptr->font->max_bounds.rbearing;
+ /* the next line is a hack to get a good position of the
+ * bullet in most practical cases, otherwise the
+ * bullet may appear just a bit too low (for large fonts)
+ * What is does is to compare the lineheight with
+ * the lineheight of the next element, to correct
+ * for the possibly too large y_offset
+ */
+ if (eptr->next != NULL && (eptr->next->type == E_TEXT
+ || eptr->next->type == E_IMAGE))
+ offset = eptr->line_height -
+ eptr->next->line_height +
+ eptr->y_offset +
+ eptr->next->font->ascent;
+ else
+ offset = eptr->y_offset + eptr->font->ascent;
+
+ PSmove_offset(offset - width/4);
+ PSbullet(eptr->indent_level, eptr->line_height);
+ break;
+ }
+
+ case E_IMAGE: {
+
+ PSmove_offset(eptr->y_offset);
+ PSimage(eptr->pic_data ,(eptr->anchorHRef != NULL));
+ break;
+ }
+
+ case E_LINEFEED: {
+ break;
+ }
+ case E_HRULE: {
+ PSmove_offset(eptr->y_offset);
+ PShrule(hw->html.doc_width);
+ break;
+ }
+ }
+ last = eptr;
+ eptr = eptr->next;
+ }
+
+ PSshowpage();
+ PStrailer();
+
+ return( PS_string);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/HTML.c b/vendor/x11iraf/obm/ObmW/HTML.c
new file mode 100644
index 00000000..546bfbc0
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTML.c
@@ -0,0 +1,6177 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include "HTMLP.h"
+#ifdef MOTIF
+#include <Xm/DrawingA.h>
+#include <Xm/ScrollBar.h>
+#else
+#include "DrawingArea.h"
+#include <X11/Xaw/Scrollbar.h>
+#endif
+#include <X11/cursorfont.h>
+
+
+#define MARGIN_DEFAULT 20
+#define CLICK_TIME 500
+#define SELECT_THRESHOLD 3
+#define MAX_UNDERLINES 3
+#define DEFAULT_INCREMENT 18
+
+#ifndef ABS
+#define ABS(x) (((x) > 0) ? (x) : ((x) * -1))
+#endif
+
+#define W_TEXTFIELD 0
+#define W_CHECKBOX 1
+#define W_RADIOBOX 2
+#define W_PUSHBUTTON 3
+#define W_PASSWORD 4
+#define W_OPTIONMENU 5
+
+
+extern int FormatAll();
+extern int DocumentWidth();
+extern void PlaceLine();
+extern void TextRefresh();
+extern void ImageRefresh();
+extern void LinefeedRefresh();
+extern void RefreshTextRange();
+extern void FreeColors();
+extern void FreeImages();
+extern void HideWidgets();
+extern void MapWidgets();
+extern int SwapElements();
+extern int ElementLessThan();
+extern int IsDelayedHRef();
+extern int IsIsMapForm();
+extern int AnchoredHeight();
+extern char *ParseMarkTag();
+extern char *ParseTextToString();
+extern char *ParseTextToPrettyString();
+extern char *ParseTextToPSString();
+extern struct mark_up *HTMLParse();
+extern struct ele_rec *LocateElement();
+extern struct ele_rec **MakeLineList();
+extern void FreeHRefs();
+extern struct ref_rec *AddHRef();
+extern void FreeDelayedImages();
+extern struct delay_rec *AddDelayedImage();
+extern ImageInfo *NoImageData();
+extern void ImageSubmitForm();
+
+
+static void SelectStart();
+static void ExtendStart();
+static void ExtendAdjust();
+static void ExtendEnd();
+static void TrackMotion();
+static Boolean ConvertSelection();
+static void LoseSelection();
+static void SelectionDone();
+static void Scroll();
+
+
+#ifdef _NO_PROTO
+
+static void _HTMLInput() ;
+#ifndef MOTIF
+static void _HTMLpwdInput() ;
+#endif
+static void Initialize() ;
+static void Realize() ;
+static void Redisplay() ;
+static void Resize() ;
+static Boolean SetValues() ;
+static XtGeometryResult GeometryManager() ;
+static void RecolorInternalHRefs() ;
+static Dimension VbarWidth();
+static Dimension HbarHeight();
+static void ViewRedisplay();
+static void ViewClearAndRefresh();
+static void CallLinkCallbacks();
+
+#else /* _NO_PROTO */
+
+static void _HTMLInput(Widget w, XEvent *event,
+ String *params, Cardinal *num_params);
+#ifndef MOTIF
+static void _HTMLpwdInput(Widget w, XEvent *event,
+ String *params, Cardinal *num_params);
+#endif
+static void Initialize(HTMLWidget request, HTMLWidget new);
+static void Realize(HTMLWidget hw, Mask *valueMask,
+ XSetWindowAttributes *attributes);
+static void Redisplay(HTMLWidget hw, XEvent *event, Region region);
+static void Resize(HTMLWidget hw);
+static Boolean SetValues(HTMLWidget current, HTMLWidget request,
+ HTMLWidget new);
+static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
+ XtWidgetGeometry *reply);
+static void RecolorInternalHRefs(HTMLWidget hw, char *href);
+static Dimension VbarWidth(HTMLWidget hw);
+static Dimension HbarHeight(HTMLWidget hw);
+static void ViewRedisplay(HTMLWidget hw, int x, int y,
+ int width, int height);
+static void ViewClearAndRefresh(HTMLWidget hw);
+static void CallLinkCallbacks(HTMLWidget hw);
+#endif /* _NO_PROTO */
+
+
+/*
+ * Default translations
+ * Selection of text, and activate anchors.
+ * If motif, add manager translations.
+ */
+#ifdef MOTIF
+static char defaultTranslations[] =
+" \
+<Btn1Down>: select-start() ManagerGadgetArm()\n\
+<Btn1Motion>: extend-adjust() ManagerGadgetButtonMotion()\n\
+<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) ManagerGadgetActivate()\n\
+<Btn2Down>: select-start()\n\
+<Btn2Motion>: extend-adjust()\n\
+<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0)\n\
+<Btn3Down>: extend-start()\n\
+<Btn3Motion>: extend-adjust()\n\
+<Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Key>f: scroll(1)\n\
+<Key>b: scroll(-1)\n\
+<Key>Prior: scroll(-1)\n\
+<Key>Next: scroll(1)\n\
+<Key>u: scroll(-0.5)\n\
+<Key>d: scroll(0.5)\n\
+<Key>Up: scroll(-0.5)\n\
+<Key>Down: scroll(0.5)\n\
+<Key>j: scroll(1ch)\n\
+<Key>k: scroll(-1ch)\n\
+<Motion>: track-motion()\n\
+<Leave>: track-motion()\n\
+<FocusOut>: track-motion()\n\
+<Expose>: track-motion()\
+";
+#else
+static char defaultTranslations[] =
+" \
+<Btn1Down>: select-start() \n\
+<Btn1Motion>: extend-adjust() \n\
+<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Btn2Down>: select-start() \n\
+<Btn2Motion>: extend-adjust() \n\
+<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Btn3Down>: extend-start()\n\
+<Btn3Motion>: extend-adjust()\n\
+<Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Key>f: scroll(1)\n\
+<Key>b: scroll(-1)\n\
+<Key>Prior: scroll(-1)\n\
+<Key>Next: scroll(1)\n\
+<Key>u: scroll(-0.5)\n\
+<Key>d: scroll(0.5)\n\
+<Key>Up: scroll(-0.5)\n\
+<Key>Down: scroll(0.5)\n\
+<Key>j: scroll(1ch)\n\
+<Key>k: scroll(-1ch)\n\
+<Motion>: track-motion()\n\
+<Leave>: track-motion()\n\
+<FocusOut>: track-motion()\n\
+<Expose>: track-motion()\
+";
+#endif /* MOTIF */
+
+
+static XtActionsRec actionsList[] =
+{
+ { "select-start", (XtActionProc) SelectStart },
+ { "extend-start", (XtActionProc) ExtendStart },
+ { "extend-adjust", (XtActionProc) ExtendAdjust },
+ { "extend-end", (XtActionProc) ExtendEnd },
+ { "track-motion", (XtActionProc) TrackMotion },
+ { "scroll", (XtActionProc) Scroll },
+ { "HTMLInput", (XtActionProc) _HTMLInput },
+#ifndef MOTIF
+ { "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
+#endif
+
+#ifdef MOTIF
+#ifndef MOTIF1_2
+ { "Arm", (XtActionProc) _XmGadgetArm }, /* Motif 1.0 */
+ { "Activate", (XtActionProc) _XmGadgetActivate }, /* Motif 1.0 */
+ { "Enter", (XtActionProc) _XmManagerEnter }, /* Motif 1.0 */
+ { "FocusIn", (XtActionProc) _XmManagerFocusIn }, /* Motif 1.0 */
+ { "Help", (XtActionProc) _XmManagerHelp }, /* Motif 1.0 */
+#endif /* not MOTIF1_2 */
+#endif /* MOTIF */
+};
+
+/*
+ * For some reason, in Motif1.2/X11R5 the actionsList above gets corrupted
+ * When the parent HTML widget is created. This means we can't use
+ * it later with XtAppAddActions to add to the viewing area.
+ * So, we make a spare copy here to use with XtAppAddActions.
+ */
+static XtActionsRec SpareActionsList[] =
+{
+ { "select-start", (XtActionProc) SelectStart },
+ { "extend-start", (XtActionProc) ExtendStart },
+ { "extend-adjust", (XtActionProc) ExtendAdjust },
+ { "extend-end", (XtActionProc) ExtendEnd },
+ { "track-motion", (XtActionProc) TrackMotion },
+ { "scroll", (XtActionProc) Scroll },
+ { "HTMLInput", (XtActionProc) _HTMLInput },
+#ifndef MOTIF
+ { "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
+#endif
+};
+
+
+
+/*
+ * Resource definitions for HTML widget
+ */
+
+static XtResource resources[] =
+{
+ /* Without Motif we need to override the borderWidth to 0 (from 1). */
+#ifndef MOTIF
+ { XtNborderWidth,
+ XtCBorderWidth, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, core.border_width),
+ XtRImmediate, (XtPointer) 0
+ },
+#endif
+
+ { WbNmarginWidth,
+ WbCMarginWidth, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, html.margin_width),
+ XtRImmediate, (caddr_t) MARGIN_DEFAULT
+ },
+
+ { WbNmarginHeight,
+ WbCMarginHeight, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, html.margin_height),
+ XtRImmediate, (caddr_t) MARGIN_DEFAULT
+ },
+
+ { WbNanchorCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.anchor_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNlinkCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.link_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNsubmitFormCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.form_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNtext,
+ WbCText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.raw_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNheaderText,
+ WbCHeaderText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.header_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNfooterText,
+ WbCFooterText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.footer_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNtitleText,
+ WbCTitleText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.title),
+ XtRString, (char *) NULL
+ },
+
+/*
+ * Without motif we need our own foreground resource instead of
+ * using the manager's
+ */
+#ifndef MOTIF
+ { XtNforeground,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.foreground),
+ XtRString, "Black"
+ },
+#endif
+
+ { WbNanchorUnderlines,
+ WbCAnchorUnderlines, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.num_anchor_underlines),
+ XtRString, "0"
+ },
+
+ { WbNvisitedAnchorUnderlines,
+ WbCVisitedAnchorUnderlines, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.num_visitedAnchor_underlines),
+ XtRString, "0"
+ },
+
+ { WbNdashedAnchorUnderlines,
+ WbCDashedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.dashed_anchor_lines),
+ XtRString, "False"
+ },
+
+ { WbNdashedVisitedAnchorUnderlines,
+ WbCDashedVisitedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.dashed_visitedAnchor_lines),
+ XtRString, "False"
+ },
+
+ { WbNanchorColor,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.anchor_fg),
+ XtRString, "blue2"
+ },
+
+ { WbNvisitedAnchorColor,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.visitedAnchor_fg),
+ XtRString, "purple4"
+ },
+
+ { WbNactiveAnchorFG,
+ XtCBackground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.activeAnchor_fg),
+ XtRString, "Red"
+ },
+
+ { WbNactiveAnchorBG,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.activeAnchor_bg),
+ XtRString, "White"
+ },
+
+ { WbNpercentVerticalSpace,
+ WbCPercentVerticalSpace, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.percent_vert_space),
+ XtRString, "90"
+ },
+
+ { WbNimageBorders,
+ WbCImageBorders, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.border_images),
+ XtRString, "False"
+ },
+
+ { WbNdelayImageLoads,
+ WbCDelayImageLoads, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.delay_images),
+ XtRString, "False"
+ },
+
+ { WbNfancySelections,
+ WbCFancySelections, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.fancy_selections),
+ XtRString, "False"
+ },
+
+ { WbNisIndex,
+ WbCIsIndex, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.is_index),
+ XtRString, "False"
+ },
+
+ { WbNview,
+ WbCView, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.view),
+ XtRImmediate, NULL
+ },
+
+ { WbNverticalScrollBar,
+ WbCVerticalScrollBar, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.vbar),
+ XtRImmediate, NULL
+ },
+
+ { WbNhorizontalScrollBar,
+ WbCHorizontalScrollBar, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.hbar),
+ XtRImmediate, NULL
+ },
+
+ { WbNverticalScrollOnRight,
+ WbCVerticalScrollOnRight, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.vbar_right),
+ XtRString, "True"
+ },
+
+ { WbNhorizontalScrollOnTop,
+ WbCHorizontalScrollOnTop, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.hbar_top),
+ XtRString, "False"
+ },
+
+ { XtNfont,
+ XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.font),
+ XtRString, "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNitalicFont,
+ WbCItalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.italic_font),
+ XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNboldFont,
+ WbCBoldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.bold_font),
+ XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixedFont,
+ WbCFixedFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixed_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixedboldFont,
+ WbCFixedboldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixedbold_font),
+ XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixeditalicFont,
+ WbCFixeditalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixeditalic_font),
+ XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader1Font,
+ WbCHeader1Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header1_font),
+ XtRString, "-adobe-times-bold-r-normal-*-24-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader2Font,
+ WbCHeader2Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header2_font),
+ XtRString, "-adobe-times-bold-r-normal-*-18-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader3Font,
+ WbCHeader3Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header3_font),
+ XtRString, "-adobe-times-bold-r-normal-*-17-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader4Font,
+ WbCHeader4Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header4_font),
+ XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader5Font,
+ WbCHeader5Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header5_font),
+ XtRString, "-adobe-times-bold-r-normal-*-12-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader6Font,
+ WbCHeader6Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header6_font),
+ XtRString, "-adobe-times-bold-r-normal-*-10-*-*-*-*-*-*-*"
+ },
+
+ { WbNaddressFont,
+ WbCAddressFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.address_font),
+ XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainFont,
+ WbCPlainFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plain_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainboldFont,
+ WbCPlainboldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plainbold_font),
+ XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainitalicFont,
+ WbCPlainitalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plainitalic_font),
+ XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNlistingFont,
+ WbCListingFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.listing_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*"
+ },
+
+ { WbNpreviouslyVisitedTestFunction,
+ WbCPreviouslyVisitedTestFunction, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.previously_visited_test),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNpreviouslyVisitedTestData,
+ WbCPreviouslyVisitedTestData, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.vt_client_data),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNresolveImageFunction,
+ WbCResolveImageFunction, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.resolveImage),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNresolveDelayedImage,
+ WbCResolveDelayedImage, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.resolveDelayedImage),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ {
+ WbNpointerMotionCallback,
+ WbCPointerMotionCallback, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.pointer_motion_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNpointerMotionData,
+ WbCPointerMotionData, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.pm_client_data),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+};
+
+
+
+HTMLClassRec htmlClassRec = {
+ { /* core class fields */
+#ifdef MOTIF
+ (WidgetClass) &xmManagerClassRec, /* superclass */
+#else
+ (WidgetClass) &constraintClassRec, /* superclass */
+#endif /* MOTIF */
+ "HTML", /* class_name */
+ sizeof(HTMLRec), /* widget_size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ (XtInitProc) Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ (XtRealizeProc) Realize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ FALSE, /* compress_exposure */
+ TRUE, /* compress_enterlv */
+ FALSE, /* visible_interest */
+ NULL, /* destroy */
+ (XtWidgetProc) Resize, /* resize */
+ (XtExposeProc) Redisplay, /* expose */
+ (XtSetValuesFunc) SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+
+ { /* composite_class fields */
+ (XtGeometryHandler) GeometryManager, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL, /* extension */
+ },
+
+ { /* constraint_class fields */
+ NULL, /* resource list */
+ 0, /* num resources */
+ 0, /* constraint size */
+ NULL, /* init proc */
+ NULL, /* destroy proc */
+ NULL, /* set values proc */
+ NULL, /* extension */
+ },
+
+#ifdef MOTIF
+ { /* manager_class fields */
+ XtInheritTranslations, /* translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+ },
+#endif /* MOTIF */
+
+ { /* html_class fields */
+ 0 /* none */
+ }
+};
+
+WidgetClass htmlWidgetClass = (WidgetClass)&htmlClassRec;
+
+/*static Cursor in_anchor_cursor = (Cursor)NULL;*/ /* MF021 */
+Cursor in_anchor_cursor = (Cursor)NULL;
+
+
+/*
+ * Process an expose event in the View (or drawing area). This
+ * Can be a regular expose event, or perhaps a GraphicsExpose Event.
+ */
+static void
+DrawExpose(w, data, event)
+ Widget w;
+ caddr_t data;
+ XEvent *event;
+{
+ XExposeEvent *ExEvent = (XExposeEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ int x, y;
+ int width, height;
+
+ if ((event->xany.type != Expose)&&(event->xany.type != GraphicsExpose))
+ {
+ return;
+ }
+
+ /*
+ * Make sure we have a valid GC to draw with.
+ */
+ if (hw->html.drawGC == NULL)
+ {
+ unsigned long valuemask;
+ XGCValues values;
+
+ values.function = GXcopy;
+ values.plane_mask = AllPlanes;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ values.foreground = hw->manager.foreground;
+#else
+ values.foreground = hw->html.foreground;
+#endif /* MOTIF */
+ values.background = hw->core.background_pixel;
+
+ valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
+
+ hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
+ valuemask, &values);
+ }
+
+ x = ExEvent->x;
+ y = ExEvent->y;
+ width = (int)ExEvent->width;
+ height = (int)ExEvent->height;
+
+#ifdef DEBUG
+DebugHook(x, y, width, height);
+#endif
+
+ ViewRedisplay(hw, x, y, width, height);
+}
+
+
+void
+ScrollWidgets(hw)
+ HTMLWidget hw;
+{
+ WidgetInfo *wptr;
+ int xval, yval;
+
+ xval = hw->html.scroll_x;
+ yval = hw->html.scroll_y;
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->w != NULL)
+ {
+ Widget w;
+ int x, y;
+
+ w = wptr->w;
+ x = wptr->x;
+ y = wptr->y;
+ XtMoveWidget(w, (x - xval), (y - yval));
+ }
+ wptr = wptr->next;
+ }
+}
+
+
+#ifndef MOTIF
+/*
+ * Set the Athena Scrollbar's thumb position properly.
+ */
+static void
+setScrollBar(sb, topPosition, totalLength, currentLength)
+ Widget sb;
+ int topPosition; /* MF026 */
+ int totalLength, currentLength; /* MF026 */
+{
+ float top = (float)topPosition /(float)(totalLength);
+ float shown = (float)currentLength/(float)(totalLength);
+
+ XawScrollbarSetThumb(sb, top, shown);
+}
+#endif
+
+
+/*
+ * Either the vertical or hortizontal scrollbar has been moved
+ */
+void
+ScrollToPos(w, hw, value)
+ Widget w;
+ HTMLWidget hw;
+ int value;
+{
+ /*
+ * Special code incase the scrollbar is "moved" before we have a window
+ * (if we have a GC we have a window)
+ */
+ if (hw->html.drawGC == NULL)
+ {
+ if (w == hw->html.vbar)
+ {
+ hw->html.scroll_y = value;
+ }
+ else if (w == hw->html.hbar)
+ {
+ hw->html.scroll_x = value;
+ }
+ return;
+ }
+
+ /*
+ * get our widgets out of the way (No Expose events)
+ HideWidgets(hw);
+ */
+
+ /*
+ * If we've moved the vertical scrollbar
+ */
+ if (w == hw->html.vbar)
+ {
+ /*
+ * We've scrolled down. Copy up the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ if (value > hw->html.scroll_y)
+ {
+ int dy;
+
+ dy = value - hw->html.scroll_y;
+ if (dy > hw->html.view_height)
+ {
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, dy,
+ hw->html.view_width,
+ hw->html.view_height - dy,
+ 0, 0);
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, (int)hw->html.view_height - dy,
+ hw->html.view_width, dy, False);
+ ViewRedisplay(hw,
+ 0, (int)hw->html.view_height - dy,
+ hw->html.view_width, dy);
+ }
+ }
+ /*
+ * We've scrolled up. Copy down the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ else if (value < hw->html.scroll_y)
+ {
+ int dy;
+
+ dy = hw->html.scroll_y - value;
+ if (dy > hw->html.view_height)
+ {
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, 0,
+ hw->html.view_width,
+ hw->html.view_height - dy,
+ 0, dy);
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width, dy, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width, dy);
+ }
+ }
+ }
+ /*
+ * Else we've moved the horizontal scrollbar
+ */
+ else if (w == hw->html.hbar)
+ {
+ /*
+ * We've scrolled right. Copy left the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ if (value > hw->html.scroll_x)
+ {
+ int dx;
+
+ dx = value - hw->html.scroll_x;
+ if (dx > hw->html.view_width)
+ {
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, dx, 0,
+ hw->html.view_width - dx,
+ hw->html.view_height,
+ 0, 0);
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ (int)hw->html.view_width - dx, 0,
+ dx, hw->html.view_height, False);
+ ViewRedisplay(hw,
+ (int)hw->html.view_width - dx, 0,
+ dx, hw->html.view_height);
+ }
+ }
+ /*
+ * We've scrolled left. Copy right the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ else if (value < hw->html.scroll_x)
+ {
+ int dx;
+
+ dx = hw->html.scroll_x - value;
+ if (dx > hw->html.view_width)
+ {
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, 0,
+ hw->html.view_width - dx,
+ hw->html.view_height,
+ dx, 0);
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ dx, hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ dx, hw->html.view_height);
+ }
+ }
+ }
+
+ /*
+ * Move the now hidden widgets
+ * Flush any Copyed or Cleared text first.
+ XFlush(XtDisplay(hw));
+ */
+ ScrollWidgets(hw);
+
+ /*
+ * Remap the widgets to their new location
+ MapWidgets(hw);
+ */
+}
+
+
+/*
+ * Either the vertical or hortizontal scrollbar has been moved
+ */
+void
+ScrollMove(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+#ifdef MOTIF
+ XmScrollBarCallbackStruct *sc = (XmScrollBarCallbackStruct *)call_data;
+
+ ScrollToPos(w, (HTMLWidget)client_data, sc->value);
+#else
+ float scrollDir = (int)call_data < 0 ? -0.3 : 0.3;
+ HTMLWidget hw = (HTMLWidget)client_data;
+ int value;
+ int totalLength, currentLength; /* MF026 */
+
+ if (w == hw->html.vbar)
+ {
+ totalLength = hw->html.doc_height;
+ currentLength = hw->html.view_height;
+ value = hw->html.scroll_y + scrollDir * currentLength;
+ }
+ else
+ {
+ totalLength = hw->html.doc_width;
+ currentLength = hw->html.view_width;
+ value = hw->html.scroll_x + scrollDir * currentLength;
+ }
+
+ if (value > (int)totalLength) value = totalLength;
+ if (value < 0) value = 0;
+
+ setScrollBar(w, value, totalLength, currentLength);
+ ScrollToPos(w, hw, value);
+#endif
+}
+
+
+#ifndef MOTIF
+void
+JumpMove(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ HTMLWidget hw = (HTMLWidget)client_data;
+ int value = (int)(*(float *)call_data *
+ (w == hw->html.vbar ?
+ hw->html.doc_height :
+ hw->html.doc_width));
+ ScrollToPos(w, hw, value);
+}
+#endif
+
+
+/*
+ * Create the horizontal and vertical scroll bars.
+ * Size them later.
+ */
+static void
+#ifdef _NO_PROTO
+CreateScrollbars (hw)
+ HTMLWidget hw ;
+#else
+CreateScrollbars(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[20];
+ Cardinal argcnt;
+ XtTranslations trans;
+
+ /*
+ * If the user hasn't provided a viewing area Widget (which they
+ * should not most of the time) make a drawing are to use.
+ */
+ if (hw->html.view == NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNwidth, 10); argcnt++;
+ XtSetArg(arg[argcnt], XxNheight, 10); argcnt++;
+ hw->html.view = XtCreateWidget("View",
+#ifdef MOTIF
+ xmDrawingAreaWidgetClass,
+#else
+ drawingAreaWidgetClass,
+#endif
+ (Widget)hw, arg, argcnt);
+ XtManageChild(hw->html.view);
+ }
+
+ /*
+ * For the view widget catch all Expose and GraphicsExpose
+ * events. Replace its translations with ours, and make
+ * sure all the actions are in order.
+ */
+ XtAddEventHandler((Widget)hw->html.view, ExposureMask, True,
+ (XtEventHandler)DrawExpose, (caddr_t)hw);
+ /*
+ * As described previoisly, for some reason with Motif1.2/X11R5
+ * the list actionsList is corrupted when we get here,
+ * so we have to use the special copy SpareActionsList
+ */
+ XtAppAddActions(XtWidgetToApplicationContext(hw->html.view),
+ SpareActionsList, XtNumber(SpareActionsList));
+ trans = XtParseTranslationTable(defaultTranslations);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNtranslations, trans); argcnt++;
+ XtSetValues(hw->html.view, arg, argcnt);
+
+ /*
+ * If the user hasn't provided a vertical scrollbar (which they
+ * should not most of the time) make one.
+ */
+ if (hw->html.vbar == NULL)
+ {
+ argcnt = 0;
+#ifdef MOTIF
+ XtSetArg(arg[argcnt], XmNorientation, XmVERTICAL); argcnt++;
+ hw->html.vbar = XtCreateWidget("Vbar", xmScrollBarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#else
+ XtSetArg(arg[argcnt],XtNorientation,XtorientVertical); argcnt++;
+ hw->html.vbar = XtCreateWidget("Vbar", scrollbarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#endif
+ XtManageChild(hw->html.vbar);
+ }
+
+ /*
+ * Add callbacks to catch scrollbar changes
+ */
+#ifdef MOTIF
+ XtAddCallback(hw->html.vbar, XmNvalueChangedCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+ XtAddCallback(hw->html.vbar, XmNdragCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#else
+ XtAddCallback(hw->html.vbar, XtNjumpProc,
+ (XtCallbackProc)JumpMove, (caddr_t)hw);
+ XtAddCallback(hw->html.vbar, XtNscrollProc,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#endif
+
+ /*
+ * If the user hasn't provided a horizontal scrollbar (which they
+ * should not most of the time) make one.
+ */
+ if (hw->html.hbar == NULL)
+ {
+ argcnt = 0;
+#ifdef MOTIF
+ XtSetArg(arg[argcnt], XmNorientation, XmHORIZONTAL); argcnt++;
+ hw->html.hbar = XtCreateWidget("Hbar", xmScrollBarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#else
+ XtSetArg(arg[argcnt], XtNorientation, XtorientHorizontal);
+ argcnt++;
+ hw->html.hbar = XtCreateWidget("Hbar", scrollbarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#endif
+ XtManageChild(hw->html.hbar);
+ }
+
+ /*
+ * Add callbacks to catch scrollbar changes
+ */
+#ifdef MOTIF
+ XtAddCallback(hw->html.hbar, XmNvalueChangedCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+ XtAddCallback(hw->html.hbar, XmNdragCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#else
+ XtAddCallback(hw->html.hbar, XtNjumpProc,
+ (XtCallbackProc)JumpMove, (caddr_t)hw);
+ XtAddCallback(hw->html.hbar, XtNscrollProc,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#endif
+}
+
+
+/*
+ * Return the width of the vertical scrollbar
+ */
+static Dimension
+#ifdef _NO_PROTO
+VbarWidth (hw)
+ HTMLWidget hw ;
+#else
+VbarWidth(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[4];
+ Cardinal argcnt;
+ Dimension width;
+
+ width = 0;
+ if (hw->html.vbar != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNwidth, &width); argcnt++;
+ XtGetValues(hw->html.vbar, arg, argcnt);
+ }
+
+ return(width);
+}
+
+
+/*
+ * Return the height of the horizontal scrollbar
+ */
+static Dimension
+#ifdef _NO_PROTO
+HbarHeight (hw)
+ HTMLWidget hw ;
+#else
+HbarHeight(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[4];
+ Cardinal argcnt;
+ Dimension height;
+
+ height = 0;
+ if (hw->html.hbar != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNheight, &height); argcnt++;
+ XtGetValues(hw->html.hbar, arg, argcnt);
+ }
+
+ return(height);
+}
+
+
+/*
+ * Resize and set the min and max values of the scrollbars. Position viewing
+ * area based on scrollbar locations.
+ */
+static void
+#ifdef _NO_PROTO
+ConfigScrollBars (hw)
+ HTMLWidget hw ;
+#else
+ConfigScrollBars(
+ HTMLWidget hw)
+#endif
+{
+#ifdef MOTIF
+ Arg arg[20];
+ Cardinal argcnt;
+#endif
+ int vx, vy;
+
+ /*
+ * Move and size the viewing area
+ */
+#ifdef MOTIF
+ vx = hw->manager.shadow_thickness;
+ vy = hw->manager.shadow_thickness;
+#else
+ vx = vy = 0;
+#endif
+ if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
+ {
+ vx += VbarWidth(hw);
+ }
+ if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
+ {
+ vy += HbarHeight(hw);
+ }
+ XtMoveWidget(hw->html.view, vx, vy);
+ XtResizeWidget(hw->html.view, hw->html.view_width, hw->html.view_height,
+ hw->html.view->core.border_width);
+
+ /*
+ * Set up vertical scrollbar
+ */
+ if (hw->html.use_vbar == True)
+ {
+ int maxv;
+ int ss;
+
+ /*
+ * Size the vertical scrollbar to the height of
+ * the viewing area
+ */
+ XtResizeWidget(hw->html.vbar, hw->html.vbar->core.width,
+ hw->html.view_height + (2 *
+#ifdef MOTIF
+ hw->manager.shadow_thickness
+#else
+ 0
+#endif
+ ),
+ hw->html.vbar->core.border_width);
+
+ /*
+ * Set the slider size to be the percentage of the
+ * viewing area that the viewing area is of the
+ * document area. Or set it to 1 if that isn't possible.
+ */
+ if (hw->html.doc_height == 0)
+ {
+ ss = 1;
+ }
+ else
+ {
+#ifdef DEBUG
+fprintf (stderr, "view_height %d, doc_height %d\n",
+hw->html.view_height, hw->html.doc_height);
+#endif
+#ifdef NOT_RIGHT
+ /* Eric -- your previous equation wasn't doing it.
+ This isn't either... */
+ ss =
+ (int)((float)hw->html.view_height *
+ ((float)hw->html.view_height /
+ (float)(hw->html.doc_height - (int)hw->html.view_height)));
+ if (ss > hw->html.view_height)
+ {
+ ss = hw->html.view_height;
+ }
+#endif
+ /* Added by marca: this produces results *very* close (~1 pixel)
+ to the original scrolled window behavior. */
+ ss = hw->html.view_height;
+ }
+ if (ss < 1)
+ {
+ ss = 1;
+ }
+#ifdef DEBUG
+fprintf (stderr, "computed ss to be %d\n", ss);
+#endif
+
+ /*
+ * If resizing of the document has made scroll_y
+ * greater than the max, we want to hold it at the max.
+ */
+ maxv = hw->html.doc_height - (int)hw->html.view_height;
+ if (maxv < 0)
+ {
+ maxv = 0;
+ }
+ if (hw->html.scroll_y > maxv)
+ {
+ hw->html.scroll_y = maxv;
+ }
+
+ /*
+ * Prevent the Motif max value and slider size
+ * from going to zero, which is illegal
+ */
+ maxv = maxv + ss;
+ if (maxv < 1)
+ {
+ maxv = 1;
+ }
+
+ /*
+ * Motif will not allow the actual value to be equal to
+ * its max value. Adjust accordingly.
+ * Since we might decrease scroll_y, cap it at zero.
+ */
+ if (hw->html.scroll_y >= maxv)
+ {
+ hw->html.scroll_y = maxv - 1;
+ }
+ if (hw->html.scroll_y < 0)
+ {
+ hw->html.scroll_y = 0;
+ }
+
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
+ XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
+ XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_y); argcnt++;
+ XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
+ XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
+ XtSetArg(arg[argcnt], XmNpageIncrement,
+ hw->html.view_height > DEFAULT_INCREMENT ?
+ hw->html.view_height - DEFAULT_INCREMENT : 1); argcnt++;
+ XtSetValues(hw->html.vbar, arg, argcnt);
+#else
+ setScrollBar(hw->html.vbar,
+ hw->html.scroll_y,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif /* MOTIF */
+
+#ifdef DEBUG
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "real slider size %d\n", ss);
+#endif
+ }
+
+ /*
+ * Set up horizontal scrollbar
+ */
+ if (hw->html.use_hbar == True)
+ {
+ int maxv;
+ int ss;
+
+ /*
+ * Size the horizontal scrollbar to the width of
+ * the viewing area
+ */
+ XtResizeWidget(hw->html.hbar,
+ hw->html.view_width + (2 *
+#ifdef MOTIF
+ hw->manager.shadow_thickness
+#else
+ 0
+#endif /* MOTIF */
+ ),
+ hw->html.hbar->core.height,
+ hw->html.hbar->core.border_width);
+
+ /*
+ * Set the slider size to be the percentage of the
+ * viewing area that the viewing area is of the
+ * document area. Or set it to 1 if that isn't possible.
+ */
+ if (hw->html.doc_width == 0)
+ {
+ ss = 1;
+ }
+ else
+ {
+#ifdef NOT_RIGHT
+ ss = hw->html.view_width *
+ hw->html.view_width / hw->html.doc_width;
+ if (ss > hw->html.view_width)
+ {
+ ss = hw->html.view_width;
+ }
+#endif
+ /* Added by marca: this produces results *very* close (~1 pixel)
+ to the original scrolled window behavior. */
+ ss = hw->html.view_width;
+ }
+ if (ss < 1)
+ {
+ ss = 1;
+ }
+
+ /*
+ * If resizing of the document has made scroll_x
+ * greater than the max, we want to hold it at the max.
+ */
+ maxv = hw->html.doc_width - (int)hw->html.view_width;
+ if (maxv < 0)
+ {
+ maxv = 0;
+ }
+ if (hw->html.scroll_x > maxv)
+ {
+ hw->html.scroll_x = maxv;
+ }
+
+ /*
+ * Prevent the Motif max value and slider size
+ * from going to zero, which is illegal
+ */
+ maxv = maxv + ss;
+ if (maxv < 1)
+ {
+ maxv = 1;
+ }
+
+ /*
+ * Motif will not allow the actual value to be equal to
+ * its max value. Adjust accordingly.
+ * Since we might decrease scroll_x, cap it at zero.
+ */
+ if (hw->html.scroll_x >= maxv)
+ {
+ hw->html.scroll_x = maxv - 1;
+ }
+ if (hw->html.scroll_x < 0)
+ {
+ hw->html.scroll_x = 0;
+ }
+
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
+ XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
+ XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_x); argcnt++;
+ XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
+ XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
+ XtSetArg(arg[argcnt], XmNpageIncrement,
+ hw->html.view_width > DEFAULT_INCREMENT ?
+ hw->html.view_width - DEFAULT_INCREMENT : 1); argcnt++;
+ XtSetValues(hw->html.hbar, arg, argcnt);
+#else
+ setScrollBar(hw->html.hbar,
+ hw->html.scroll_x,
+ hw->html.doc_width,
+ (int)hw->html.view_width);
+#endif /* MOTIF */
+ }
+
+#ifdef DEBUG
+ {
+ int ss;
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "real slider size %d\n", ss);
+ }
+#endif
+}
+
+
+/*
+ * Reformat the window and scrollbars.
+ * May be called because of a changed document, or because of a changed
+ * window size.
+ */
+static void
+#ifdef _NO_PROTO
+ReformatWindow (hw)
+ HTMLWidget hw ;
+#else
+ReformatWindow(
+ HTMLWidget hw)
+#endif
+{
+ int temp;
+ int new_width;
+ Dimension swidth, sheight;
+ Dimension st;
+
+ /*
+ * Find the current scrollbar sizes, and shadow thickness and format
+ * the document to the current window width
+ * (assume a vertical scrollbar)
+ */
+ swidth = VbarWidth(hw);
+ sheight = HbarHeight(hw);
+#ifdef MOTIF
+ st = hw->manager.shadow_thickness;
+#else
+ st = 0;
+#endif /* MOTIF */
+ if (hw->core.width <= swidth)
+ {
+ hw->core.width = swidth + 10;
+ }
+ new_width = hw->core.width - swidth - (2 * st);
+ temp = FormatAll(hw, &new_width);
+
+ /*
+ * If we need the vertical scrollbar, place and manage it,
+ * and store the current viewing area width.
+ */
+ if (temp > hw->core.height - sheight)
+ {
+ hw->html.use_vbar = True;
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.vbar,
+ (hw->core.width - swidth), 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.vbar, 0, 0);
+ }
+ XtManageChild(hw->html.vbar);
+ hw->html.view_width = hw->core.width - swidth - (2 * st);
+ }
+ /*
+ * Else we were wrong to assume a vertical scrollbar.
+ * Remove it, and reformat the document to the wider width.
+ * Save the as the current viewing are width.
+ */
+ else
+ {
+ hw->html.use_vbar = False;
+ XtUnmanageChild(hw->html.vbar);
+ hw->html.scroll_y = 0;
+ new_width = hw->core.width - (2 * st);
+ temp = FormatAll(hw, &new_width);
+ hw->html.view_width = hw->core.width - (2 * st);
+ /* fake out later horizontal scrollbars */
+ swidth = 0;
+ }
+
+ /*
+ * Calculate the actual max width and height of the complete
+ * formatted document.
+ * The max width may exceed the preformatted width due to special
+ * factors in the formatting of the widget.
+ * Use the max of the 2 here, but leave max_pre_width unchanged
+ * for future formatting calls.
+ */
+ /*
+ * new_width includes the margins, and hw->html.max_pre_width
+ * does not, fix that here.
+ */
+ new_width = new_width - (2 * hw->html.margin_width);
+ if (hw->html.max_pre_width > new_width)
+ {
+ new_width = hw->html.max_pre_width;
+ }
+ /*
+ * If the maximum width derives from a formatted, as opposed to
+ * unformatted piece of text, allow a 20% of margin width slop
+ * over into the margin to cover up a minor glick with terminaing
+ * punctuation after anchors at the end of the line.
+ */
+ else
+ {
+ new_width = new_width - (20 * hw->html.margin_width / 100);
+ }
+
+ hw->html.doc_height = temp;
+ hw->html.doc_width = new_width + (2 * hw->html.margin_width);
+ if (hw->html.view_width > hw->html.doc_width)
+ {
+ hw->html.doc_width = hw->html.view_width;
+ }
+
+ /*
+ * If we need a horizontal scrollbar
+ * Place it and manage it. Save the height of the current
+ * viewing area.
+ */
+ if (hw->html.doc_width > hw->html.view_width)
+ {
+ hw->html.use_hbar = True;
+ if (hw->html.hbar_top == True)
+ {
+ if (hw->html.use_vbar == True)
+ {
+ XtMoveWidget(hw->html.vbar,
+ hw->html.vbar->core.x, sheight);
+ }
+
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0, 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth, 0);
+ }
+ }
+ else
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0,
+ (hw->core.height - sheight));
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth,
+ (hw->core.height - sheight));
+ }
+ }
+ XtManageChild(hw->html.hbar);
+ hw->html.view_height = hw->core.height - sheight - (2 * st);
+ }
+ /*
+ * Else we don't need a horizontal scrollbar.
+ * Remove it and save the current viewing area height.
+ */
+ else
+ {
+ hw->html.use_hbar = False;
+ XtUnmanageChild(hw->html.hbar);
+ hw->html.scroll_x = 0;
+ hw->html.view_height = hw->core.height - (2 * st);
+ }
+
+ /*
+ * Configure the scrollbar min, max, and slider sizes
+ */
+#ifdef DEBUG
+fprintf (stderr, "calling in ReformatWindow\n");
+#endif
+ ConfigScrollBars(hw);
+}
+
+
+/*
+ * We're a happy widget. We let any child move or resize themselves
+ * however they want, we don't care.
+ */
+static XtGeometryResult
+#ifdef _NO_PROTO
+GeometryManager (w, request, reply)
+ Widget w;
+ XtWidgetGeometry * request;
+ XtWidgetGeometry * reply;
+#else
+GeometryManager (
+ Widget w,
+ XtWidgetGeometry * request,
+ XtWidgetGeometry * reply)
+#endif
+{
+ reply->x = request->x;
+ reply->y = request->y;
+ reply->width = request->width;
+ reply->height = request->height;
+ reply->border_width = request->border_width;
+ reply->request_mode = request->request_mode;
+ return (XtGeometryYes);
+}
+
+
+/*
+ * Initialize is called when the widget is first initialized.
+ * Check to see that all the starting resources are valid.
+ */
+static void
+#ifdef _NO_PROTO
+Initialize (request, new)
+ HTMLWidget request ;
+ HTMLWidget new ;
+#else
+Initialize(
+ HTMLWidget request,
+ HTMLWidget new)
+#endif
+{
+ /*
+ * Make sure height and width are not zero.
+ */
+ if (new->core.width == 0)
+ {
+ new->core.width = new->html.margin_width << 1 ;
+ }
+ if (new->core.width == 0)
+ {
+ new->core.width = 10 ;
+ }
+ if (new->core.height == 0)
+ {
+ new->core.height = new->html.margin_height << 1 ;
+ }
+ if (new->core.height == 0)
+ {
+ new->core.height = 10 ;
+ }
+
+ /*
+ * Make sure the underline numbers are within bounds.
+ */
+ if (new->html.num_anchor_underlines < 0)
+ {
+ new->html.num_anchor_underlines = 0;
+ }
+ if (new->html.num_anchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_anchor_underlines = MAX_UNDERLINES;
+ }
+ if (new->html.num_visitedAnchor_underlines < 0)
+ {
+ new->html.num_visitedAnchor_underlines = 0;
+ }
+ if (new->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
+ }
+
+ /*
+ * Parse the raw text with the HTML parser. And set the formatted
+ * element list to NULL.
+ */
+ new->html.html_objects = HTMLParse(NULL, request->html.raw_text);
+ CallLinkCallbacks(new);
+ new->html.html_header_objects =
+ HTMLParse(NULL, request->html.header_text);
+ new->html.html_footer_objects =
+ HTMLParse(NULL, request->html.footer_text);
+ new->html.formatted_elements = NULL;
+ new->html.my_visited_hrefs = NULL;
+ new->html.my_delayed_images = NULL;
+ new->html.widget_list = NULL;
+ new->html.form_list = NULL;
+
+ /*
+ * Blank document
+ */
+ new->html.line_array = NULL;
+ new->html.line_count = 0;
+
+ /*
+ * Find the max width of a preformatted
+ * line in this document.
+ */
+ new->html.max_pre_width = DocumentWidth(new, new->html.html_objects);
+
+ /*
+ * Create the scrollbars.
+ * Find their dimensions and then decide which scrollbars you
+ * will need, and what the dimensions of the viewing area are.
+ * Start assuming a vertical scrollbar and a horizontal one.
+ * The remove vertical if short enough, and remove horizontal
+ * if narrow enough.
+ */
+ CreateScrollbars(new);
+ new->html.scroll_x = 0;
+ new->html.scroll_y = 0;
+ ReformatWindow(new);
+
+ /*
+ * Initialize private widget resources
+ */
+ new->html.drawGC = NULL;
+ new->html.select_start = NULL;
+ new->html.select_end = NULL;
+ new->html.sel_start_pos = 0;
+ new->html.sel_end_pos = 0;
+ new->html.new_start = NULL;
+ new->html.new_end = NULL;
+ new->html.new_start_pos = 0;
+ new->html.new_end_pos = 0;
+ new->html.active_anchor = NULL;
+ new->html.press_x = 0;
+ new->html.press_y = 0;
+
+ new->html.cached_tracked_ele = NULL;
+
+ /* Initialize cursor used when pointer is inside anchor.
+ if (in_anchor_cursor == (Cursor)NULL) */
+ in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
+
+ return;
+}
+
+/*
+ * Realize is called when the widget is realized to create its window.
+ * We call the Realize method of our superclass and then create the drawGC
+ * to be used by the HTML widget. (This was added at NOAO, the NCSA
+ * version does not use a custom Realize method, and the drawGC is not
+ * created until the first Expose event occurs. This causes the widget to
+ * crash if a drawing routine is called before the application becomes idle
+ * and processes the queued input from the display server.)
+ */
+static void
+#ifdef _NO_PROTO
+Realize (hw, valueMask, attributes)
+ HTMLWidget hw ;
+ Mask *valueMask ;
+ XSetWindowAttributes *attributes ;
+#else
+Realize (
+ HTMLWidget hw ,
+ Mask *valueMask ,
+ XSetWindowAttributes *attributes )
+#endif
+{
+ unsigned long valuemask;
+ XGCValues values;
+
+ /* Call the Realize method of the superclass to create the window. */
+ (*htmlWidgetClass->core_class.superclass->core_class.realize)
+ ((Widget)hw, valueMask, attributes);
+
+ /* Create the drawGC for the HTML window (copied from Expose). */
+ values.function = GXcopy;
+ values.plane_mask = AllPlanes;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ values.foreground = hw->manager.foreground;
+#else
+ values.foreground = hw->html.foreground;
+#endif /* MOTIF */
+ values.background = hw->core.background_pixel;
+
+ valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
+
+ hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
+ valuemask, &values);
+}
+
+
+#ifdef DEBUG
+void
+DebugHook(x, y, width, height)
+ int x, y, width, height;
+{
+fprintf(stderr, "Redrawing (%d,%d) %dx%d\n", x, y, width, height);
+}
+#endif
+
+
+/*
+ * This is called by redisplay. It is passed a rectangle
+ * in the viewing area, and it redisplays that portion of the
+ * underlying document area.
+ */
+static void
+#ifdef _NO_PROTO
+ViewRedisplay (hw, x, y, width, height)
+ HTMLWidget hw;
+ int x, y;
+ int width, height;
+#else
+ViewRedisplay(
+ HTMLWidget hw,
+ int x,
+ int y,
+ int width,
+ int height)
+#endif
+{
+ int sx, sy;
+ int doc_x, doc_y;
+ int i, start, end, guess;
+
+ /*
+ * Use scrollbar values to map from view space to document space.
+ */
+ sx = sy = 0;
+ if (hw->html.use_vbar == True)
+ {
+ sy += hw->html.scroll_y;
+ }
+ if (hw->html.use_hbar == True)
+ {
+ sx += hw->html.scroll_x;
+ }
+
+ doc_x = x + sx;
+ doc_y = y + sy;
+
+ /*
+ * Find the lines that overlap the exposed area.
+ */
+ start = 0;
+ end = hw->html.line_count - 1;
+
+ /*
+ * Heuristic to speed up redraws by guessing at the starting line.
+ */
+ guess = doc_y / (hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent);
+ if (guess > end)
+ {
+ guess = end;
+ }
+ while (guess > 0)
+ {
+ if ((hw->html.line_array[guess] != NULL)&&
+ (hw->html.line_array[guess]->y < doc_y))
+ {
+ break;
+ }
+ guess--;
+ }
+ if (guess < start)
+ {
+ guess = start;
+ }
+
+ for (i=guess; i<hw->html.line_count; i++)
+ {
+ if (hw->html.line_array[i] == NULL)
+ {
+ continue;
+ }
+
+ if (hw->html.line_array[i]->y < doc_y)
+ {
+ start = i;
+ }
+ if (hw->html.line_array[i]->y > (doc_y + height))
+ {
+ end = i;
+ break;
+ }
+ }
+
+ /*
+ * If we have a GC draw the lines that overlap the exposed area.
+ */
+ if (hw->html.drawGC != NULL)
+ {
+ for (i=start; i<=end; i++)
+ {
+ PlaceLine(hw, i);
+ }
+#ifdef EXTRA_FLUSH
+ XFlush(XtDisplay(hw));
+#endif
+ }
+}
+
+
+static void
+#ifdef _NO_PROTO
+ViewClearAndRefresh (hw)
+ HTMLWidget hw;
+#else
+ViewClearAndRefresh(
+ HTMLWidget hw)
+#endif
+{
+ /*
+ * Only refresh if we have a window already.
+ * (if we have a GC we have a window)
+ */
+ if (hw->html.drawGC != NULL)
+ {
+ XClearArea(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ 0, 0, 0, 0, False);
+ ViewRedisplay(hw, 0, 0,
+ hw->html.view_width, hw->html.view_height);
+ /*
+ * This is a fake deal to make an Expose event tocall Redisplay
+ * to redraw the shadow around the view area
+ */
+ XClearArea(XtDisplay(hw), XtWindow(hw),
+ 0, 0, 1, 1, True);
+ }
+}
+
+
+/*
+ * The Redisplay function is what you do with an expose event.
+ * Right now we call user callbacks, and then call the CompositeWidget's
+ * Redisplay routine.
+ */
+static void
+#ifdef _NO_PROTO
+Redisplay (hw, event, region)
+ HTMLWidget hw;
+ XEvent * event;
+ Region region;
+#else
+Redisplay(
+ HTMLWidget hw,
+ XEvent * event,
+ Region region)
+#endif
+{
+ XExposeEvent *ExEvent = (XExposeEvent *)event;
+ int dx, dy;
+
+#ifdef MOTIF
+ /*
+ * find out where the shadow is based on scrollbars
+ */
+
+ Dimension st = hw->manager.shadow_thickness;
+#endif /* MOTIF */
+
+ dx = dy = 0;
+ if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
+ {
+ dx += VbarWidth(hw);
+ }
+ if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
+ {
+ dy += HbarHeight(hw);
+ }
+
+#ifdef MOTIF
+ /*
+ * Redraw the shadow around the scrolling area which may have been
+ * messed up.
+ */
+ _XmDrawShadow(XtDisplay(hw), XtWindow(hw),
+ hw->manager.bottom_shadow_GC, hw->manager.top_shadow_GC,
+ hw->manager.shadow_thickness, dx, dy,
+ hw->html.view_width + (2 * st),hw->html.view_height + (2 * st));
+#endif /* MOTIF */
+
+#ifdef MOTIF
+#ifdef MOTIF1_2
+ _XmRedisplayGadgets ((Widget)hw, (XEvent*)event, region);
+#else
+ _XmRedisplayGadgets ((CompositeWidget)hw, (XExposeEvent*)event, region);
+#endif /* MOTIF1_2 */
+#endif /* MOTIF */
+
+ return;
+}
+
+
+/*
+ * Resize is called when the widget changes size.
+ * Mostly any resize causes a reformat, except for the special case
+ * where the width doesn't change, and the height doesn't change
+ * enought to affect the vertical scrollbar.
+ * It is too complex to guess exactly what needs to be redrawn, so refresh the
+ * whole window on any resize.
+ */
+static void
+#ifdef _NO_PROTO
+Resize (hw)
+ HTMLWidget hw;
+#else
+Resize(
+ HTMLWidget hw)
+#endif
+{
+ int tempw;
+ Dimension swidth, sheight;
+ Dimension st;
+
+ /*
+ * Find the new widht of the viewing area.
+ */
+ swidth = VbarWidth(hw);
+ sheight = HbarHeight(hw);
+#ifdef MOTIF
+ st = hw->manager.shadow_thickness;
+#else
+ st = 0;
+#endif /* MOTIF */
+ if (hw->core.width <= swidth)
+ {
+ hw->core.width = swidth + 10 ;
+ }
+
+ if (hw->html.use_vbar == True)
+ {
+ tempw = hw->core.width - swidth - (2 * st);
+ }
+ else
+ {
+ tempw = hw->core.width - (2 * st);
+ /* fool positioning of horz scrollbar later */
+ swidth = 0;
+ }
+
+ /*
+ * Special case where we don't have to reformat to a new width.
+ * The width has not changed, and the height has not changed
+ * significantly to change the state of the vertical scrollbar.
+ */
+ if ((tempw == hw->html.view_width)&&
+ (((hw->html.use_vbar == True)&&
+ ((hw->core.height - sheight - (2 * st)) < hw->html.doc_height))||
+ ((hw->html.use_vbar == False)&&
+ ((hw->core.height - sheight - (2 * st)) >= hw->html.doc_height))))
+ {
+ /*
+ * Super special case where the size of the window hasn't
+ * changed at ALL!
+ */
+ if (((hw->html.use_hbar == True)&&(hw->html.view_height ==
+ (hw->core.height - sheight - (2 * st))))||
+ ((hw->html.use_hbar == False)&&(hw->html.view_height ==
+ (hw->core.height - (2 * st)))))
+ {
+ return;
+ }
+
+ if (hw->html.use_hbar == True)
+ {
+ if (hw->html.hbar_top == True)
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0, 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth, 0);
+ }
+ }
+ else
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0,
+ (hw->core.height - sheight));
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth,
+ (hw->core.height - sheight));
+ }
+ }
+ hw->html.view_height = hw->core.height - sheight -
+ (2 * st);
+ }
+ else
+ {
+ hw->html.view_height = hw->core.height - (2 * st);
+ }
+#ifdef DEBUG
+fprintf (stderr, "calling in Resize\n");
+#endif
+ ConfigScrollBars(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ /*
+ * Otherwise we have to do a full reformat on every resize.
+ */
+ else
+ {
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+
+#ifdef DEBUG
+ {
+ int ss;
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "leaving; slider size %d\n", ss);
+ }
+#endif
+
+ return;
+}
+
+
+/*
+ * Find the complete text for this the anchor that aptr is a part of
+ * and set it into the selection.
+ */
+static void
+FindSelectAnchor(hw, aptr)
+ HTMLWidget hw;
+ struct ele_rec *aptr;
+{
+ struct ele_rec *eptr;
+
+ eptr = aptr;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->anchorHRef != NULL)&&
+ (strcmp(eptr->prev->anchorHRef, eptr->anchorHRef) == 0))
+ {
+ eptr = eptr->prev;
+ }
+ hw->html.select_start = eptr;
+ hw->html.sel_start_pos = 0;
+
+ eptr = aptr;
+ while ((eptr->next != NULL)&&
+ (eptr->next->anchorHRef != NULL)&&
+ (strcmp(eptr->next->anchorHRef, eptr->anchorHRef) == 0))
+ {
+ eptr = eptr->next;
+ }
+ hw->html.select_end = eptr;
+ hw->html.sel_end_pos = eptr->edata_len - 2;
+}
+
+
+/*
+ * Set as active all elements in the widget that are part of the anchor
+ * in the widget's start ptr.
+ */
+static void
+SetAnchor(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *eptr;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ unsigned long fg, bg;
+ unsigned long old_fg, old_bg;
+
+ eptr = hw->html.active_anchor;
+ if ((eptr == NULL)||(eptr->anchorHRef == NULL))
+ {
+ return;
+ }
+ fg = hw->html.activeAnchor_fg;
+ bg = hw->html.activeAnchor_bg;
+
+ FindSelectAnchor(hw, eptr);
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ if (eptr->type == E_TEXT)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ else if (eptr->type == E_IMAGE)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ ImageRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ /*
+ * Linefeeds in anchor spanning multiple lines should NOT
+ * be highlighted!
+ else if (eptr->type == E_LINEFEED)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ LinefeedRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ */
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ if (eptr->type == E_TEXT)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ else if (eptr->type == E_IMAGE)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ ImageRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ /*
+ * Linefeeds in anchor spanning multiple lines should NOT
+ * be highlighted!
+ else if (eptr->type == E_LINEFEED)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ LinefeedRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ */
+ }
+}
+
+
+/*
+ * Draw selection for all elements in the widget
+ * from start to end.
+ */
+static void
+DrawSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *eptr;
+ int epos;
+
+ if ((start == NULL)||(end == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Keep positions within bounds (allows us to be sloppy elsewhere)
+ */
+ if (start_pos < 0)
+ {
+ start_pos = 0;
+ }
+ if (start_pos >= start->edata_len - 1)
+ {
+ start_pos = start->edata_len - 2;
+ }
+ if (end_pos < 0)
+ {
+ end_pos = 0;
+ }
+ if (end_pos >= end->edata_len - 1)
+ {
+ end_pos = end->edata_len - 2;
+ }
+
+ if (SwapElements(start, end, start_pos, end_pos))
+ {
+ eptr = start;
+ start = end;
+ end = eptr;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+ p2 = eptr->edata_len - 2;
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = True;
+ eptr->start_pos = p1;
+ eptr->end_pos = p2;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = True;
+ LinefeedRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+
+ if (eptr == end)
+ {
+ p2 = end_pos;
+ }
+ else
+ {
+ p2 = eptr->edata_len - 2;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = True;
+ eptr->start_pos = p1;
+ eptr->end_pos = p2;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = True;
+ LinefeedRefresh(hw, eptr);
+ }
+ }
+}
+
+
+/*
+ * Set selection for all elements in the widget's
+ * start to end list.
+ */
+static void
+SetSelection(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+ start_pos = hw->html.sel_start_pos;
+ end_pos = hw->html.sel_end_pos;
+ DrawSelection(hw, start, end, start_pos, end_pos);
+}
+
+
+/*
+ * Erase the selection from start to end
+ */
+static void
+EraseSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *eptr;
+ int epos;
+
+ if ((start == NULL)||(end == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Keep positoins within bounds (allows us to be sloppy elsewhere)
+ */
+ if (start_pos < 0)
+ {
+ start_pos = 0;
+ }
+ if (start_pos >= start->edata_len - 1)
+ {
+ start_pos = start->edata_len - 2;
+ }
+ if (end_pos < 0)
+ {
+ end_pos = 0;
+ }
+ if (end_pos >= end->edata_len - 1)
+ {
+ end_pos = end->edata_len - 2;
+ }
+
+ if (SwapElements(start, end, start_pos, end_pos))
+ {
+ eptr = start;
+ start = end;
+ end = eptr;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+ p2 = eptr->edata_len - 2;
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = False;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = False;
+ LinefeedRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+
+ if (eptr == end)
+ {
+ p2 = end_pos;
+ }
+ else
+ {
+ p2 = eptr->edata_len - 2;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = False;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = False;
+ LinefeedRefresh(hw, eptr);
+ }
+ }
+}
+
+
+/*
+ * Clear the current selection (if there is one)
+ */
+static void
+ClearSelection(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+ start_pos = hw->html.sel_start_pos;
+ end_pos = hw->html.sel_end_pos;
+ EraseSelection(hw, start, end, start_pos, end_pos);
+
+ if ((start == NULL)||(end == NULL))
+ {
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.active_anchor = NULL;
+ return;
+ }
+
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.active_anchor = NULL;
+}
+
+
+/*
+ * clear from active all elements in the widget that are part of the anchor.
+ * (These have already been previously set into the start and end of the
+ * selection.
+ */
+static void
+UnsetAnchor(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *eptr;
+
+ /*
+ * Clear any activated images
+ */
+ eptr = hw->html.select_start;
+ while ((eptr != NULL)&&(eptr != hw->html.select_end))
+ {
+ if (eptr->type == E_IMAGE)
+ {
+ ImageRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ ImageRefresh(hw, eptr);
+ }
+
+ /*
+ * Clear the activated anchor
+ */
+ ClearSelection(hw);
+}
+
+
+/*
+ * Erase the old selection, and draw the new one in such a way
+ * that advantage is taken of overlap, and there is no obnoxious
+ * flashing.
+ */
+static void
+ChangeSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *old_start;
+ struct ele_rec *old_end;
+ struct ele_rec *new_start;
+ struct ele_rec *new_end;
+ struct ele_rec *eptr;
+ int epos;
+ int new_start_pos, new_end_pos;
+ int old_start_pos, old_end_pos;
+
+ old_start = hw->html.new_start;
+ old_end = hw->html.new_end;
+ old_start_pos = hw->html.new_start_pos;
+ old_end_pos = hw->html.new_end_pos;
+ new_start = start;
+ new_end = end;
+ new_start_pos = start_pos;
+ new_end_pos = end_pos;
+
+ if ((new_start == NULL)||(new_end == NULL))
+ {
+ return;
+ }
+
+ if ((old_start == NULL)||(old_end == NULL))
+ {
+ DrawSelection(hw, new_start, new_end,
+ new_start_pos, new_end_pos);
+ return;
+ }
+
+ if (SwapElements(old_start, old_end, old_start_pos, old_end_pos))
+ {
+ eptr = old_start;
+ old_start = old_end;
+ old_end = eptr;
+ epos = old_start_pos;
+ old_start_pos = old_end_pos;
+ old_end_pos = epos;
+ }
+
+ if (SwapElements(new_start, new_end, new_start_pos, new_end_pos))
+ {
+ eptr = new_start;
+ new_start = new_end;
+ new_end = eptr;
+ epos = new_start_pos;
+ new_start_pos = new_end_pos;
+ new_end_pos = epos;
+ }
+
+ /*
+ * Deal with all possible intersections of the 2 selection sets.
+ *
+ ********************************************************
+ * * *
+ * |-- * |-- *
+ * old--| * new--| *
+ * |-- * |-- *
+ * * *
+ * |-- * |-- *
+ * new--| * old--| *
+ * |-- * |-- *
+ * * *
+ ********************************************************
+ * * *
+ * |---- * |-- *
+ * old--| * new--| *
+ * | |-- * | *
+ * |-+-- * |-+-- *
+ * | * | |-- *
+ * new--| * old--| *
+ * |-- * |---- *
+ * * *
+ ********************************************************
+ * * *
+ * |--------- * |--------- *
+ * | * | *
+ * | |-- * | |-- *
+ * new--| old--| * old--| new--| *
+ * | |-- * | |-- *
+ * | * | *
+ * |--------- * |--------- *
+ * * *
+ ********************************************************
+ *
+ */
+ if ((ElementLessThan(old_end, new_start, old_end_pos, new_start_pos))||
+ (ElementLessThan(new_end, old_start, new_end_pos, old_start_pos)))
+ {
+ EraseSelection(hw, old_start, old_end,
+ old_start_pos, old_end_pos);
+ DrawSelection(hw, new_start, new_end,
+ new_start_pos, new_end_pos);
+ }
+ else if ((ElementLessThan(old_start, new_start,
+ old_start_pos, new_start_pos))&&
+ (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
+ {
+ if (new_start_pos != 0)
+ {
+ EraseSelection(hw, old_start, new_start,
+ old_start_pos, new_start_pos - 1);
+ }
+ else
+ {
+ EraseSelection(hw, old_start, new_start->prev,
+ old_start_pos, new_start->prev->edata_len - 2);
+ }
+ if (old_end_pos < (old_end->edata_len - 2))
+ {
+ DrawSelection(hw, old_end, new_end,
+ old_end_pos + 1, new_end_pos);
+ }
+ else
+ {
+ DrawSelection(hw, old_end->next, new_end,
+ 0, new_end_pos);
+ }
+ }
+ else if ((ElementLessThan(new_start, old_start,
+ new_start_pos, old_start_pos))&&
+ (ElementLessThan(new_end, old_end, new_end_pos, old_end_pos)))
+ {
+ if (old_start_pos != 0)
+ {
+ DrawSelection(hw, new_start, old_start,
+ new_start_pos, old_start_pos - 1);
+ }
+ else
+ {
+ DrawSelection(hw, new_start, old_start->prev,
+ new_start_pos, old_start->prev->edata_len - 2);
+ }
+ if (new_end_pos < (new_end->edata_len - 2))
+ {
+ EraseSelection(hw, new_end, old_end,
+ new_end_pos + 1, old_end_pos);
+ }
+ else
+ {
+ EraseSelection(hw, new_end->next, old_end,
+ 0, old_end_pos);
+ }
+ }
+ else if ((ElementLessThan(new_start, old_start,
+ new_start_pos, old_start_pos))||
+ (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
+ {
+ if ((new_start != old_start)||(new_start_pos != old_start_pos))
+ {
+ if (old_start_pos != 0)
+ {
+ DrawSelection(hw, new_start, old_start,
+ new_start_pos, old_start_pos - 1);
+ }
+ else
+ {
+ DrawSelection(hw, new_start, old_start->prev,
+ new_start_pos,
+ old_start->prev->edata_len - 2);
+ }
+ }
+ if ((old_end != new_end)||(old_end_pos != new_end_pos))
+ {
+ if (old_end_pos < (old_end->edata_len - 2))
+ {
+ DrawSelection(hw, old_end, new_end,
+ old_end_pos + 1, new_end_pos);
+ }
+ else
+ {
+ DrawSelection(hw, old_end->next, new_end,
+ 0, new_end_pos);
+ }
+ }
+ }
+ else
+ {
+ if ((old_start != new_start)||(old_start_pos != new_start_pos))
+ {
+ if (new_start_pos != 0)
+ {
+ EraseSelection(hw, old_start, new_start,
+ old_start_pos, new_start_pos - 1);
+ }
+ else
+ {
+ EraseSelection(hw, old_start, new_start->prev,
+ old_start_pos,
+ new_start->prev->edata_len - 2);
+ }
+ }
+ if ((new_end != old_end)||(new_end_pos != old_end_pos))
+ {
+ if (new_end_pos < (new_end->edata_len - 2))
+ {
+ EraseSelection(hw, new_end, old_end,
+ new_end_pos + 1, old_end_pos);
+ }
+ else
+ {
+ EraseSelection(hw, new_end->next, old_end,
+ 0, old_end_pos);
+ }
+ }
+ }
+}
+
+
+static void
+SelectStart(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
+ struct ele_rec *eptr;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+#ifdef NOT_RIGHT
+ XUndefineCursor(XtDisplay(hw->html.view), XtWindow(hw->html.view));
+#endif
+ XUndefineCursor(XtDisplay(hw), XtWindow(hw));
+
+ /*
+ * Because X sucks, we can get the button pressed in the window, but
+ * released out of the window. This will highlight some text, but
+ * never complete the selection. Now on the next button press we
+ * have to clean up this mess.
+ */
+ EraseSelection(hw, hw->html.new_start, hw->html.new_end,
+ hw->html.new_start_pos, hw->html.new_end_pos);
+
+ /*
+ * We want to erase the currently selected text, but still save the
+ * selection internally in case we don't create a new one.
+ */
+ EraseSelection(hw, hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos);
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = 0;
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+ if (eptr != NULL)
+ {
+ /*
+ * If this is an anchor assume for now we are activating it
+ * and not selecting it.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ hw->html.active_anchor = eptr;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ SetAnchor(hw);
+ }
+ /*
+ * Else if we are on an image we can't select text so
+ * pretend we got eptr==NULL, and exit here.
+ */
+ else if (eptr->type == E_IMAGE)
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ hw->html.but_press_time = BuEvent->time;
+ return;
+ }
+ /*
+ * Else if we used button2, we can't select text, so exit
+ * here.
+ */
+ else if (BuEvent->button == Button2)
+ {
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ hw->html.but_press_time = BuEvent->time;
+ return;
+ }
+ /*
+ * Else a single click will not select a new object
+ * but it will prime that selection on the next mouse
+ * move.
+ * Ignore special internal text
+ */
+ else if (eptr->internal == False)
+ {
+ hw->html.new_start = eptr;
+ hw->html.new_start_pos = epos;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ else
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ }
+ else
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ hw->html.but_press_time = BuEvent->time;
+}
+
+
+static void
+ExtendStart(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ struct ele_rec *old_start, *old_end;
+ int old_start_pos, old_end_pos;
+ int start_pos, end_pos;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+
+ /*
+ * Ignore IMAGE elements.
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ eptr = NULL;
+ }
+
+ /*
+ * Ignore NULL elements.
+ * Ignore special internal text
+ * documents.
+ */
+ if ((eptr != NULL)&&(eptr->internal == False))
+ {
+ old_start = hw->html.new_start;
+ old_start_pos = hw->html.new_start_pos;
+ old_end = hw->html.new_end;
+ old_end_pos = hw->html.new_end_pos;
+ if (hw->html.new_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ hw->html.new_end = eptr;
+ hw->html.new_end_pos = epos;
+ }
+
+ if (SwapElements(hw->html.new_start, hw->html.new_end,
+ hw->html.new_start_pos, hw->html.new_end_pos))
+ {
+ if (SwapElements(eptr, hw->html.new_end,
+ epos, hw->html.new_end_pos))
+ {
+ start = hw->html.new_end;
+ start_pos = hw->html.new_end_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ else
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ }
+ else
+ {
+ if (SwapElements(eptr, hw->html.new_start,
+ epos, hw->html.new_start_pos))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ else
+ {
+ start = hw->html.new_end;
+ start_pos = hw->html.new_end_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ }
+
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+
+ if (old_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ hw->html.new_start = old_start;
+ hw->html.new_end = old_end;
+ hw->html.new_start_pos = old_start_pos;
+ hw->html.new_end_pos = old_end_pos;
+ }
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.new_start = start;
+ hw->html.new_end = end;
+ hw->html.new_start_pos = start_pos;
+ hw->html.new_end_pos = end_pos;
+ }
+ else
+ {
+ if (hw->html.new_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ }
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+}
+
+
+static void
+ExtendAdjust(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XPointerMovedEvent *MoEvent = (XPointerMovedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ int start_pos, end_pos;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ /*
+ * Very small mouse motion immediately after button press
+ * is ignored.
+ */
+ if ((ABS((hw->html.press_x - MoEvent->x)) <= SELECT_THRESHOLD)&&
+ (ABS((hw->html.press_y - MoEvent->y)) <= SELECT_THRESHOLD))
+ {
+ return;
+ }
+
+ /*
+ * If we have an active anchor and we got here, we have moved the
+ * mouse too far. Deactivate anchor, and prime a selection.
+ * If the anchor is internal text, don't
+ * prime a selection.
+ */
+ if (hw->html.active_anchor != NULL)
+ {
+ eptr = hw->html.active_anchor;
+ UnsetAnchor(hw);
+ if (eptr->internal == False)
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+ }
+
+ /*
+ * If we used button2, we can't select text, so
+ * clear selection and exit here.
+ */
+ if ((MoEvent->state & Button2Mask) != 0)
+ {
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ return;
+ }
+
+ eptr = LocateElement(hw, MoEvent->x, MoEvent->y, &epos);
+
+ /*
+ * If we are on an image pretend we are nowhere
+ * and just return;
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ return;
+ }
+
+ /*
+ * Ignore NULL items.
+ * Ignore if the same as last selected item and position.
+ * Ignore special internal text
+ */
+ if ((eptr != NULL)&&
+ ((eptr != hw->html.new_end)||(epos != hw->html.new_end_pos))&&
+ (eptr->internal == False))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.new_start = start;
+ hw->html.new_end = end;
+ hw->html.new_start_pos = start_pos;
+ hw->html.new_end_pos = end_pos;
+ }
+}
+
+
+static void
+ExtendEnd(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonReleasedEvent *BuEvent = (XButtonReleasedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ Atom *atoms;
+ int i, buffer;
+ int start_pos, end_pos;
+ int epos;
+ char *text;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+
+ /*
+ * If we just released button one or two, and we are on an object,
+ * and we have an active anchor, and we are on the active anchor,
+ * and if we havn't waited too long. Activate that anchor.
+ */
+ if (((BuEvent->button == Button1)||(BuEvent->button == Button2))&&
+ (eptr != NULL)&&
+ (hw->html.active_anchor != NULL)&&
+ (eptr == hw->html.active_anchor)&&
+ ((BuEvent->time - hw->html.but_press_time) < CLICK_TIME))
+ {
+ _HTMLInput(w, event, params, num_params);
+ return;
+ }
+ else if (hw->html.active_anchor != NULL)
+ {
+ start = hw->html.active_anchor;
+ UnsetAnchor(hw);
+ if (start->internal == False)
+ {
+ hw->html.new_start = eptr;
+ hw->html.new_start_pos = epos;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+ }
+
+ /*
+ * If we used button2, we can't select text, so clear
+ * selection and exit here.
+ */
+ if (BuEvent->button == Button2)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = 0;
+ return;
+ }
+
+ /*
+ * If we are on an image, pretend we are nowhere
+ * and NULL out the eptr
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ eptr = NULL;
+ }
+
+ /*
+ * If button released on a NULL item, take the last non-NULL
+ * item that we highlighted.
+ */
+ if ((eptr == NULL)&&(hw->html.new_end != NULL))
+ {
+ eptr = hw->html.new_end;
+ epos = hw->html.new_end_pos;
+ }
+
+ if ((eptr != NULL)&&(eptr->internal == False)&&
+ (hw->html.new_end != NULL))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.select_start = start;
+ hw->html.sel_start_pos = start_pos;
+ hw->html.select_end = end;
+ hw->html.sel_end_pos = end_pos;
+ SetSelection(hw);
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+
+ atoms = (Atom *)malloc(*num_params * sizeof(Atom));
+ if (atoms == NULL)
+ {
+ fprintf(stderr, "cannot allocate atom list\n");
+ return;
+ }
+ XmuInternStrings(XtDisplay((Widget)hw), params, *num_params, atoms);
+ hw->html.selection_time = BuEvent->time;
+ for (i=0; i< *num_params; i++)
+ {
+ switch (atoms[i])
+ {
+ case XA_CUT_BUFFER0: buffer = 0; break;
+ case XA_CUT_BUFFER1: buffer = 1; break;
+ case XA_CUT_BUFFER2: buffer = 2; break;
+ case XA_CUT_BUFFER3: buffer = 3; break;
+ case XA_CUT_BUFFER4: buffer = 4; break;
+ case XA_CUT_BUFFER5: buffer = 5; break;
+ case XA_CUT_BUFFER6: buffer = 6; break;
+ case XA_CUT_BUFFER7: buffer = 7; break;
+ default: buffer = -1; break;
+ }
+ if (buffer >= 0)
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ XStoreBuffer(XtDisplay((Widget)hw),
+ text, strlen(text), buffer);
+ if (text != NULL)
+ {
+ free(text);
+ }
+ }
+ else
+ {
+ XtOwnSelection((Widget)hw, atoms[i],
+ BuEvent->time,
+ (XtConvertSelectionProc )ConvertSelection,
+ (XtLoseSelectionProc )LoseSelection,
+ (XtSelectionDoneProc )SelectionDone);
+ }
+ }
+ free((char *)atoms);
+ }
+ else if (eptr == NULL)
+ {
+ hw->html.select_start = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.select_end = NULL;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+}
+
+
+#define LEAVING_ANCHOR(hw) \
+ hw->html.cached_tracked_ele = NULL; \
+ (*(pointerTrackProc) \
+ (hw->html.pointer_motion_callback))(hw, hw->html.pm_client_data, ""); \
+ XUndefineCursor (XtDisplay (hw), XtWindow (hw));
+
+/* KNOWN PROBLEM: We never get LeaveNotify or FocusOut events,
+ despite the fact we've requested them. Bummer. */
+static void
+TrackMotion(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ struct ele_rec *eptr;
+ int epos, x, y;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ if (!hw->html.pointer_motion_callback)
+ return;
+
+ if (event->type == MotionNotify)
+ {
+ x = ((XMotionEvent *)event)->x;
+ y = ((XMotionEvent *)event)->y;
+ }
+ else if (event->type == LeaveNotify || event->type == FocusOut ||
+ event->type == Expose)
+ {
+ /* Wipe out. */
+ if (hw->html.cached_tracked_ele)
+ {
+ LEAVING_ANCHOR (hw);
+ }
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, x, y, &epos);
+
+ /* We're hitting a new anchor if eptr exists and
+ eptr != cached tracked element and anchorHRef != NULL. */
+ if (eptr != NULL && eptr != hw->html.cached_tracked_ele &&
+ eptr->anchorHRef != NULL)
+ {
+ hw->html.cached_tracked_ele = eptr;
+ (*(pointerTrackProc)
+ (hw->html.pointer_motion_callback))
+ (hw, hw->html.pm_client_data, eptr->anchorHRef);
+ XDefineCursor (XtDisplay (hw), XtWindow (hw), in_anchor_cursor);
+ }
+ /* We're leaving an anchor if eptr exists and
+ a cached ele exists and we're not entering a new anchor. */
+ else if (eptr != NULL && hw->html.cached_tracked_ele != NULL &&
+ eptr->anchorHRef == NULL)
+ {
+ LEAVING_ANCHOR (hw);
+ }
+
+ return;
+}
+
+
+/*
+ * Scroll display vertically.
+ */
+static void
+Scroll (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ register HTMLWidget hw = (HTMLWidget)XtParent(w);
+#ifdef MOTIF
+ int val, size, inc, pageinc;
+#endif
+ int offset, newy;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ return;
+
+ if (*num_params > 0) {
+ char *s = params[0];
+ double fraction;
+ double atof();
+ int ch;
+
+ if (strcmp (s + strlen(s) - 2, "ch") == 0) {
+ fraction = atof (s);
+ ch = (hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent);
+ offset = fraction * ch;
+ } else
+ offset = (int)hw->html.view_height * atof(s);
+
+ } else
+ offset = (int)hw->html.view_height / 10;
+
+ newy = hw->html.scroll_y + offset;
+ if (newy < 0)
+ newy = 0;
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ if (newy < 0)
+ newy = 0;
+
+#ifdef MOTIF
+ XmScrollBarGetValues(hw->html.vbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.vbar, newy, size, inc, pageinc, True);
+ XmScrollBarGetValues(hw->html.hbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.hbar, 0, size, inc, pageinc, True);
+#else
+ ScrollToPos(hw->html.vbar, hw, newy);
+ ScrollToPos(hw->html.hbar, hw, 0);
+ setScrollBar(hw->html.vbar, newy,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif
+}
+
+
+/*
+ * Process mouse input to the HTML widget
+ * Currently only processes an anchor-activate when Button1
+ * is pressed
+ */
+static void
+#ifdef _NO_PROTO
+_HTMLInput( w, event, params, num_params)
+ Widget w ;
+ XEvent *event ;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+#else
+_HTMLInput(
+ Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params) /* unused */
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ struct ele_rec *eptr;
+ WbAnchorCallbackData cbdata;
+ int epos;
+#ifdef MOTIF
+ Boolean on_gadget;
+#endif /* MOTIF */
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+#ifdef MOTIF
+ /*
+ * If motif is defined, we don't want to process this button press
+ * if it is on a gadget
+ */
+#ifdef MOTIF1_2
+ on_gadget = (_XmInputForGadget((Widget)hw,
+#else
+ on_gadget = (_XmInputForGadget((CompositeWidget)hw,
+#endif /* MOTIF1_2 */
+ event->xbutton.x, event->xbutton.y) != NULL);
+
+ if (on_gadget)
+ {
+ return;
+ }
+#endif /* MOTIF */
+
+ if (event->type == ButtonRelease)
+ {
+ eptr = LocateElement(hw, event->xbutton.x, event->xbutton.y,
+ &epos);
+ if (eptr != NULL)
+ {
+ if (eptr->anchorHRef != NULL)
+ {
+ char *tptr, *ptr;
+
+ /*
+ * Save the anchor text, replace newlines with
+ * spaces.
+ */
+ tptr = ParseTextToString(hw->html.select_start,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ ptr = tptr;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ if (*ptr == '\n')
+ {
+ *ptr = ' ';
+ }
+ ptr++;
+ }
+
+ /*
+ * Clear the activated anchor
+ */
+ UnsetAnchor(hw);
+#ifdef EXTRA_FLUSH
+ XFlush(XtDisplay(hw));
+#endif
+
+ if ((IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (hw->html.resolveDelayedImage != NULL))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->delayed)&&
+ (eptr->anchorHRef != NULL)&&
+ (IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->delayed)&&
+ (eptr->anchorHRef != NULL)&&
+ (!IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (!IsIsMapForm(hw, eptr->anchorHRef))&&
+ (((event->xbutton.y + hw->html.scroll_y) -
+ (eptr->y + eptr->y_offset)) >
+ AnchoredHeight(hw)))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+ eptr->pic_data->delayed = 0;
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->ismap)&&
+ (eptr->anchorHRef != NULL)&&
+ (IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ int form_x, form_y;
+
+ form_x = event->xbutton.x + hw->html.scroll_x -
+ eptr->x;
+ form_y = event->xbutton.y + hw->html.scroll_y -
+ eptr->y;
+ ImageSubmitForm(eptr->pic_data->fptr, event,
+ eptr->pic_data->text, form_x, form_y);
+ }
+ else
+ {
+ /* The following is a hack to send the
+ * selection location along with the HRef
+ * for images. This allows you to
+ * point at a location on a map and have
+ * the server send you the related document.
+ * Tony Sanders, April 1993 <sanders@bsdi.com>
+ */
+ int alloced = 0;
+ char *buf = eptr->anchorHRef;
+ if (eptr->type == E_IMAGE && eptr->pic_data
+ && eptr->pic_data->ismap) {
+ buf = (char *)
+ malloc(strlen(eptr->anchorHRef) + 256);
+ alloced = 1;
+ sprintf(buf, "%s?%d,%d",
+ eptr->anchorHRef,
+ event->xbutton.x + hw->html.scroll_x - eptr->x,
+ event->xbutton.y + hw->html.scroll_y - eptr->y);
+ }
+ /*
+ * XXX: should call a media dependent
+ * function that decides how to munge the
+ * HRef. For example mpeg data will want
+ * to know on what frame the event occured.
+ *
+ * cddata.href = *(eptr->eventf)(eptr, event);
+ */
+ cbdata.event = event;
+ cbdata.element_id = eptr->ele_id;
+ cbdata.href = buf;
+ /* cbdata.href = eptr->anchorHRef; */
+ cbdata.text = tptr;
+ XtCallCallbackList ((Widget)hw,
+ hw->html.anchor_callback,
+ (XtPointer)&cbdata);
+ if (alloced) free(buf);
+ if (tptr != NULL) free(tptr);
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+
+#ifndef MOTIF
+#include <X11/Xaw/AsciiText.h>
+/*
+ * Process key input passwd widgets
+ */
+static void
+#ifdef _NO_PROTO
+_HTMLpwdInput( w, event, params, num_params)
+ Widget w ;
+ XEvent *event ;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+#else
+_HTMLpwdInput(
+ Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params) /* unused */
+#endif
+ {
+ char buffer[50];
+ KeySym ks;
+ char *keySymString;
+ char *star = "*";
+ int length, passwdLength, i, insertPos, maxLength;
+ Boolean stringInPlace;
+
+ if (event->type == KeyPress)
+ {
+ HTMLWidget hw = (HTMLWidget)XtParent(XtParent(w));
+ WidgetInfo *wptr;
+
+ if (XtClass((Widget)hw) != htmlWidgetClass)
+ return; /* it was not for us */
+
+ /*
+ * find the structure for this widget
+ */
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->w == w)
+ break;
+ wptr = wptr->next;
+ }
+ if (wptr == NULL)
+ return;
+
+ passwdLength = wptr->password ? strlen(wptr->password) : 0;
+
+ length = XLookupString((XKeyEvent *)event,
+ buffer, 50, &ks, NULL);
+ keySymString = XKeysymToString(ks);
+ XtVaGetValues(w,
+ XtNinsertPosition,&insertPos,
+ XtNuseStringInPlace, &stringInPlace,
+ XtNlength, &maxLength,
+ NULL);
+
+ if (maxLength<1) maxLength = 1000000;
+
+ if (!strcmp("Left",keySymString))
+ {
+ if (insertPos > 0)
+ XtVaSetValues(w,XtNinsertPosition,--insertPos,NULL);
+ return;
+ }
+ else if (!strcmp("Right",keySymString))
+ {
+ if (insertPos < passwdLength)
+ XtVaSetValues(w,XtNinsertPosition,++insertPos,NULL);
+ return;
+ }
+
+ if ((!strcmp("BackSpace",keySymString))
+ || (!strcmp("Backspace",keySymString))
+ || (!strcmp("Delete",keySymString)) )
+ {
+ insertPos --;
+
+ if (passwdLength>0)
+ {
+ char *pwd = &(wptr->password[insertPos]);
+
+ for (i = passwdLength - insertPos; i>0; i--,pwd++)
+ *pwd = *(pwd+1);
+
+/* fprintf(stderr,"modified passwd <%s>\n", wptr->password);*/
+ XtCallActionProc(w,
+ insertPos>-1 ? "delete-previous-character" :
+ "delete-next-character",
+ event, NULL,0);
+ }
+ /* else nothing to erase */
+ return;
+ }
+
+ if (length == 1)
+ {
+ buffer[1] = '\0';
+
+ if (passwdLength>0)
+ {
+
+ if (passwdLength < maxLength)
+ {
+ char *pwd = wptr->password =
+ (char *)realloc(wptr->password,
+ sizeof(char)*(passwdLength+2));
+ for (i=passwdLength+1; i>insertPos; i--)
+ pwd[i] = pwd[i-1];
+
+ pwd[insertPos] = buffer[0];
+ }
+ }
+ else
+ {
+ if (wptr->password == NULL)
+ wptr->password = (char *)malloc(sizeof(char)*2);
+
+ wptr->password[0] = buffer[0];
+ wptr->password[1] = '\0';
+ }
+
+ if (stringInPlace && passwdLength<maxLength)
+ {
+ char *txt;
+ /* insert string dumps core when string in place is true */
+
+ XtVaGetValues(w,XtNstring,&txt,NULL);
+ txt[passwdLength] = star[0];
+ txt[passwdLength+1] = '\0';
+
+ /* the combined set values command does not work */
+ XtVaSetValues(w, XtNstring,txt, NULL);
+ XtVaSetValues(w, XtNinsertPosition,insertPos+1, NULL);
+ }
+ else
+ XtCallActionProc(w, "insert-string", event, &star, 1);
+/* fprintf(stderr,"modified passwd <%s>\n", wptr->password); */
+ }
+ }
+ }
+#endif /* not MOTIF */
+
+
+/*
+ * SetValues is called when XtSetValues is used to change resources in this
+ * widget.
+ */
+static Boolean
+#ifdef _NO_PROTO
+SetValues (current, request, new)
+ HTMLWidget current ;
+ HTMLWidget request ;
+ HTMLWidget new ;
+#else
+SetValues(
+ HTMLWidget current,
+ HTMLWidget request,
+ HTMLWidget new)
+#endif
+{
+ int reformatted;
+
+ /*
+ * Make sure the underline numbers are within bounds.
+ */
+ if (request->html.num_anchor_underlines < 0)
+ {
+ new->html.num_anchor_underlines = 0;
+ }
+ if (request->html.num_anchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_anchor_underlines = MAX_UNDERLINES;
+ }
+ if (request->html.num_visitedAnchor_underlines < 0)
+ {
+ new->html.num_visitedAnchor_underlines = 0;
+ }
+ if (request->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
+ }
+
+ reformatted = 0;
+ if ((request->html.raw_text != current->html.raw_text)||
+ (request->html.header_text != current->html.header_text)||
+ (request->html.footer_text != current->html.footer_text))
+ {
+ /*
+ * Free up the old visited href list.
+ */
+ FreeHRefs(current->html.my_visited_hrefs);
+ new->html.my_visited_hrefs = NULL;
+
+ /*
+ * Free up the old visited delayed images list.
+ */
+ FreeDelayedImages(current->html.my_delayed_images);
+ new->html.my_delayed_images = NULL;
+
+ /*
+ * Free any old colors and pixmaps
+ */
+ FreeColors(XtDisplay(current), DefaultColormapOfScreen(XtScreen(current)));
+ FreeImages(current);
+
+ /*
+ * Hide any old widgets
+ */
+ HideWidgets(current);
+ new->html.widget_list = NULL;
+ new->html.form_list = NULL;
+
+ /*
+ * Parse the raw text with the HTML parser
+ */
+ new->html.html_objects = HTMLParse(current->html.html_objects,
+ request->html.raw_text);
+ CallLinkCallbacks(new);
+ new->html.html_header_objects =
+ HTMLParse(current->html.html_header_objects,
+ request->html.header_text);
+ new->html.html_footer_objects =
+ HTMLParse(current->html.html_footer_objects,
+ request->html.footer_text);
+
+ /*
+ * Redisplay for the changed data.
+ */
+ {
+ new->html.scroll_x = 0;
+ new->html.scroll_y = 0;
+ new->html.max_pre_width = DocumentWidth(new,
+ new->html.html_objects);
+ ReformatWindow(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * Clear any previous selection
+ */
+ new->html.select_start = NULL;
+ new->html.select_end = NULL;
+ new->html.sel_start_pos = 0;
+ new->html.sel_end_pos = 0;
+ new->html.new_start = NULL;
+ new->html.new_end = NULL;
+ new->html.new_start_pos = 0;
+ new->html.new_end_pos = 0;
+ new->html.active_anchor = NULL;
+ }
+ else if ((request->html.font != current->html.font)||
+ (request->html.italic_font != current->html.italic_font)||
+ (request->html.bold_font != current->html.bold_font)||
+ (request->html.fixed_font != current->html.fixed_font)||
+ (request->html.fixedbold_font != current->html.fixedbold_font)||
+ (request->html.fixeditalic_font != current->html.fixeditalic_font)||
+ (request->html.header1_font != current->html.header1_font)||
+ (request->html.header2_font != current->html.header2_font)||
+ (request->html.header3_font != current->html.header3_font)||
+ (request->html.header4_font != current->html.header4_font)||
+ (request->html.header5_font != current->html.header5_font)||
+ (request->html.header6_font != current->html.header6_font)||
+ (request->html.address_font != current->html.address_font)||
+ (request->html.plain_font != current->html.plain_font)||
+ (request->html.plainbold_font != current->html.plainbold_font)||
+ (request->html.plainitalic_font != current->html.plainitalic_font)||
+ (request->html.listing_font != current->html.listing_font)||
+ (request->html.activeAnchor_fg != current->html.activeAnchor_fg)||
+ (request->html.activeAnchor_bg != current->html.activeAnchor_bg)||
+ (request->html.anchor_fg != current->html.anchor_fg)||
+ (request->html.visitedAnchor_fg != current->html.visitedAnchor_fg)||
+ (request->html.dashed_anchor_lines != current->html.dashed_anchor_lines)||
+ (request->html.dashed_visitedAnchor_lines != current->html.dashed_visitedAnchor_lines)||
+ (request->html.num_anchor_underlines != current->html.num_anchor_underlines)||
+ (request->html.num_visitedAnchor_underlines != current->html.num_visitedAnchor_underlines))
+ {
+ if ((request->html.plain_font != current->html.plain_font)||
+ (request->html.listing_font != current->html.listing_font))
+ {
+ new->html.max_pre_width = DocumentWidth(new,
+ new->html.html_objects);
+ }
+
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * image borders have been changed
+ */
+ if (request->html.border_images != current->html.border_images)
+ {
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * vertical space has been changed
+ */
+ if(request->html.percent_vert_space != current->html.percent_vert_space)
+ {
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * Set client data for retest anchors callback.
+ */
+ if(request->html.vt_client_data != current->html.vt_client_data)
+ {
+ new->html.vt_client_data = request->html.vt_client_data;
+ }
+
+ /*
+ * Set client data for pointer motion callback.
+ */
+ if(request->html.pm_client_data != current->html.pm_client_data)
+ {
+ new->html.pm_client_data = request->html.pm_client_data;
+ }
+
+ return(False);
+}
+
+
+/*
+ * Go through the parsed marks and for all the <LINK> tags in the document
+ * call the LinkCallback.
+ */
+static void
+#ifdef _NO_PROTO
+CallLinkCallbacks(hw)
+ HTMLWidget hw;
+#else
+CallLinkCallbacks(HTMLWidget hw)
+#endif
+{
+ struct mark_up *mptr;
+ LinkInfo l_info;
+
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ l_info.href = ParseMarkTag(mptr->start, MT_BASE,
+ "HREF");
+ l_info.role = ParseMarkTag(mptr->start, MT_BASE,
+ "ROLE");
+ XtCallCallbackList ((Widget)hw, hw->html.link_callback,
+ (XtPointer)&l_info);
+ if (l_info.href != NULL)
+ {
+ free(l_info.href);
+ }
+ if (l_info.role != NULL)
+ {
+ free(l_info.role);
+ }
+ }
+ mptr = mptr->next;
+ }
+}
+
+
+/*
+ * Search through the whole document, and recolor the internal elements with
+ * the passed HREF.
+ */
+static void
+#ifdef _NO_PROTO
+RecolorInternalHRefs(hw, href)
+ HTMLWidget hw;
+ char *href;
+#else
+RecolorInternalHRefs(HTMLWidget hw, char *href)
+#endif
+{
+ struct ele_rec *start;
+ unsigned long fg;
+
+ fg = hw->html.visitedAnchor_fg;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ /*
+ * This one is internal
+ * This one has an href
+ * This is the href we want
+ */
+ if ((start->internal == True)&&
+ (start->anchorHRef != NULL)&&
+ (strcmp(start->anchorHRef, href) == 0))
+ {
+ start->fg = fg;
+ start->underline_number =
+ hw->html.num_visitedAnchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_visitedAnchor_lines;
+ }
+ start = start->next;
+ }
+}
+
+
+static Boolean
+ConvertSelection(w, selection, target, type, value, length, format)
+ Widget w;
+ Atom *selection, *target, *type;
+ caddr_t *value;
+ unsigned long *length;
+ int *format;
+{
+ Display *d = XtDisplay(w);
+ HTMLWidget hw = (HTMLWidget)w;
+ char *text;
+
+ if (hw->html.select_start == NULL)
+ {
+ return False;
+ }
+
+ if (*target == XA_TARGETS(d))
+ {
+ Atom *targetP;
+ Atom *std_targets;
+ unsigned long std_length;
+ XmuConvertStandardSelection( w, hw->html.selection_time,
+ selection, target, type, (caddr_t*)&std_targets,
+ &std_length, format);
+
+ *length = std_length + 5;
+ *value = (caddr_t)XtMalloc(sizeof(Atom)*(*length));
+ targetP = *(Atom**)value;
+ *targetP++ = XA_STRING;
+ *targetP++ = XA_TEXT(d);
+ *targetP++ = XA_COMPOUND_TEXT(d);
+ *targetP++ = XA_LENGTH(d);
+ *targetP++ = XA_LIST_LENGTH(d);
+
+ bcopy((char*)std_targets, (char*)targetP,
+ sizeof(Atom)*std_length);
+ XtFree((char*)std_targets);
+ *type = XA_ATOM;
+ *format = 32;
+ return True;
+ }
+
+ if (*target == XA_STRING || *target == XA_TEXT(d) ||
+ *target == XA_COMPOUND_TEXT(d))
+ {
+ if (*target == XA_COMPOUND_TEXT(d))
+ {
+ *type = *target;
+ }
+ else
+ {
+ *type = XA_STRING;
+ }
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ *value = text;
+ *length = strlen(*value);
+ *format = 8;
+ return True;
+ }
+
+ if (*target == XA_LIST_LENGTH(d))
+ {
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4)
+ {
+ *(long*)*value = 1;
+ }
+ else
+ {
+ long temp = 1;
+ bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
+ }
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ return True;
+ }
+
+ if (*target == XA_LENGTH(d))
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4)
+ {
+ *(long*)*value = strlen(text);
+ }
+ else
+ {
+ long temp = strlen(text);
+ bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
+ }
+ free(text);
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ return True;
+ }
+
+ if (XmuConvertStandardSelection(w, hw->html.selection_time, selection,
+ target, type, value, length, format))
+ {
+ return True;
+ }
+
+ return False;
+}
+
+
+static void
+LoseSelection(w, selection)
+ Widget w;
+ Atom *selection;
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ ClearSelection(hw);
+}
+
+
+static void
+SelectionDone(w, selection, target)
+ Widget w;
+ Atom *selection, *target;
+{
+ /* empty proc so Intrinsics know we want to keep storage */
+}
+
+
+/*
+ *************************************************************************
+ ******************************* PUBLIC FUNCTIONS ************************
+ *************************************************************************
+ */
+
+
+/*
+ * Convenience function to return the text of the HTML document as a plain
+ * ascii text string.
+ * This function allocates memory for the returned string, that it is up
+ * to the user to free.
+ * Extra option flags "pretty" text to be returned.
+ * when pretty is two or larger, Postscript is returned. The font used is
+ * encoded in the pretty parameter:
+ * pretty = 2: Times
+ * pretty = 3: Helvetica
+ * pretty = 4: New century schoolbook
+ * pretty = 5: Lucida Bright
+ */
+char *
+#ifdef _NO_PROTO
+HTMLGetText (w, pretty)
+ Widget w;
+ int pretty;
+#else
+HTMLGetText(Widget w, int pretty)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ char *text;
+ char *tptr, *buf;
+ struct ele_rec *start;
+ struct ele_rec *end;
+
+ text = NULL;
+ start = hw->html.formatted_elements;
+ end = start;
+ while (end != NULL)
+ {
+ end = end->next;
+ }
+
+ if (pretty >= 2)
+ {
+ tptr = ParseTextToPSString(hw, start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width , pretty-2);
+ }
+ else if (pretty)
+ {
+ tptr = ParseTextToPrettyString(hw, start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ tptr = ParseTextToString(start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ if (tptr != NULL)
+ {
+ if (text == NULL)
+ {
+ text = tptr;
+ }
+ else
+ {
+ buf = (char *)malloc(strlen(text) +
+ strlen(tptr) + 1);
+ strcpy(buf, text);
+ strcat(buf, tptr);
+ free(text);
+ free(tptr);
+ text = buf;
+ }
+ }
+ return(text);
+}
+
+
+/*
+ * Convenience function to return the element id of the element
+ * nearest to the x,y coordinates passed in.
+ * If there is no element there, return the first element in the
+ * line we are on. If there we are on no line, either return the
+ * beginning, or the end of the document.
+ */
+int
+#ifdef _NO_PROTO
+HTMLPositionToId(w, x, y)
+ Widget w;
+ int x, y;
+#else
+HTMLPositionToId(Widget w, int x, int y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int i;
+ int epos;
+ struct ele_rec *eptr;
+
+ eptr = LocateElement(hw, x, y, &epos);
+ if (eptr == NULL)
+ {
+ x = x + hw->html.scroll_x;
+ y = y + hw->html.scroll_y;
+ eptr = hw->html.line_array[0];
+ for (i=0; i<hw->html.line_count; i++)
+ {
+ if (hw->html.line_array[i] == NULL)
+ {
+ continue;
+ }
+ else if (hw->html.line_array[i]->y <= y)
+ {
+ eptr = hw->html.line_array[i];
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ /*
+ * 0 means the very top of the document. We put you there for
+ * unfound elements.
+ * We also special case for when the scrollbar is at the
+ * absolute top.
+ */
+ if ((eptr == NULL)||(hw->html.scroll_y == 0))
+ {
+ return(0);
+ }
+ else
+ {
+ return(eptr->ele_id);
+ }
+}
+
+
+/*
+ * Convenience function to return the position of the element
+ * based on the element id passed in.
+ * Function returns 1 on success and fills in x,y pixel values.
+ * If there is no such element, x=0, y=0 and -1 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLIdToPosition(w, element_id, x, y)
+ Widget w;
+ int element_id;
+ int *x, *y;
+#else
+HTMLIdToPosition(Widget w, int element_id, int *x, int *y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ *x = 0;
+ *y = 0;
+ return(-1);
+ }
+ else
+ {
+ *x = eptr->x;
+ *y = eptr->y;
+ return(1);
+ }
+}
+
+
+/*
+ * Convenience function to position the element
+ * based on the element id passed at the top of the viewing area.
+ * A passed in id of 0 means goto the top.
+ */
+void
+#ifdef _NO_PROTO
+HTMLGotoId(w, element_id)
+ Widget w;
+ int element_id;
+#else
+HTMLGotoId(Widget w, int element_id)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+ int newy;
+#ifdef MOTIF
+ int val, size, inc, pageinc;
+#endif
+
+ /*
+ * If we have no scrollbar, just return.
+ */
+ if (hw->html.use_vbar == False)
+ {
+ return;
+ }
+
+ /*
+ * Find the element corrsponding to the id passed in.
+ */
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ /*
+ * No such element, do nothing.
+ */
+ if ((element_id != 0)&&(eptr == NULL))
+ {
+ return;
+ }
+
+ if (element_id == 0)
+ {
+ newy = 0;
+ }
+ else
+ {
+ newy = eptr->y - 2;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ {
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+#ifdef MOTIF
+ XmScrollBarGetValues(hw->html.vbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.vbar, newy, size, inc, pageinc, True);
+ XmScrollBarGetValues(hw->html.hbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.hbar, 0, size, inc, pageinc, True);
+#else
+ ScrollToPos(hw->html.vbar, hw, newy);
+ ScrollToPos(hw->html.hbar, hw, 0);
+ setScrollBar(hw->html.vbar, newy,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif
+}
+
+
+/*
+ * Convenience function to return the position of the anchor
+ * based on the anchor NAME passed.
+ * Function returns 1 on success and fills in x,y pixel values.
+ * If there is no such element, x=0, y=0 and -1 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLAnchorToPosition(w, name, x, y)
+ Widget w;
+ char *name;
+ int *x, *y;
+#else
+HTMLAnchorToPosition(Widget w, char *name, int *x, int *y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->anchorName)&&
+ (strcmp(start->anchorName, name) == 0))
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ *x = 0;
+ *y = 0;
+ return(-1);
+ }
+ else
+ {
+ *x = eptr->x;
+ *y = eptr->y;
+ return(1);
+ }
+}
+
+
+/*
+ * Convenience function to return the element id of the anchor
+ * based on the anchor NAME passed.
+ * Function returns id on success.
+ * If there is no such element, 0 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLAnchorToId(w, name)
+ Widget w;
+ char *name;
+#else
+HTMLAnchorToId(Widget w, char *name)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ /*
+ * Find the passed anchor name
+ */
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->anchorName)&& /* MF023 */
+ ((strcmp(start->anchorName, name) == 0) ||
+ (*name == '#' && strcmp(start->anchorName, &(name[1])) == 0)) ) {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ return(0);
+ }
+ else
+ {
+ return(eptr->ele_id);
+ }
+}
+
+
+/*
+ * Convenience function to return the HREFs of all active anchors in the
+ * document.
+ * Function returns an array of strings and fills num_hrefs passed.
+ * If there are no HREFs NULL returned.
+ */
+char **
+#ifdef _NO_PROTO
+HTMLGetHRefs(w, num_hrefs)
+ Widget w;
+ int *num_hrefs;
+#else
+HTMLGetHRefs(Widget w, int *num_hrefs)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int cnt;
+ struct ele_rec *start;
+ struct ele_rec *list;
+ struct ele_rec *eptr;
+ char **harray;
+
+ list = NULL;
+ cnt = 0;
+ /*
+ * Construct a linked list of all the diffeent hrefs, counting
+ * then as we go.
+ */
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ /*
+ * This one has an HREF
+ */
+ if (start->anchorHRef != NULL)
+ {
+ /*
+ * Check to see if we already have
+ * this HREF in our list.
+ */
+ eptr = list;
+ while (eptr != NULL)
+ {
+ if (strcmp(eptr->anchorHRef,
+ start->anchorHRef) == 0)
+ {
+ break;
+ }
+ eptr = eptr->next;
+ }
+ /*
+ * This HREF is not, in our list. Add it.
+ * That is, if it's not an internal reference.
+ */
+ if ((eptr == NULL)&&(start->internal == False))
+ {
+ eptr = (struct ele_rec *)
+ malloc(sizeof(struct ele_rec));
+ eptr->anchorHRef = start->anchorHRef;
+ eptr->next = list;
+ list = eptr;
+ cnt++;
+ }
+ }
+ start = start->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_hrefs = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_hrefs = cnt;
+ harray = (char **)malloc(sizeof(char *) * cnt);
+ eptr = list;
+ cnt--;
+ while (eptr != NULL)
+ {
+ harray[cnt] = (char *)
+ malloc(strlen(eptr->anchorHRef) + 1);
+ strcpy(harray[cnt], eptr->anchorHRef);
+ start = eptr;
+ eptr = eptr->next;
+ free((char *)start);
+ cnt--;
+ }
+ return(harray);
+ }
+}
+
+
+/*
+ * Convenience function to return the SRCs of all images in the
+ * document.
+ * Function returns an array of strings and fills num_srcs passed.
+ * If there are no SRCs NULL returned.
+ */
+char **
+#ifdef _NO_PROTO
+HTMLGetImageSrcs(w, num_srcs)
+ Widget w;
+ int *num_srcs;
+#else
+HTMLGetImageSrcs(Widget w, int *num_srcs)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct mark_up *mptr;
+ int cnt;
+ char *tptr;
+ char **harray;
+
+ cnt = 0;
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_IMAGE)
+ {
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
+ if ((tptr != NULL)&&(*tptr != '\0'))
+ {
+ cnt++;
+ free(tptr);
+ }
+ }
+ mptr = mptr->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_srcs = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_srcs = cnt;
+ harray = (char **)malloc(sizeof(char *) * cnt);
+ mptr = hw->html.html_objects;
+ cnt = 0;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_IMAGE)
+ {
+ tptr = ParseMarkTag(mptr->start,MT_IMAGE,"SRC");
+ if ((tptr != NULL)&&(*tptr != '\0'))
+ {
+ harray[cnt] = tptr;
+ cnt++;
+ }
+ }
+ mptr = mptr->next;
+ }
+ return(harray);
+ }
+}
+
+
+/*
+ * Convenience function to return the link information
+ * for all the <LINK> tags in the document.
+ * Function returns an array of LinkInfo structures and fills
+ * num_links passed.
+ * If there are no LINKs NULL returned.
+ */
+LinkInfo *
+#ifdef _NO_PROTO
+HTMLGetLinks(w, num_links)
+ Widget w;
+ int *num_links;
+#else
+HTMLGetLinks(Widget w, int *num_links)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct mark_up *mptr;
+ int cnt;
+ char *tptr;
+ LinkInfo *larray;
+
+ cnt = 0;
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ cnt++;
+ }
+ mptr = mptr->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_links = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_links = cnt;
+ larray = (LinkInfo *)malloc(sizeof(LinkInfo) * cnt);
+ mptr = hw->html.html_objects;
+ cnt = 0;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ tptr = ParseMarkTag(mptr->start,
+ MT_BASE, "HREF");
+ larray[cnt].href = tptr;
+ tptr = ParseMarkTag(mptr->start,
+ MT_BASE, "ROLE");
+ larray[cnt].role = tptr;
+ cnt++;
+ }
+ mptr = mptr->next;
+ }
+ return(larray);
+ }
+}
+
+
+
+void *
+#ifdef _NO_PROTO
+HTMLGetWidgetInfo(w)
+ Widget w;
+#else
+HTMLGetWidgetInfo(Widget w)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ return((void *)hw->html.widget_list);
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLFreeImageInfo(w)
+ Widget w;
+#else
+HTMLFreeImageInfo(Widget w)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ FreeColors(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)));
+ FreeImages(hw);
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLFreeWidgetInfo(ptr)
+ void *ptr;
+#else
+HTMLFreeWidgetInfo(void *ptr)
+#endif
+{
+ WidgetInfo *wptr = (WidgetInfo *)ptr;
+ WidgetInfo *tptr;
+
+ while (wptr != NULL)
+ {
+ tptr = wptr;
+ wptr = wptr->next;
+ if (tptr->w != NULL)
+ {
+ /*
+ * This is REALLY DUMB, but X generates an expose event
+ * for the destruction of the Widgte, even if it isn't
+ * mapped at the time it is destroyed.
+ * So I move the invisible widget to -1000,-1000
+ * before destroying it, to avoid a visible flash.
+ */
+ XtMoveWidget(tptr->w, -1000, -1000);
+ XtDestroyWidget(tptr->w);
+ }
+ if (tptr->name != NULL)
+ {
+ free(tptr->name);
+ }
+ if ((tptr->value != NULL)&&(tptr->type != W_OPTIONMENU))
+ {
+ free(tptr->value);
+ }
+ free((char *)tptr);
+ }
+}
+
+
+/*
+ * Convenience function to redraw all active anchors in the
+ * document.
+ * Can also pass a new predicate function to check visited
+ * anchors. If NULL passed for function, uses default predicate
+ * function.
+ */
+void
+#ifdef _NO_PROTO
+HTMLRetestAnchors(w, testFunc, client_data)
+ Widget w;
+ visitTestProc testFunc;
+ XtPointer client_data;
+#else
+HTMLRetestAnchors(Widget w, visitTestProc testFunc, XtPointer client_data)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ int stat = 0;
+
+ if (testFunc == NULL)
+ {
+ testFunc = (visitTestProc)hw->html.previously_visited_test;
+ client_data = hw->html.vt_client_data;
+ }
+
+ /*
+ * Search all elements
+ */
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->internal == True)||
+ (start->anchorHRef == NULL))
+ {
+ start = start->next;
+ continue;
+ }
+
+ if (testFunc != NULL)
+ {
+ if ((stat=(*testFunc)(hw, client_data, start->anchorHRef)))
+ {
+ start->fg = hw->html.visitedAnchor_fg;
+ start->underline_number =
+ hw->html.num_visitedAnchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_visitedAnchor_lines;
+ }
+ else
+ {
+ start->fg = hw->html.anchor_fg;
+ start->underline_number =
+ hw->html.num_anchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_anchor_lines;
+ }
+ }
+ else
+ {
+ start->fg = hw->html.anchor_fg;
+ start->underline_number =
+ hw->html.num_anchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_anchor_lines;
+ }
+
+ /*
+ * Since the element may have changed, redraw it
+ */
+ if (stat) {
+ switch(start->type)
+ {
+ case E_TEXT:
+ TextRefresh(hw, start,
+ 0, (start->edata_len - 2));
+ break;
+ case E_IMAGE:
+ ImageRefresh(hw, start);
+ break;
+ case E_BULLET:
+ BulletRefresh(hw, start);
+ break;
+ case E_LINEFEED:
+ LinefeedRefresh(hw, start);
+ break;
+ }
+ }
+
+ start = start->next;
+ }
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLClearSelection (w)
+ Widget w;
+#else
+HTMLClearSelection(Widget w)
+#endif
+{
+ LoseSelection (w, NULL);
+}
+
+
+/*
+ * Set the current selection based on the ElementRefs passed in.
+ * Both refs must be valid.
+ */
+void
+#ifdef _NO_PROTO
+HTMLSetSelection (w, start, end)
+ Widget w;
+ ElementRef *start;
+ ElementRef *end;
+#else
+HTMLSetSelection(Widget w, ElementRef *start, ElementRef *end)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int found;
+ struct ele_rec *eptr;
+ struct ele_rec *e_start;
+ struct ele_rec *e_end;
+ int start_pos, end_pos;
+ Atom *atoms;
+ int i, buffer;
+ char *text;
+ char *params[2];
+
+ /*
+ * If the starting position is not valid, fail the selection
+ */
+ if ((start->id > 0)&&(start->pos >= 0))
+ {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL)
+ {
+ if (eptr->ele_id == start->id)
+ {
+ e_start = eptr;
+ start_pos = start->pos;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ if (!found)
+ {
+ return;
+ }
+ }
+
+ /*
+ * If the ending position is not valid, fail the selection
+ */
+ if ((end->id > 0)&&(end->pos >= 0))
+ {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL)
+ {
+ if (eptr->ele_id == end->id)
+ {
+ e_end = eptr;
+ end_pos = end->pos;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ if (!found)
+ {
+ return;
+ }
+ }
+
+ LoseSelection (w, NULL);
+
+ /*
+ * We expect the ElementRefs came from HTMLSearchText, so we know
+ * that the end_pos is one past what we want to select.
+ */
+ end_pos = end_pos - 1;
+
+ /*
+ * Sanify the position data
+ */
+ if ((start_pos > 0)&&(start_pos >= e_start->edata_len - 1))
+ {
+ start_pos = e_start->edata_len - 2;
+ }
+ if ((end_pos > 0)&&(end_pos >= e_end->edata_len - 1))
+ {
+ end_pos = e_end->edata_len - 2;
+ }
+
+ hw->html.select_start = e_start;
+ hw->html.sel_start_pos = start_pos;
+ hw->html.select_end = e_end;
+ hw->html.sel_end_pos = end_pos;
+ SetSelection(hw);
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+
+ /*
+ * Do all the gunk from the end of the ExtendEnd function
+ */
+ params[0] = "PRIMARY";
+ params[1] = "CUT_BUFFER0";
+ atoms = (Atom *)malloc(2 * sizeof(Atom));
+ if (atoms == NULL)
+ {
+ fprintf(stderr, "cannot allocate atom list\n");
+ return;
+ }
+ XmuInternStrings(XtDisplay((Widget)hw), params, 2, atoms);
+ hw->html.selection_time = CurrentTime;
+ for (i=0; i< 2; i++)
+ {
+ switch (atoms[i])
+ {
+ case XA_CUT_BUFFER0: buffer = 0; break;
+ case XA_CUT_BUFFER1: buffer = 1; break;
+ case XA_CUT_BUFFER2: buffer = 2; break;
+ case XA_CUT_BUFFER3: buffer = 3; break;
+ case XA_CUT_BUFFER4: buffer = 4; break;
+ case XA_CUT_BUFFER5: buffer = 5; break;
+ case XA_CUT_BUFFER6: buffer = 6; break;
+ case XA_CUT_BUFFER7: buffer = 7; break;
+ default: buffer = -1; break;
+ }
+ if (buffer >= 0)
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ XStoreBuffer(XtDisplay((Widget)hw),
+ text, strlen(text), buffer);
+ free(text);
+ }
+ else
+ {
+ XtOwnSelection((Widget)hw, atoms[i], CurrentTime,
+ (XtConvertSelectionProc )ConvertSelection,
+ (XtLoseSelectionProc )LoseSelection,
+ (XtSelectionDoneProc )SelectionDone);
+ }
+ }
+ free((char *)atoms);
+}
+
+
+/*
+ * Convenience function to return the text of the HTML document as a single
+ * white space separated string, with pointers to the various start and
+ * end points of selections.
+ * This function allocates memory for the returned string, that it is up
+ * to the user to free.
+ */
+char *
+#ifdef _NO_PROTO
+HTMLGetTextAndSelection (w, startp, endp, insertp)
+ Widget w;
+ char **startp;
+ char **endp;
+ char **insertp;
+#else
+HTMLGetTextAndSelection(Widget w, char **startp, char **endp, char **insertp)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int length;
+ char *text;
+ char *tptr;
+ struct ele_rec *eptr;
+ struct ele_rec *sel_start;
+ struct ele_rec *sel_end;
+ struct ele_rec *insert_start;
+ int start_pos, end_pos, insert_pos;
+
+ if (SwapElements(hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos))
+ {
+ sel_end = hw->html.select_start;
+ end_pos = hw->html.sel_start_pos;
+ sel_start = hw->html.select_end;
+ start_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ sel_start = hw->html.select_start;
+ start_pos = hw->html.sel_start_pos;
+ sel_end = hw->html.select_end;
+ end_pos = hw->html.sel_end_pos;
+ }
+
+ insert_start = hw->html.new_start;
+ insert_pos = hw->html.new_start_pos;
+ *startp = NULL;
+ *endp = NULL;
+ *insertp = NULL;
+
+ length = 0;
+
+ eptr = hw->html.formatted_elements;
+ while (eptr != NULL)
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ length = length + eptr->edata_len - 1;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ length = length + 1;
+ }
+ eptr = eptr->next;
+ }
+
+ text = (char *)malloc(length + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "No space for return string\n");
+ return(NULL);
+ }
+ strcpy(text, "");
+
+ tptr = text;
+
+ eptr = hw->html.formatted_elements;
+ while (eptr != NULL)
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ if (eptr == sel_start)
+ {
+ *startp = (char *)(tptr + start_pos);
+ }
+
+ if (eptr == sel_end)
+ {
+ *endp = (char *)(tptr + end_pos);
+ }
+
+ if (eptr == insert_start)
+ {
+ *insertp = (char *)(tptr + insert_pos);
+ }
+
+ strcat(text, (char *)eptr->edata);
+ tptr = tptr + eptr->edata_len - 1;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ if (eptr == sel_start)
+ {
+ *startp = tptr;
+ }
+
+ if (eptr == sel_end)
+ {
+ *endp = tptr;
+ }
+
+ if (eptr == insert_start)
+ {
+ *insertp = tptr;
+ }
+
+ strcat(text, " ");
+ tptr = tptr + 1;
+ }
+ eptr = eptr->next;
+ }
+ return(text);
+}
+
+
+/*
+ * Convenience function to set the raw text into the widget.
+ * Forces a reparse and a reformat.
+ * If any pointer is passed in as NULL that text is unchanged,
+ * if a pointer points to an empty string, that text is set to NULL;
+ * Also pass an element ID to set the view area to that section of the new
+ * text. Finally pass an anchor NAME to set position of the new text
+ * to that anchor.
+ */
+void
+#ifdef _NO_PROTO
+HTMLSetText (w, text, header_text, footer_text, element_id, target_anchor, ptr)
+ Widget w;
+ char *text;
+ char *header_text;
+ char *footer_text;
+ int element_id;
+ char *target_anchor;
+ void *ptr;
+#else
+HTMLSetText(Widget w, char *text, char *header_text, char *footer_text, int element_id, char *target_anchor, void *ptr)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ WidgetInfo *wptr = (WidgetInfo *)ptr;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+ int newy;
+
+ if ((text == NULL)&&(header_text == NULL)&&(footer_text == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Free up the old visited href list.
+ */
+ FreeHRefs(hw->html.my_visited_hrefs);
+ hw->html.my_visited_hrefs = NULL;
+
+ /*
+ * Free up the old visited delayed images list.
+ */
+ FreeDelayedImages(hw->html.my_delayed_images);
+ hw->html.my_delayed_images = NULL;
+
+ /*
+ * Hide any old widgets
+ */
+ HideWidgets(hw);
+ hw->html.widget_list = wptr;
+ hw->html.form_list = NULL;
+
+ if (text != NULL)
+ {
+ if (*text == '\0')
+ {
+ text = NULL;
+ }
+ hw->html.raw_text = text;
+
+ /*
+ * Free any old colors and pixmaps
+ */
+ FreeColors(XtDisplay(hw),DefaultColormapOfScreen(XtScreen(hw)));
+ FreeImages(hw);
+
+ /*
+ * Parse the raw text with the HTML parser
+ */
+ hw->html.html_objects = HTMLParse(hw->html.html_objects,
+ hw->html.raw_text);
+ CallLinkCallbacks(hw);
+ }
+ if (header_text != NULL)
+ {
+ if (*header_text == '\0')
+ {
+ header_text = NULL;
+ }
+ hw->html.header_text = header_text;
+
+ /*
+ * Parse the header text with the HTML parser
+ */
+ hw->html.html_header_objects =
+ HTMLParse(hw->html.html_header_objects,
+ hw->html.header_text);
+ }
+ if (footer_text != NULL)
+ {
+ if (*footer_text == '\0')
+ {
+ footer_text = NULL;
+ }
+ hw->html.footer_text = footer_text;
+
+ /*
+ * Parse the footer text with the HTML parser
+ */
+ hw->html.html_footer_objects =
+ HTMLParse(hw->html.html_footer_objects,
+ hw->html.footer_text);
+ }
+
+ /*
+ * Reformat the new text
+ */
+ hw->html.max_pre_width = DocumentWidth(hw, hw->html.html_objects);
+ ReformatWindow(hw);
+
+ /*
+ * If a target anchor is passed, override the element id
+ * with the id of that anchor.
+ */
+ if (target_anchor != NULL)
+ {
+ int id;
+
+ id = HTMLAnchorToId(w, target_anchor);
+ if (id != 0)
+ {
+ element_id = id;
+ }
+ }
+
+ /*
+ * Position text at id specified, or at top if no position
+ * specified.
+ * Find the element corrsponding to the id passed in.
+ */
+ eptr = NULL;
+ if (element_id != 0)
+ {
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+ }
+ if (eptr == NULL)
+ {
+ newy = 0;
+ }
+ else
+ {
+ newy = eptr->y - 2;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ {
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ hw->html.scroll_x = 0;
+ hw->html.scroll_y = newy;
+#ifdef DEBUG
+fprintf (stderr, "calling in HTMLSetText\n");
+#endif
+ ConfigScrollBars(hw);
+ ScrollWidgets(hw);
+
+ /*
+ * Display the new text
+ */
+ ViewClearAndRefresh(hw);
+
+ /*
+ * Clear any previous selection
+ */
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.active_anchor = NULL;
+
+ hw->html.cached_tracked_ele = NULL;
+}
+
+
+/*
+ * To use faster TOLOWER as set up in HTMLparse.c
+ */
+#ifdef NOT_ASCII
+#define TOLOWER(x) (tolower(x))
+#else
+extern char map_table[];
+#define TOLOWER(x) (map_table[x])
+#endif /* NOT_ASCII */
+
+
+/*
+ * Convenience function to search the text of the HTML document as a single
+ * white space separated string. Linefeeds are converted into spaces.
+ *
+ * Takes a pattern, pointers to the start and end blocks to store the
+ * start and end of the match into. Start is also used as the location to
+ * start the search from for incremental searching. If start is an invalid
+ * position (id = 0). Default start is the beginning of the document for
+ * forward searching, and the end of the document for backwards searching.
+ * The backward and caseless parameters I hope are self-explanatory.
+ *
+ * returns 1 on success
+ * (and the start and end positions of the match).
+ * returns -1 otherwise (and start and end are unchanged).
+ */
+int
+#ifdef _NO_PROTO
+HTMLSearchText (w, pattern, m_start, m_end, backward, caseless)
+ Widget w;
+ char *pattern;
+ ElementRef *m_start;
+ ElementRef *m_end;
+ int backward;
+ int caseless;
+#else
+HTMLSearchText (Widget w, char *pattern, ElementRef *m_start, ElementRef *m_end,
+ int backward, int caseless)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int found, equal;
+ char *match;
+ char *tptr;
+ char *mptr;
+ char cval;
+ struct ele_rec *eptr;
+ int s_pos;
+ struct ele_rec *s_eptr;
+ ElementRef s_ref, e_ref;
+ ElementRef *start, *end;
+
+ /*
+ * If bad parameters are passed, just fail the search
+ */
+ if ((pattern == NULL)||(*pattern == '\0')||
+ (m_start == NULL)||(m_end == NULL)) {
+ return(-1);
+ }
+
+ /*
+ * If we are caseless, make a lower case copy of the pattern to
+ * match to use in compares.
+ *
+ * remember to free this before returning
+ */
+ if (caseless) {
+ match = (char *)malloc(strlen(pattern) + 1);
+ tptr = pattern;
+ mptr = match;
+ while (*tptr != '\0') {
+ *mptr = (char)TOLOWER((int)*tptr);
+ mptr++;
+ tptr++;
+ }
+ *mptr = '\0';
+ } else {
+ match = pattern;
+ }
+
+ /*
+ * Slimy coding. I later decided I didn't want to change start and
+ * end if the search failed. Rather than changing all the code,
+ * I just copy it into locals here, and copy it out again if a match
+ * is found.
+ */
+ start = &s_ref;
+ end = &e_ref;
+ start->id = m_start->id;
+ start->pos = m_start->pos;
+ end->id = m_end->id;
+ end->pos = m_end->pos;
+
+ /*
+ * Find the user specified start position.
+ */
+ if (start->id > 0) {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL) {
+/* if (eptr->ele_id > start->id) {*/ /* MF031 */
+ if ((!backward && eptr->ele_id > start->id) ||
+ ( backward && eptr->ele_id == start->id)) {
+ s_eptr = eptr;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ /*
+ * Bad start position, fail them out.
+ */
+ if (!found) {
+ if (caseless) {
+ free(match);
+ }
+ return(-1);
+ }
+ /*
+ * Sanify the start position
+ */
+ s_pos = start->pos;
+ if (s_pos >= s_eptr->edata_len - 1) {
+ s_pos = s_eptr->edata_len - 2;
+ }
+ if (s_pos < 0) {
+ s_pos = 0;
+ }
+
+ } else {
+ /*
+ * Default search starts at end for backward, and
+ * beginning for forwards.
+ */
+ if (backward) {
+ s_eptr = hw->html.formatted_elements;
+ while (s_eptr->next != NULL) {
+ s_eptr = s_eptr->next;
+ }
+ s_pos = s_eptr->edata_len - 2;
+ } else {
+ s_eptr = hw->html.formatted_elements;
+ s_pos = 0;
+ }
+ }
+
+ if (backward) {
+ char *mend;
+
+ /*
+ * Save the end of match here for easy end to start searching
+ */
+ mend = match;
+ while (*mend != '\0') {
+ mend++;
+ }
+ if (mend > match) {
+ mend--;
+ }
+ found = 0;
+ equal = 0;
+ mptr = mend;
+
+ if (s_eptr != NULL) {
+ eptr = s_eptr;
+ } else {
+ eptr = hw->html.formatted_elements;
+ while (eptr->next != NULL) {
+ eptr = eptr->next;
+ }
+ }
+
+ while (eptr != NULL) {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True) {
+ eptr = eptr->prev;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT) {
+ tptr = (char *)(eptr->edata + eptr->edata_len - 2);
+ if (eptr == s_eptr) {
+ tptr = (char *)(eptr->edata + s_pos);
+ }
+ while (tptr >= eptr->edata) {
+ if (equal) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((mptr >= match)&&
+ (tptr >= eptr->edata)&&
+ (cval == *mptr))
+ {
+ tptr--;
+ mptr--;
+ if (tptr >= eptr->edata) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ }
+ if (mptr < match) {
+ found = 1;
+ start->id = eptr->ele_id;
+ start->pos = (int)
+ (tptr - eptr->edata + 1);
+ break;
+ } else if (tptr < eptr->edata) {
+ break;
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = mend;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((tptr >= eptr->edata)&&
+ (cval != *mptr))
+ {
+ tptr--;
+ if (tptr >= eptr->edata) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ }
+ if ((tptr >= eptr->edata)&&
+ (cval == *mptr))
+ {
+ equal = 1;
+ end->id = eptr->ele_id;
+ end->pos = (int)
+ (tptr - eptr->edata + 1);
+ }
+ }
+ }
+ }
+ /*
+ * Linefeeds match to single space characters.
+ */
+ else if (eptr->type == E_LINEFEED) {
+ if (equal) {
+ if (*mptr == ' ') {
+ mptr--;
+ if (mptr < match) {
+ found = 1;
+ start->id =eptr->ele_id;
+ start->pos = 0;
+ }
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = mend;
+ if (*mptr == ' ') {
+ equal = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ mptr--;
+ if (mptr < match) {
+ found = 1;
+ start->id =eptr->ele_id;
+ start->pos = 0;
+ }
+ }
+ }
+ }
+ if (found) {
+ break;
+ }
+ eptr = eptr->prev;
+ }
+ }
+ else /* forward */
+ {
+ found = 0;
+ equal = 0;
+ mptr = match;
+
+ if (s_eptr != NULL) {
+ eptr = s_eptr;
+ } else {
+ eptr = hw->html.formatted_elements;
+ }
+
+ while (eptr != NULL) {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True) {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT) {
+ tptr = eptr->edata;
+ if (eptr == s_eptr) {
+ tptr = (char *)(tptr + s_pos);
+ }
+ while (*tptr != '\0') {
+ if (equal) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((*mptr != '\0')&&
+ (cval == *mptr))
+ {
+ tptr++;
+ mptr++;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = (int)
+ (tptr - eptr->edata);
+ break;
+ } else if (*tptr == '\0') {
+ break;
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = match;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((*tptr != '\0')&&
+ (cval != *mptr))
+ {
+ tptr++;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ if (cval == *mptr) {
+ equal = 1;
+ start->id = eptr->ele_id;
+ start->pos = (int)
+ (tptr - eptr->edata);
+ }
+ }
+ }
+ }
+ else if (eptr->type == E_LINEFEED) {
+ if (equal) {
+ if (*mptr == ' ') {
+ mptr++;
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ }
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = match;
+ if (*mptr == ' ') {
+ equal = 1;
+ start->id = eptr->ele_id;
+ start->pos = 0;
+ mptr++;
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ }
+ }
+ }
+ }
+ if (found) {
+ break;
+ }
+ eptr = eptr->next;
+ }
+ }
+
+ if (found) {
+ m_start->id = start->id;
+ m_start->pos = start->pos;
+ m_end->id = end->id;
+ m_end->pos = end->pos;
+ }
+
+ if (caseless) {
+ free(match);
+ }
+
+ if (found) {
+ return(1);
+ } else {
+ return(-1);
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/HTML.h b/vendor/x11iraf/obm/ObmW/HTML.h
new file mode 100644
index 00000000..08fbf10e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTML.h
@@ -0,0 +1,491 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#ifndef HTML_H
+#define HTML_H
+
+#ifdef MOTIF
+#include <Xm/Xm.h>
+#if (XmVERSION == 1)&&(XmREVISION >= 2)
+#define MOTIF1_2
+#endif
+#else
+#include <X11/Intrinsic.h>
+#include <X11/Constraint.h>
+#endif /* MOTIF */
+#include <X11/StringDefs.h>
+
+
+
+typedef int (*visitTestProc)();
+typedef void (*pointerTrackProc)();
+
+typedef struct ele_ref_rec {
+ int id, pos;
+} ElementRef;
+
+typedef struct link_rec {
+ char *href;
+ char *role;
+} LinkInfo;
+
+/*
+ * Public functions
+ */
+#ifdef _NO_PROTO
+extern char *HTMLGetText ();
+extern char *HTMLGetTextAndSelection ();
+extern char **HTMLGetHRefs ();
+extern char **HTMLGetImageSrcs ();
+extern void *HTMLGetWidgetInfo ();
+extern void HTMLFreeWidgetInfo ();
+extern void HTMLFreeImageInfo ();
+extern LinkInfo *HTMLGetLinks ();
+extern int HTMLPositionToId ();
+extern int HTMLIdToPosition ();
+extern int HTMLAnchorToPosition ();
+extern int HTMLAnchorToId ();
+extern void HTMLGotoId ();
+extern void HTMLRetestAnchors ();
+extern void HTMLClearSelection ();
+extern void HTMLSetSelection ();
+extern void HTMLSetText ();
+extern int HTMLSearchText ();
+#else
+extern char *HTMLGetText (Widget w, int pretty);
+extern char *HTMLGetTextAndSelection (Widget w, char **startp, char **endp,
+ char **insertp);
+extern char **HTMLGetHRefs (Widget w, int *num_hrefs);
+extern char **HTMLGetImageSrcs (Widget w, int *num_srcs);
+extern void *HTMLGetWidgetInfo (Widget w);
+extern void HTMLFreeWidgetInfo (void *ptr);
+extern void HTMLFreeImageInfo (Widget w);
+extern LinkInfo *HTMLGetLinks (Widget w, int *num_links);
+extern int HTMLPositionToId(Widget w, int x, int y);
+extern int HTMLIdToPosition(Widget w, int element_id, int *x, int *y);
+extern int HTMLAnchorToPosition(Widget w, char *name, int *x, int *y);
+extern int HTMLAnchorToId(Widget w, char *name);
+extern void HTMLGotoId(Widget w, int element_id);
+extern void HTMLRetestAnchors(Widget w, visitTestProc testFunc,
+ XtPointer client_data);
+extern void HTMLClearSelection (Widget w);
+extern void HTMLSetSelection (Widget w, ElementRef *start, ElementRef *end);
+extern void HTMLSetText (Widget w, char *text, char *header_text,
+ char *footer_text, int element_id,
+ char *target_anchor, void *ptr);
+extern int HTMLSearchText (Widget w, char *pattern,
+ ElementRef *m_start, ElementRef *m_end, int backward, int caseless);
+#endif /* _NO_PROTO */
+
+
+/*
+ * Public Structures
+ */
+typedef struct acall_rec {
+ XEvent *event;
+ int element_id;
+ char *text;
+ char *href;
+} WbAnchorCallbackData;
+
+
+typedef struct fcall_rec {
+ XEvent *event;
+ char *href;
+ char *method;
+ char *enctype;
+ char *enc_entity;
+ int attribute_count;
+ char **attribute_names;
+ char **attribute_values;
+} WbFormCallbackData;
+
+
+typedef struct form_rec {
+ Widget hw;
+ char *action;
+ char *method;
+ char *enctype;
+ char *enc_entity;
+ int start, end;
+ struct form_rec *next;
+} FormInfo;
+
+
+typedef struct image_rec {
+ int ismap;
+ FormInfo *fptr;
+ int internal;
+ int delayed;
+ int fetched;
+ int width, height;
+ int num_colors;
+ int *reds;
+ int *greens;
+ int *blues;
+ unsigned char *image_data;
+ Pixmap image;
+ char *text;
+} ImageInfo;
+
+
+typedef struct wid_rec {
+ Widget w;
+ int type;
+ int id;
+ int x, y;
+ int width, height;
+ char *name;
+ char *value;
+ char *password;
+ char **mapping;
+ Boolean checked;
+ Boolean mapped;
+ struct wid_rec *next;
+} WidgetInfo;
+
+typedef struct sel_rec {
+ Widget hw;
+ struct mark_up *mptr;
+ int is_value;
+ char *retval_buf;
+ char *option_buf;
+ char **returns;
+ char **options;
+ int option_cnt;
+ char **value;
+ int value_cnt;
+} SelectInfo;
+
+
+typedef ImageInfo *(*resolveImageProc)();
+
+
+/*
+ * defines and structures used for the formatted element list
+ */
+
+#define E_TEXT 1
+#define E_BULLET 2
+#define E_LINEFEED 3
+#define E_IMAGE 4
+#define E_WIDGET 5
+#define E_HRULE 6
+
+struct ele_rec {
+ int type;
+ ImageInfo *pic_data;
+ WidgetInfo *widget_data;
+ XFontStruct *font;
+ int alignment;
+ Boolean internal;
+ Boolean selected;
+ int indent_level;
+ int start_pos, end_pos;
+ int x, y;
+ int y_offset;
+ int width;
+ int line_number;
+ int line_height;
+ int ele_id;
+ int underline_number;
+ Boolean dashed_underline;
+ Boolean strikeout;
+ unsigned long fg;
+ unsigned long bg;
+ char *anchorName;
+ char *anchorHRef;
+ char *edata;
+ int edata_len;
+ struct ele_rec *next;
+ struct ele_rec *prev;
+};
+
+struct ref_rec {
+ char *anchorHRef;
+ struct ref_rec *next;
+};
+
+struct delay_rec {
+ char *src;
+ struct delay_rec *next;
+};
+
+
+/*
+ * defines and structures used for the HTML parser, and the
+ * parsed object list.
+ */
+
+/* Mark types */
+#define M_UNKNOWN -1
+#define M_NONE 0
+#define M_TITLE 1
+#define M_HEADER_1 2
+#define M_HEADER_2 3
+#define M_HEADER_3 4
+#define M_HEADER_4 5
+#define M_HEADER_5 6
+#define M_HEADER_6 7
+#define M_ANCHOR 8
+#define M_PARAGRAPH 9
+#define M_ADDRESS 10
+#define M_PLAIN_TEXT 11
+#define M_UNUM_LIST 12
+#define M_NUM_LIST 13
+#define M_LIST_ITEM 14
+#define M_DESC_LIST 15
+#define M_DESC_TITLE 16
+#define M_DESC_TEXT 17
+#define M_PREFORMAT 18
+#define M_PLAIN_FILE 19
+#define M_LISTING_TEXT 20
+#define M_INDEX 21
+#define M_MENU 22
+#define M_DIRECTORY 23
+#define M_IMAGE 24
+#define M_FIXED 25
+#define M_BOLD 26
+#define M_ITALIC 27
+#define M_EMPHASIZED 28
+#define M_STRONG 29
+#define M_CODE 30
+#define M_SAMPLE 31
+#define M_KEYBOARD 32
+#define M_VARIABLE 33
+#define M_CITATION 34
+#define M_BLOCKQUOTE 35
+#define M_STRIKEOUT 36
+#define M_INPUT 37
+#define M_FORM 38
+#define M_HRULE 39
+#define M_LINEBREAK 40
+#define M_BASE 41
+#define M_SELECT 42
+#define M_OPTION 43
+#define M_TEXTAREA 44
+
+/* syntax of Mark types */
+#define MT_TITLE "title"
+#define MT_HEADER_1 "h1"
+#define MT_HEADER_2 "h2"
+#define MT_HEADER_3 "h3"
+#define MT_HEADER_4 "h4"
+#define MT_HEADER_5 "h5"
+#define MT_HEADER_6 "h6"
+#define MT_ANCHOR "a"
+#define MT_PARAGRAPH "p"
+#define MT_ADDRESS "address"
+#define MT_PLAIN_TEXT "xmp"
+#define MT_UNUM_LIST "ul"
+#define MT_NUM_LIST "ol"
+#define MT_LIST_ITEM "li"
+#define MT_DESC_LIST "dl"
+#define MT_DESC_TITLE "dt"
+#define MT_DESC_TEXT "dd"
+#define MT_PREFORMAT "pre"
+#define MT_PLAIN_FILE "plaintext"
+#define MT_LISTING_TEXT "listing"
+#define MT_INDEX "isindex"
+#define MT_MENU "menu"
+#define MT_DIRECTORY "dir"
+#define MT_IMAGE "img"
+#define MT_FIXED "tt"
+#define MT_BOLD "b"
+#define MT_ITALIC "i"
+#define MT_EMPHASIZED "em"
+#define MT_STRONG "strong"
+#define MT_CODE "code"
+#define MT_SAMPLE "samp"
+#define MT_KEYBOARD "kbd"
+#define MT_VARIABLE "var"
+#define MT_CITATION "cite"
+#define MT_BLOCKQUOTE "blockquote"
+#define MT_STRIKEOUT "strike"
+#define MT_INPUT "input"
+#define MT_FORM "form"
+#define MT_HRULE "hr"
+#define MT_LINEBREAK "br"
+#define MT_BASE "base"
+#define MT_SELECT "select"
+#define MT_OPTION "option"
+#define MT_TEXTAREA "textarea"
+
+
+/* anchor tags */
+#define AT_NAME "name"
+#define AT_HREF "href"
+
+
+struct mark_up {
+ int type;
+ int is_end;
+ char *start;
+ char *text;
+ char *end;
+ struct mark_up *next;
+};
+
+
+/*
+ * New resource names
+ */
+#define WbNmarginWidth "marginWidth"
+#define WbNmarginHeight "marginHeight"
+#define WbNtext "text"
+#define WbNheaderText "headerText"
+#define WbNfooterText "footerText"
+#define WbNtitleText "titleText"
+#define WbNanchorUnderlines "anchorUnderlines"
+#define WbNvisitedAnchorUnderlines "visitedAnchorUnderlines"
+#define WbNdashedAnchorUnderlines "dashedAnchorUnderlines"
+#define WbNdashedVisitedAnchorUnderlines "dashedVisitedAnchorUnderlines"
+#define WbNanchorColor "anchorColor"
+#define WbNvisitedAnchorColor "visitedAnchorColor"
+#define WbNactiveAnchorFG "activeAnchorFG"
+#define WbNactiveAnchorBG "activeAnchorBG"
+#define WbNfancySelections "fancySelections"
+#define WbNimageBorders "imageBorders"
+#define WbNdelayImageLoads "delayImageLoads"
+#define WbNisIndex "isIndex"
+#define WbNitalicFont "italicFont"
+#define WbNboldFont "boldFont"
+#define WbNfixedFont "fixedFont"
+#define WbNfixedboldFont "fixedboldFont"
+#define WbNfixeditalicFont "fixeditalicFont"
+#define WbNheader1Font "header1Font"
+#define WbNheader2Font "header2Font"
+#define WbNheader3Font "header3Font"
+#define WbNheader4Font "header4Font"
+#define WbNheader5Font "header5Font"
+#define WbNheader6Font "header6Font"
+#define WbNaddressFont "addressFont"
+#define WbNplainFont "plainFont"
+#define WbNplainboldFont "plainboldFont"
+#define WbNplainitalicFont "plainitalicFont"
+#define WbNlistingFont "listingFont"
+#define WbNanchorCallback "anchorCallback"
+#define WbNlinkCallback "linkCallback"
+#define WbNsubmitFormCallback "submitFormCallback"
+#define WbNpreviouslyVisitedTestFunction "previouslyVisitedTestFunction"
+#define WbNpreviouslyVisitedTestData "previouslyVisitedTestData"
+#define WbNresolveImageFunction "resolveImageFunction"
+#define WbNresolveDelayedImage "resolveDelayedImage"
+#define WbNpercentVerticalSpace "percentVerticalSpace"
+#define WbNpointerMotionCallback "pointerMotionCallback"
+#define WbNpointerMotionData "pointerMotionData"
+#define WbNverticalScrollOnRight "verticalScrollOnRight"
+#define WbNhorizontalScrollOnTop "horizontalScrollOnTop"
+#define WbNview "view"
+#define WbNverticalScrollBar "verticalScrollBar"
+#define WbNhorizontalScrollBar "horizontalScrollBar"
+
+/*
+ * New resource classes
+ */
+#define WbCMarginWidth "MarginWidth"
+#define WbCMarginHeight "MarginHeight"
+#define WbCText "Text"
+#define WbCHeaderText "HeaderText"
+#define WbCFooterText "FooterText"
+#define WbCTitleText "TitleText"
+#define WbCAnchorUnderlines "AnchorUnderlines"
+#define WbCVisitedAnchorUnderlines "VisitedAnchorUnderlines"
+#define WbCDashedAnchorUnderlines "DashedAnchorUnderlines"
+#define WbCDashedVisitedAnchorUnderlines "DashedVisitedAnchorUnderlines"
+#define WbCAnchorColor "AnchorColor"
+#define WbCVisitedAnchorColor "VisitedAnchorColor"
+#define WbCActiveAnchorFG "ActiveAnchorFG"
+#define WbCActiveAnchorBG "ActiveAnchorBG"
+#define WbCFancySelections "FancySelections"
+#define WbCImageBorders "ImageBorders"
+#define WbCDelayImageLoads "DelayImageLoads"
+#define WbCIsIndex "IsIndex"
+#define WbCItalicFont "ItalicFont"
+#define WbCBoldFont "BoldFont"
+#define WbCFixedFont "FixedFont"
+#define WbCFixedboldFont "FixedboldFont"
+#define WbCFixeditalicFont "FixeditalicFont"
+#define WbCHeader1Font "Header1Font"
+#define WbCHeader2Font "Header2Font"
+#define WbCHeader3Font "Header3Font"
+#define WbCHeader4Font "Header4Font"
+#define WbCHeader5Font "Header5Font"
+#define WbCHeader6Font "Header6Font"
+#define WbCAddressFont "AddressFont"
+#define WbCPlainFont "PlainFont"
+#define WbCPlainboldFont "PlainboldFont"
+#define WbCPlainitalicFont "PlainitalicFont"
+#define WbCListingFont "ListingFont"
+#define WbCPreviouslyVisitedTestFunction "PreviouslyVisitedTestFunction"
+#define WbCPreviouslyVisitedTestData "PreviouslyVisitedTestData"
+#define WbCResolveImageFunction "ResolveImageFunction"
+#define WbCResolveDelayedImage "ResolveDelayedImage"
+#define WbCPercentVerticalSpace "PercentVerticalSpace"
+#define WbCPointerMotionCallback "PointerMotionCallback"
+#define WbCPointerMotionData "PointerMotionData"
+#define WbCVerticalScrollOnRight "VerticalScrollOnRight"
+#define WbCHorizontalScrollOnTop "HorizontalScrollOnTop"
+#define WbCView "View"
+#define WbCVerticalScrollBar "VerticalScrollBar"
+#define WbCHorizontalScrollBar "HorizontalScrollBar"
+
+typedef struct _HTMLClassRec *HTMLWidgetClass;
+typedef struct _HTMLRec *HTMLWidget;
+
+extern WidgetClass htmlWidgetClass;
+
+
+#endif /* HTML_H */
+
diff --git a/vendor/x11iraf/obm/ObmW/HTML.notes b/vendor/x11iraf/obm/ObmW/HTML.notes
new file mode 100644
index 00000000..95ab1689
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTML.notes
@@ -0,0 +1,72 @@
+HTML Widget
+
+ Composite widget consisting of a drawingArea widget and horizontal and
+ vertical scrollbars.
+
+Resources
+
+ pic_data = resolveImageFunction (w, src, noload)
+ pic_data = resolveDelayedImage (w, src)
+
+
+Callbacks
+
+ anchorCallback (w, cbdata) called when href is selected
+ linkCallback (w, cbdata) called during set text for <LINK> tags
+ submitFormCallback (w, cbdata) called when form is submitted
+
+ LinkInfo: href role
+ anchorCallback: event element_id text href
+ formCallback: event href method enctype enc_entity
+ attrib_count attrib_names attrib_values
+
+
+Public Functions
+
+ HTMLGetText (w, pretty) # text or Postscript
+ HTMLPositionToId (w, x, y) # find nearest element
+ HTMLIdToPosition (w, element_id, x, y) # cvt id to position
+ HTMLGotoId (w, element_id) # scroll window to element
+ HTMLAnchorToPosition (w, name, x, y) # pos of anchor given name
+ HTMLAnchorToId (w, name) # id of anchor given name
+ list = HTMLGetHRefs (w, num_hrefs) # HREFs of all active anchors
+ HTMLGetImageSrcs (w, num_srcs) # SRCs of all images in doc
+ HTMLGetLinks (w, num_links) # get list of LINK tags in doc
+
+ HTMLGetWidgetInfo (w) # get widget list
+ HTMLFreeImageInfo (w) # free image resources
+ HTMLFreeWidgetInfo (ptr) # free WidgetInfo struct
+
+** HTMLRetestAnchors (w, testFunc, data) # redraw all active anchors
+
+ HTMLSetSelection (w, start, end) # set selection by ElementRef
+ HTMLClearSelection (w) # clear selection
+HTMLGetTextAndSelection(w,startp,endp,insertp) # get selection
+
+ HTMLSetText (w, text, header_text, # set document text
+ footer_text, element_id, target_anchor, ptr)
+
+ HTMLSearchText (w, pattern, m_start, # search text -> ElementRefs
+ m_end, backward, caseless)
+
+
+LOCAL REVISIONS
+----------------------
+
+Added a third argument (client_data for the callback function) to the
+HTMLRetestAnchors function. This required changes to several files.
+
+Likewise, added a client_data argument to the pointer motion callback.
+Mosaic in its callbacks would assume that the HTML widget was being called
+from within Mosaic, but this doesn't work in a more general setting.
+
+Modified the HTML widget to add a custom Realize method. This calls the
+realize method of the superclass and then makes a drawGC for the HTML
+widget. This was necessary to avoid segvios occuring when something is
+drawn in the window before the application becomes idle and the widget
+processes the first Expose event, as the widget would create the GC only
+in response to the expose event.
+
+Added a "scroll" action to the widget and modified the default HTML
+translations to add u/d and j/k keys to permit vertical scrolling using the
+keyboard instead of the scroll bars.
diff --git a/vendor/x11iraf/obm/ObmW/HTMLP.h b/vendor/x11iraf/obm/ObmW/HTMLP.h
new file mode 100644
index 00000000..6e75819e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLP.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#ifndef HTMLP_H
+#define HTMLP_H
+
+#include "HTML.h"
+
+#ifdef MOTIF
+#include <Xm/XmP.h>
+# ifdef MOTIF1_2
+# include <Xm/ManagerP.h>
+# endif /* MOTIF1_2 */
+#else
+#include <X11/IntrinsicP.h>
+#include <X11/ConstrainP.h>
+#endif /* MOTIF */
+
+#include <X11/Xatom.h>
+#include <X11/Xmu/Atoms.h>
+
+#if defined(SYSV) || defined(SVR4) || defined(__svr4__) || defined(VMS)
+#define bcopy(source, dest, count) memcpy(dest, source, count)
+#define bzero(b, len) memset(b, 0, len)
+#endif
+
+
+/*
+ * Used for special images
+ */
+#define INTERNAL_IMAGE "internal-"
+
+
+/* New fields for the HTML widget class */
+typedef struct _HTMLClassPart
+{
+ int none; /* no extra HTML class stuff */
+} HTMLClassPart;
+
+
+typedef struct _HTMLClassRec
+{
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+#ifdef MOTIF
+ XmManagerClassPart manager_class;
+#endif /* MOTIF */
+ HTMLClassPart html_class;
+} HTMLClassRec;
+
+
+extern HTMLClassRec htmlClassRec;
+
+
+/* New fields for the HTML widget */
+typedef struct _HTMLPart
+{
+ /* Resources */
+ Dimension margin_width;
+ Dimension margin_height;
+
+ Widget view;
+ Widget hbar;
+ Widget vbar;
+ Boolean hbar_top;
+ Boolean vbar_right;
+
+ XtCallbackList anchor_callback;
+ XtCallbackList link_callback;
+ XtCallbackList form_callback;
+
+ char *title;
+ char *raw_text;
+ char *header_text;
+ char *footer_text;
+/*
+ * Without motif we have to define our own forground resource
+ * instead of using the manager's
+ */
+#ifndef MOTIF
+ Pixel foreground;
+#endif
+ Pixel anchor_fg;
+ Pixel visitedAnchor_fg;
+ Pixel activeAnchor_fg;
+ Pixel activeAnchor_bg;
+ int num_anchor_underlines;
+ int num_visitedAnchor_underlines;
+ Boolean dashed_anchor_lines;
+ Boolean dashed_visitedAnchor_lines;
+ Boolean fancy_selections;
+ Boolean border_images;
+ Boolean delay_images;
+ Boolean is_index;
+ int percent_vert_space;
+
+ XFontStruct *font;
+ XFontStruct *italic_font;
+ XFontStruct *bold_font;
+ XFontStruct *fixed_font;
+ XFontStruct *fixedbold_font;
+ XFontStruct *fixeditalic_font;
+ XFontStruct *header1_font;
+ XFontStruct *header2_font;
+ XFontStruct *header3_font;
+ XFontStruct *header4_font;
+ XFontStruct *header5_font;
+ XFontStruct *header6_font;
+ XFontStruct *address_font;
+ XFontStruct *plain_font;
+ XFontStruct *plainbold_font;
+ XFontStruct *plainitalic_font;
+ XFontStruct *listing_font;
+
+ XtPointer previously_visited_test;
+ XtPointer vt_client_data;
+ XtPointer resolveImage;
+ XtPointer resolveDelayedImage;
+
+ XtPointer pointer_motion_callback;
+ XtPointer pm_client_data;
+
+ /* PRIVATE */
+ Dimension max_pre_width;
+ Dimension view_width;
+ Dimension view_height;
+ int doc_width;
+ int doc_height;
+ int scroll_x;
+ int scroll_y;
+ Boolean use_hbar;
+ Boolean use_vbar;
+ struct ele_rec *formatted_elements;
+ int line_count;
+ struct ele_rec **line_array;
+ struct ele_rec *select_start;
+ struct ele_rec *select_end;
+ int sel_start_pos;
+ int sel_end_pos;
+ struct ele_rec *new_start;
+ struct ele_rec *new_end;
+ int new_start_pos;
+ int new_end_pos;
+ struct ele_rec *active_anchor;
+ GC drawGC;
+ int press_x;
+ int press_y;
+ Time but_press_time;
+ Time selection_time;
+ struct mark_up *html_objects;
+ struct mark_up *html_header_objects;
+ struct mark_up *html_footer_objects;
+ struct ref_rec *my_visited_hrefs;
+ struct delay_rec *my_delayed_images;
+ WidgetInfo *widget_list;
+ FormInfo *form_list;
+
+ struct ele_rec *cached_tracked_ele;
+} HTMLPart;
+
+
+typedef struct _HTMLRec
+{
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+#ifdef MOTIF
+ XmManagerPart manager;
+#endif /* MOTIF */
+ HTMLPart html;
+} HTMLRec;
+
+/*
+ * to reduce the number of MOTIF/ATHENA ifdefs around the code
+ * we use some generalized constants
+ */
+#ifdef MOTIF
+# define XxNx XmNx
+# define XxNy XmNy
+# define XxNwidth XmNwidth
+# define XxNheight XmNheight
+# define XxNset XmNset
+# define XxNvalue XmNvalue
+#else
+# define XxNx XtNx
+# define XxNy XtNy
+# define XxNwidth XtNwidth
+# define XxNheight XtNheight
+# define XxNset XtNstate
+# define XxNvalue XtNstring
+#endif /* MOTIF */
+
+
+#endif /* HTMLP_H */
diff --git a/vendor/x11iraf/obm/ObmW/HTMLamp.h b/vendor/x11iraf/obm/ObmW/HTMLamp.h
new file mode 100644
index 00000000..6536f806
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLamp.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+
+typedef struct amp_esc_rec {
+ char *tag;
+ char value;
+} AmpEsc;
+
+static AmpEsc AmpEscapes[] = {
+ {"lt", '<'},
+ {"LT", '<'},
+ {"gt", '>'},
+ {"GT", '>'},
+ {"amp", '&'},
+ {"AMP", '&'},
+ {"quot", '\"'},
+ {"QUOT", '\"'},
+ {"Agrave", '\300'},
+ {"Aacute", '\301'},
+ {"Acirc", '\302'},
+ {"Atilde", '\303'},
+ {"Auml", '\304'},
+ {"Aring", '\305'},
+ {"AElig", '\306'},
+ {"Ccedil", '\307'},
+ {"Egrave", '\310'},
+ {"Eacute", '\311'},
+ {"Ecirc", '\312'},
+ {"Euml", '\313'},
+ {"Igrave", '\314'},
+ {"Iacute", '\315'},
+ {"Icirc", '\316'},
+ {"Iuml", '\317'},
+ {"ETH", '\320'},
+ {"Ntilde", '\321'},
+ {"Ograve", '\322'},
+ {"Oacute", '\323'},
+ {"Ocirc", '\324'},
+ {"Otilde", '\325'},
+ {"Ouml", '\326'},
+
+ {"?", '\327'}, /* ? */
+
+ {"Oslash", '\330'},
+ {"Ugrave", '\331'},
+ {"Uacute", '\332'},
+ {"Ucirc", '\333'},
+ {"Uuml", '\334'},
+ {"Yacute", '\335'},
+ {"THORN", '\336'},
+ {"szlig", '\337'},
+ {"agrave", '\340'},
+ {"aacute", '\341'},
+ {"acirc", '\342'},
+ {"atilde", '\343'},
+ {"auml", '\344'},
+ {"aring", '\345'},
+ {"aelig", '\346'},
+ {"ccedil", '\347'},
+ {"egrave", '\350'},
+ {"eacute", '\351'},
+ {"ecirc", '\352'},
+ {"euml", '\353'},
+ {"igrave", '\354'},
+ {"iacute", '\355'},
+ {"icirc", '\356'},
+ {"iuml", '\357'},
+ {"eth", '\360'},
+ {"ntilde", '\361'},
+ {"ograve", '\362'},
+ {"oacute", '\363'},
+ {"ocirc", '\364'},
+ {"otilde", '\365'},
+ {"ouml", '\366'},
+
+ {"?", '\367'}, /* ? */
+
+ {"oslash", '\370'},
+ {"ugrave", '\371'},
+ {"uacute", '\372'},
+ {"ucirc", '\373'},
+ {"uuml", '\374'},
+ {"yacute", '\375'},
+ {"thorn", '\376'},
+ {"yuml", '\377'},
+
+ {NULL, '\0'},
+};
+
diff --git a/vendor/x11iraf/obm/ObmW/HTMLformat.c b/vendor/x11iraf/obm/ObmW/HTMLformat.c
new file mode 100644
index 00000000..d58eed5e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLformat.c
@@ -0,0 +1,6285 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#ifdef TIMING
+#include <sys/time.h>
+struct timeval Tv;
+struct timezone Tz;
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include "HTMLP.h"
+
+
+/*
+ * I need my own is ispunct function because I need a closing paren
+ * immediately after a word to act like punctuation.
+ */
+#define MY_ISPUNCT(val) (ispunct((int)(val)) || ((val) == ')'))
+
+#define INDENT_SPACES 2
+#define IMAGE_BORDER 2
+
+#define D_NONE 0
+#define D_TITLE 1
+#define D_TEXT 2
+#define D_OLIST 3
+#define D_ULIST 4
+
+#define ALIGN_BOTTOM 0
+#define ALIGN_MIDDLE 1
+#define ALIGN_TOP 2
+
+
+extern struct ele_rec *AddEle();
+extern void FreeLineList();
+extern void FreeObjList();
+extern int SwapElements();
+extern struct ele_rec **MakeLineList();
+extern char *ParseMarkTag();
+extern char *MaxTextWidth();
+extern char *IsMapForm();
+extern char *DelayedHRef();
+extern int IsDelayedHRef();
+extern int AnchoredHeight();
+extern struct mark_up *HTMLParse();
+extern struct ref_rec *FindHRef();
+extern struct delay_rec *FindDelayedImage();
+extern ImageInfo *NoImageData();
+extern ImageInfo *DelayedImageData();
+extern Pixmap NoImage();
+extern Pixmap DelayedImage();
+extern Pixmap InfoToImage();
+extern int caseless_equal();
+extern void clean_white_space();
+extern void WidgetRefresh();
+extern WidgetInfo *MakeWidget();
+extern XFontStruct *GetWidgetFont();
+extern void AddNewForm();
+extern void PrepareFormEnd();
+extern char *ComposeCommaList();
+extern void FreeCommaList();
+
+
+/*
+ * To allow arbitrary nesting of lists
+ */
+typedef struct dtype_rec {
+ int type; /* D_NONE, D_TITLE, D_TEXT, D_OLIST, D_ULIST */
+ int count;
+ int compact;
+ struct dtype_rec *next;
+} DescRec;
+
+
+/*
+ * To allow arbitrary nesting of font changes
+ */
+typedef struct font_rec {
+ XFontStruct *font;
+ struct font_rec *next;
+} FontRec;
+
+static DescRec BaseDesc;
+static DescRec *DescType;
+static DescRec *ListData;
+static FontRec FontBase;
+static FontRec *FontStack;
+static XFontStruct *currentFont;
+static XFontStruct *saveFont;
+static unsigned long Fg;
+static unsigned long Bg;
+static int Width;
+static int MaxWidth;
+static int ElementId;
+static int WidgetId;
+static int LineNumber;
+static int LineHeight;
+static int LineBottom;
+static int BaseLine;
+static int TextIndent;
+static int MarginW;
+static int Ignore;
+static int Preformat;
+static int PF_LF_State; /* Pre-formatted linefeed state. Hack for bad HTMLs */
+static int NeedSpace;
+static Boolean Internal;
+static Boolean DashedUnderlines;
+static Boolean Strikeout;
+static int Underlines;
+static int CharsInLine;
+static int IndentLevel;
+static struct ele_rec *Current;
+static char *AnchorText;
+static char *TitleText;
+static char *TextAreaBuf;
+static struct mark_up *Last;
+static FormInfo *CurrentForm;
+static SelectInfo *CurrentSelect;
+
+/*
+ * Turned out we were taking WAY too much time mallocing and freeing
+ * memory when composing the lines into elements. So this ineligent
+ * method minimizes all that.
+ */
+#define COMP_LINE_BUF_LEN 1024
+static char *CompLine = NULL;
+static int CompLineLen = 0;
+static char *CompWord = NULL;
+static int CompWordLen = 0;
+
+
+
+/*
+ * Create a formatted element
+ */
+struct ele_rec *
+CreateElement(hw, type, fp, x, y, edata)
+ HTMLWidget hw;
+ int type;
+ XFontStruct *fp;
+ int x, y;
+ char *edata;
+{
+ struct ele_rec *eptr;
+ int baseline;
+
+ if (fp != NULL)
+ {
+ baseline = fp->max_bounds.ascent;
+ }
+ else
+ {
+ baseline = LineHeight;
+ }
+
+ eptr = (struct ele_rec *)malloc(sizeof(struct ele_rec));
+ if (eptr == NULL)
+ {
+ fprintf(stderr, "Cannot allocate space for element buffer\n");
+ exit(1);
+ }
+
+ eptr->type = type;
+ eptr->pic_data = NULL;
+ eptr->widget_data = NULL;
+ eptr->font = fp;
+ eptr->alignment = ALIGN_BOTTOM;
+ eptr->selected = False;
+ eptr->internal = Internal;
+ eptr->strikeout = Strikeout;
+ eptr->x = x;
+ eptr->y = y;
+ eptr->y_offset = 0;
+ eptr->width = 0;
+ eptr->line_number = LineNumber;
+ eptr->line_height = LineHeight;
+ eptr->fg = Fg;
+ eptr->bg = Bg;
+ eptr->underline_number = Underlines;
+ eptr->dashed_underline = DashedUnderlines;
+ eptr->indent_level = IndentLevel;
+
+ switch(type)
+ {
+ case E_TEXT:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ eptr->y_offset = 0;
+
+ eptr->edata_len = strlen(edata) + 1;
+ eptr->edata = (char *)malloc(eptr->edata_len);
+ if (eptr->edata == NULL)
+ {
+ eptr->edata_len = 0;
+ fprintf(stderr, "Cannot allocate space for copy of text element data\n");
+ exit(1);
+ }
+ strcpy(eptr->edata, edata);
+
+ /*
+ * if this is an anchor, puts its href value into
+ * the element.
+ */
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+ break;
+ case E_BULLET:
+ eptr->ele_id = ElementId;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+ else if (baseline < BaseLine)
+ {
+ eptr->y_offset = BaseLine - baseline;
+ }
+
+ /*
+ * Bullets can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ case E_HRULE:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+ else if (baseline < BaseLine)
+ {
+ eptr->y_offset = BaseLine - baseline;
+ }
+
+ /*
+ * Rules can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ case E_LINEFEED:
+ eptr->ele_id = ElementId;
+
+ eptr->y_offset = 0;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+
+ /*
+ * Linefeeds have to use the maximum line height.
+ * Deal with bad Lucidia descents.
+ */
+#ifdef NO_EXTRA_FILLS
+ eptr->line_height = eptr->font->ascent +
+ eptr->font->descent;
+#else
+ eptr->line_height = LineHeight;
+#endif /* NO_EXTRA_FILLS */
+ if ((BaseLine + LineBottom) > eptr->line_height)
+ {
+ eptr->line_height = BaseLine + LineBottom;
+ }
+
+ /*
+ * Linefeeds can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ /*
+ * if this linefeed is part of a broken anchor put
+ * its href value into the element so we can reconnect
+ * it when activated.
+ * If it at the beginning of an anchor, don't put
+ * the href in, and change the color back.
+ */
+ if (AnchorText != NULL)
+ {
+ char *tptr;
+
+ tptr = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ if ((Current != NULL)&&
+ ((Current->anchorHRef == NULL)||
+ (tptr == NULL)||
+ (strcmp(Current->anchorHRef, tptr) != 0)))
+ {
+ if (tptr)
+ free(tptr);
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ eptr->fg = hw->manager.foreground;
+#else
+ eptr->fg = hw->html.foreground;
+#endif /* MOTIF */
+ }
+ else
+ {
+ eptr->anchorHRef = tptr;
+ eptr->anchorName =
+ ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+ break;
+ case E_IMAGE:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ /*
+ * Images can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (edata != NULL)
+ {
+ eptr->edata_len = strlen(edata) + 1;
+ eptr->edata = (char *)malloc(eptr->edata_len);
+ if (eptr->edata == NULL)
+ {
+ eptr->edata_len = 0;
+ fprintf(stderr, "Cannot allocate space for copy of image element data\n");
+ exit(1);
+ }
+ strcpy(eptr->edata, edata);
+ }
+ else
+ {
+ eptr->edata_len = 0;
+ eptr->edata = NULL;
+ }
+
+ /*
+ * if this image is part of an anchor put
+ * its href and name values into the element
+ * so we can reconnect it when activated.
+ */
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+
+ /*
+ * Picture stuff
+ */
+ /*
+ * if we have an image resolver, use it.
+ */
+ if (hw->html.resolveImage != NULL)
+ {
+ int internal;
+
+ /*
+ * See if this is a special internal image
+ */
+ if ((edata != NULL)&&
+ (strncmp(edata, INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ internal = 1;
+ }
+ else
+ {
+ internal = 0;
+ }
+
+ /*
+ * if we delay image fetching
+ * internal images are not delayed.
+ */
+ if ((hw->html.delay_images == True)&&
+ (!internal))
+ {
+ /*
+ * see if already cached.
+ */
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveImage))(hw, edata, 1);
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ }
+ /*
+ * else, not cached.
+ */
+ else
+ {
+ /*
+ * just image
+ */
+ if (eptr->anchorHRef == NULL)
+ {
+ eptr->pic_data = DelayedImageData(hw,
+ False);
+ eptr->pic_data->delayed = 1;
+ eptr->anchorHRef = DelayedHRef(hw);
+ eptr->fg = hw->html.anchor_fg;
+ }
+ /*
+ * else anchor and image
+ */
+ else
+ {
+ eptr->pic_data = DelayedImageData(hw,
+ True);
+ eptr->pic_data->delayed = 1;
+ }
+ }
+ }
+ else
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveImage))(hw, edata, 0);
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ }
+ }
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->internal = internal;
+ }
+ }
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+
+ break;
+ case E_WIDGET:
+ /*
+ * get a unique element id
+ */
+ WidgetId++;
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ /*
+ * Widgets can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+
+ /*
+ * if this widget is part of an anchor put
+ * its href and name values into the element
+ * so we can reconnect it when activated.
+ */
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+
+ /*
+ * Widget stuff
+ */
+ eptr->widget_data = MakeWidget(hw, edata,
+ (x + IMAGE_BORDER), (y + IMAGE_BORDER),
+ WidgetId, CurrentForm);
+
+ /*
+ * I have no idea what to do if we can't create the
+ * widget. It probably means we are so messed up we
+ * will soon be crashing.
+ */
+ if (eptr->widget_data == NULL)
+ {
+ }
+
+ break;
+ default:
+ fprintf(stderr, "CreateElement: Unknown type %d\n", type);
+ eptr->ele_id = ElementId;
+
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ }
+ return(eptr);
+}
+
+
+/*
+ * Set the formatted element into the format list. Use a pre-allocated
+ * list position if possible, otherwise allocate a new list position.
+ */
+void
+SetElement(hw, type, fp, x, y, edata)
+ HTMLWidget hw;
+ int type;
+ XFontStruct *fp;
+ int x, y;
+ char *edata;
+{
+ struct ele_rec *eptr;
+ int len;
+ int baseline;
+
+ if (fp != NULL)
+ {
+ baseline = fp->max_bounds.ascent;
+ }
+ else
+ {
+ baseline = LineHeight;
+ }
+
+ /*
+ * There is not pre-allocated format list, or we have reached
+ * the end of the pre-allocated list. Create a new element, and
+ * add it.
+ */
+ if ((hw->html.formatted_elements == NULL)||
+ ((Current != NULL)&&(Current->next == NULL)))
+ {
+ eptr = CreateElement(hw, type, fp, x, y, edata);
+ Current = AddEle(&(hw->html.formatted_elements), Current, eptr);
+ return;
+ }
+
+ /*
+ * If current is null, but we have a pre-allocated format list, then
+ * this is the first SetElement() call for this formated text, and
+ * we must set current to the head of the formatted list. Otherwise
+ * we move current to the next pre-allocated list position.
+ */
+ if (Current == NULL)
+ {
+ Current = hw->html.formatted_elements;
+ }
+ else
+ {
+ Current = Current->next;
+ }
+
+ eptr = Current;
+ if (eptr == NULL)
+ {
+ fprintf(stderr, "SetElement: Error, setting a null element\n");
+ exit(1);
+ }
+
+ eptr->type = type;
+ eptr->pic_data = NULL;
+ eptr->widget_data = NULL;
+ eptr->font = fp;
+ eptr->alignment = ALIGN_BOTTOM;
+ eptr->selected = False;
+ eptr->internal = Internal;
+ eptr->strikeout = Strikeout;
+ eptr->x = x;
+ eptr->y = y;
+ eptr->y_offset = 0;
+ eptr->width = 0;
+ eptr->line_number = LineNumber;
+ eptr->line_height = LineHeight;
+ eptr->fg = Fg;
+ eptr->bg = Bg;
+ eptr->underline_number = Underlines;
+ eptr->dashed_underline = DashedUnderlines;
+ eptr->indent_level = IndentLevel;
+
+ switch(type)
+ {
+ case E_TEXT:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ eptr->y_offset = 0;
+
+ len = strlen(edata) + 1;
+ if (len > eptr->edata_len)
+ {
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = (char *)malloc(len);
+ if (eptr->edata == NULL)
+ {
+ eptr->edata_len = 0;
+ fprintf(stderr, "Cannot allocate space for copy of text element data\n");
+ exit(1);
+ }
+ }
+ eptr->edata_len = len;
+ strcpy(eptr->edata, edata);
+
+ /*
+ * if this is an anchor, puts its href and name
+ * values into the element.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+ break;
+ case E_BULLET:
+ eptr->ele_id = ElementId;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+ else if (baseline < BaseLine)
+ {
+ eptr->y_offset = BaseLine - baseline;
+ }
+
+ /*
+ * Bullets can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ case E_HRULE:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+ else if (baseline < BaseLine)
+ {
+ eptr->y_offset = BaseLine - baseline;
+ }
+
+ /*
+ * Rules can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ case E_LINEFEED:
+ eptr->ele_id = ElementId;
+
+ eptr->y_offset = 0;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+
+ /*
+ * Linefeeds have to use the maximum line height.
+ * Deal with bad Lucidia descents.
+ */
+#ifdef NO_EXTRA_FILLS
+ eptr->line_height = eptr->font->ascent +
+ eptr->font->descent;
+#else
+ eptr->line_height = LineHeight;
+#endif /* NO_EXTRA_FILLS */
+ if ((BaseLine + LineBottom) > eptr->line_height)
+ {
+ eptr->line_height = (BaseLine + LineBottom);
+ }
+
+ /*
+ * Linefeeds can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ /*
+ * if this linefeed is part of a broken anchor put
+ * its href and name values into the element
+ * so we can reconnect it when activated.
+ * If it at the beginning of an anchor, don't put
+ * the href in and change the color back.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ if (AnchorText != NULL)
+ {
+ char *tptr;
+
+ tptr = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ if ((eptr->prev != NULL)&&
+ ((eptr->prev->anchorHRef == NULL)||
+ (tptr == NULL)||
+ (strcmp(eptr->prev->anchorHRef, tptr) != 0)))
+ {
+ if (tptr)
+ free(tptr);
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ eptr->fg = hw->manager.foreground;
+#else
+ eptr->fg = hw->html.foreground;
+#endif /* MOTIF */
+ }
+ else
+ {
+ eptr->anchorHRef = tptr;
+ eptr->anchorName =
+ ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+ break;
+ case E_IMAGE:
+ /*
+ * get a unique element id
+ */
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ /*
+ * Images can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (edata != NULL)
+ {
+ len = strlen(edata) + 1;
+ if (len > eptr->edata_len)
+ {
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = (char *)malloc(len);
+ if (eptr->edata == NULL)
+ {
+ eptr->edata_len = 0;
+ fprintf(stderr, "Cannot allocate space for copy of text element data\n");
+ exit(1);
+ }
+ }
+ eptr->edata_len = len;
+ strcpy(eptr->edata, edata);
+ }
+ else
+ {
+ eptr->edata_len = 0;
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ }
+
+ /*
+ * if this image is part of an anchor put
+ * its href and name values into the element
+ * so we can reconnect it when activated.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+
+ /*
+ * Picture stuff
+ */
+ /*
+ * if we have an image resolver, use it.
+ */
+ if (hw->html.resolveImage != NULL)
+ {
+ int internal;
+
+ /*
+ * See if this is a special internal image
+ */
+ if ((edata != NULL)&&
+ (strncmp(edata, INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ internal = 1;
+ }
+ else
+ {
+ internal = 0;
+ }
+
+ /*
+ * if we delay image fetching
+ * internal images are not delayed.
+ */
+ if ((hw->html.delay_images == True)&&
+ (!internal))
+ {
+ /*
+ * see if already cached.
+ */
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveImage))(hw, edata, 1);
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ }
+ /*
+ * else, not cached.
+ */
+ else
+ {
+ /*
+ * just image
+ */
+ if (eptr->anchorHRef == NULL)
+ {
+ eptr->pic_data = DelayedImageData(hw,
+ False);
+ eptr->pic_data->delayed = 1;
+ eptr->anchorHRef = DelayedHRef(hw);
+ eptr->fg = hw->html.anchor_fg;
+ }
+ /*
+ * else anchor and image
+ */
+ else
+ {
+ eptr->pic_data = DelayedImageData(hw,
+ True);
+ eptr->pic_data->delayed = 1;
+ }
+ }
+ }
+ else
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveImage))(hw, edata, 0);
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ }
+ }
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->internal = internal;
+ }
+ }
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+
+ break;
+ case E_WIDGET:
+ /*
+ * get a unique element id
+ */
+ WidgetId++;
+ ElementId++;
+ eptr->ele_id = ElementId;
+
+ /*
+ * Widgets can't be underlined!
+ */
+ eptr->underline_number = 0;
+
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+
+ /*
+ * if this widget is part of an anchor put
+ * its href and name values into the element
+ * so we can reconnect it when activated.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ if (AnchorText != NULL)
+ {
+ eptr->anchorHRef = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_HREF);
+ eptr->anchorName = ParseMarkTag(AnchorText,
+ MT_ANCHOR, AT_NAME);
+ }
+ else
+ {
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ }
+
+ /*
+ * Widget stuff
+ */
+ eptr->widget_data = MakeWidget(hw, edata,
+ (x + IMAGE_BORDER), (y + IMAGE_BORDER),
+ WidgetId, CurrentForm);
+
+ /*
+ * I have no idea what to do if we can't create the
+ * widget. It probably means we are so messed up we
+ * will soon be crashing.
+ */
+ if (eptr->widget_data == NULL)
+ {
+ }
+
+ break;
+ default:
+ fprintf(stderr, "SetElement: Unknown type %d\n", type);
+ eptr->ele_id = ElementId;
+
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ eptr->edata = NULL;
+ eptr->edata_len = 0;
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ eptr->anchorHRef = NULL;
+ eptr->anchorName = NULL;
+ break;
+ }
+}
+
+
+/*
+ * Change our drawing font
+ */
+void
+NewFont(fp)
+ XFontStruct *fp;
+{
+ /*
+ * Deal with bad Lucidia descents.
+ */
+ if (fp->descent > fp->max_bounds.descent)
+ {
+ LineHeight = fp->max_bounds.ascent + fp->descent;
+ }
+ else
+ {
+ LineHeight = fp->max_bounds.ascent + fp->max_bounds.descent;
+ }
+}
+
+
+/*
+ * Place a linefeed at the end of a line.
+ * Create and add the element record for it.
+ */
+void
+LinefeedPlace(hw, x, y)
+ HTMLWidget hw;
+ int *x, *y;
+{
+ /*
+ * At the end of every line check if we have a new MaxWidth
+ */
+ if ((int)(*x + hw->html.margin_width) > MaxWidth)
+ {
+ MaxWidth = *x + hw->html.margin_width;
+ }
+
+ SetElement(hw, E_LINEFEED, currentFont, *x, *y, (char *)NULL);
+}
+
+
+/*
+ * We have encountered a line break. Incrment the line counter,
+ * and move down some space.
+ */
+void
+LineFeed(hw, x, y)
+ HTMLWidget hw;
+ int *x, *y;
+{
+ /*
+ * Manipulate linefeed state for special pre-formatted linefeed
+ * hack for broken HTMLs
+ */
+ if (Preformat)
+ {
+ switch(PF_LF_State)
+ {
+ /*
+ * First soft linefeed
+ */
+ case 0:
+ PF_LF_State = 1;
+ break;
+ /*
+ * Collapse multiple soft linefeeds within a pre
+ */
+ case 1:
+ return;
+ break;
+ /*
+ * Ignore soft linefeeds after hard linefeeds
+ * within a pre
+ */
+ case 2:
+ return;
+ break;
+ default:
+ PF_LF_State = 1;
+ break;
+ }
+ }
+ /*
+ * No blank lines allowed at the start of a document.
+ */
+ else if (ElementId == 0)
+ {
+ return;
+ }
+ /*
+ * For formatted documents there are 3 linefeed states.
+ * 0 = in the middle of a line.
+ * 1 = at left margin
+ * 2 = at left margin with blank line above
+ */
+ else
+ {
+ PF_LF_State++;
+ if (PF_LF_State > 2)
+ {
+ PF_LF_State = 2;
+ }
+ }
+
+ /*
+ * sanity check to set some line height if none was specified.
+ */
+ if (BaseLine <= 0)
+ {
+ BaseLine = LineHeight;
+ }
+
+ LinefeedPlace(hw, x, y);
+
+ CharsInLine = 0;
+ *x = TextIndent;
+ *y = *y + BaseLine + LineBottom;
+
+ LineBottom = 0;
+ BaseLine = -100;
+
+ NeedSpace = 0;
+ LineNumber++;
+}
+
+
+/*
+ * We want to make sure that future text starts at the left margin.
+ * But if we are already there, don't put in a new line.
+ */
+void
+ConditionalLineFeed(hw, x, y, state)
+ HTMLWidget hw;
+ int *x, *y;
+ int state;
+{
+ if (PF_LF_State < state)
+ {
+ /*
+ * If this funtion is being used to insert a blank line,
+ * we need to look at the percentVerticalSpace resource
+ * to see how high to make the line.
+ */
+ if ((state == 2)&&(hw->html.percent_vert_space > 0))
+ {
+ int l_height;
+
+ l_height = LineHeight;
+ LineHeight = LineHeight *
+ hw->html.percent_vert_space / 100;
+ LineFeed(hw, x, y);
+ LineHeight = l_height;
+ }
+ else
+ {
+ LineFeed(hw, x, y);
+ }
+ }
+}
+
+
+/*
+ * hack to make broken HTMLs within pre-formatted text have nice
+ * looking linefeeds.
+ */
+void
+HardLineFeed(hw, x, y)
+ HTMLWidget hw;
+ int *x, *y;
+{
+ /*
+ * Manipulate linefeed state for special pre-formatted linefeed
+ * hack for broken HTMLs
+ */
+ if (Preformat)
+ {
+ switch(PF_LF_State)
+ {
+ /*
+ * First hard linefeed
+ */
+ case 0:
+ PF_LF_State = 2;
+ break;
+ /*
+ * Previous soft linefeed should have been ignored, so
+ * ignore this hard linefeed, but set state like it
+ * was not ignored.
+ */
+ case 1:
+ PF_LF_State = 2;
+ return;
+ break;
+ /*
+ * Honor multiple hard linefeeds.
+ */
+ case 2:
+ break;
+ default:
+ PF_LF_State = 2;
+ break;
+ }
+ }
+
+ /*
+ * sanity check to set some line height if none was specified.
+ */
+ if (BaseLine <= 0)
+ {
+ BaseLine = LineHeight;
+ }
+
+ LinefeedPlace(hw, x, y);
+
+ CharsInLine = 0;
+ *x = TextIndent;
+ *y = *y + BaseLine + LineBottom;
+
+ LineBottom = 0;
+ BaseLine = -100;
+
+ NeedSpace = 0;
+ LineNumber++;
+}
+
+
+static void
+AdjustBaseLine()
+{
+ int baseline;
+
+ baseline = Current->font->max_bounds.ascent;
+
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ Current->y_offset = 0;
+ if (LineBottom == 0)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ else
+ {
+ /*
+ * It is possible (with the first item
+ * in a line being a top aligned image)
+ * for LineBottom to have already been
+ * set. It now needs to be
+ * corrected as we set a real
+ * BaseLine
+ */
+ if ((LineHeight - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom = LineHeight -
+ baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom -
+ baseline;
+ }
+ }
+ }
+ else if (baseline <= BaseLine)
+ {
+ if (baseline < BaseLine)
+ {
+ Current->y_offset = BaseLine - baseline;
+ }
+ else
+ {
+ Current->y_offset = 0;
+ }
+
+ if ((LineHeight - baseline) > LineBottom)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ }
+ else
+ {
+ struct ele_rec *eptr;
+ int line, incy;
+
+ incy = baseline - BaseLine;
+ BaseLine = baseline;
+
+ /*
+ * Go back over this line
+ * and move everything down
+ * a little.
+ */
+ eptr = Current;
+ line = eptr->line_number;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->line_number == line))
+ {
+ eptr = eptr->prev;
+ eptr->y_offset = eptr->y_offset + incy;
+ }
+
+ if ((LineHeight - baseline) > LineBottom)
+ {
+ LineBottom = LineHeight - baseline;
+ }
+ }
+}
+
+
+/*
+ * Place the bullet at the beginning of an unnumbered
+ * list item. Create and add the element record for it.
+ */
+void
+BulletPlace(hw, x, y)
+ HTMLWidget hw;
+ int *x, *y;
+{
+ int width, l_height;
+
+ /*
+ * Save the font's line height, and set your own for this
+ * element. Restore the fonts height when done.
+ * Deal with bad Lucidia descents.
+ */
+ l_height = LineHeight;
+ if (hw->html.font->descent > hw->html.font->max_bounds.descent)
+ {
+ LineHeight = hw->html.font->max_bounds.ascent +
+ hw->html.font->descent;
+ }
+ else
+ {
+ LineHeight = hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent;
+ }
+
+ NeedSpace = 0;
+ width = hw->html.font->max_bounds.width;
+ SetElement(hw, E_BULLET, hw->html.font, *x, *y, (char *)NULL);
+ LineHeight = l_height;
+/*
+ * This should reall be here, but it is a hack for headers on list
+ * elements to work if we leave it out
+ PF_LF_State = 0;
+ */
+}
+
+
+/*
+ * Place a horizontal rule across the page.
+ * Create and add the element record for it.
+ */
+void
+HRulePlace(hw, x, y, width)
+ HTMLWidget hw;
+ int *x, *y;
+ unsigned int width;
+{
+ NeedSpace = 0;
+ *x = hw->html.margin_width;
+ SetElement(hw, E_HRULE, currentFont, *x, *y, (char *)NULL);
+ *x = *x + width - (2 * hw->html.margin_width);
+ NeedSpace = 1;
+ PF_LF_State = 0;
+}
+
+
+/*
+ * Place the number at the beginning of an numbered
+ * list item. Create and add the element record for it.
+ */
+void
+ListNumberPlace(hw, x, y, val)
+ HTMLWidget hw;
+ int *x, *y;
+ int val;
+{
+ int width, my_x;
+ int dir, ascent, descent;
+ XCharStruct all;
+ char buf[20];
+
+ sprintf(buf, "%d.", val);
+
+ width = hw->html.font->max_bounds.lbearing +
+ hw->html.font->max_bounds.rbearing;
+ XTextExtents(currentFont, buf, strlen(buf), &dir,
+ &ascent, &descent, &all);
+ my_x = *x - (width / 2) - all.width;
+ /*
+ * Add a space after thenumber here so it will look right when
+ * cut and pasted from a selection.
+ */
+ width = strlen(buf);
+ buf[width] = ' ';
+ buf[width + 1] = '\0';
+
+ SetElement(hw, E_TEXT, currentFont, my_x, *y, buf);
+ AdjustBaseLine();
+ CharsInLine = CharsInLine + strlen(buf);
+
+ NeedSpace = 0;
+/*
+ * This should reall be here, but it is a hack for headers on list
+ * elements to work if we leave it out
+ PF_LF_State = 0;
+ */
+}
+
+
+/*
+ * Place a piece of pre-formatted text. Add an element record for it.
+ */
+void
+PreformatPlace(hw, mptr, x, y, width)
+ HTMLWidget hw;
+ struct mark_up *mptr;
+ int *x, *y;
+ unsigned int width;
+{
+ char *text;
+ char *start;
+ char *end;
+ char *ptr;
+ char tchar;
+ int tab_count, char_cnt;
+ int dir, ascent, descent;
+ XCharStruct all;
+ char *line;
+ int line_x;
+
+ text = mptr->text;
+
+ line_x = *x;
+ line = CompLine;
+ if (line != NULL)
+ {
+ line[0] = '\0';
+ }
+ end = text;
+ while (*end != '\0')
+ {
+ tab_count = 0;
+ char_cnt = CharsInLine;
+ /*
+ * make start and end point to one word. A word is either
+ * a lone linefeed, or all whitespace before a word, plus
+ * the text of the word itself.
+ */
+ start = end;
+ /*
+ * Throw out carriage returns and form-feeds
+ */
+ if ((*end == '\r')||(*end == '\f'))
+ {
+ start++;
+ end++;
+ }
+ else if (*end == '\n')
+ {
+ end++;
+ char_cnt++;
+ }
+ else
+ {
+ /*
+ * Should be only spaces and tabs here, so if it
+ * is not a tab, make it a space.
+ * Break on linefeeds, they must be done separately
+ */
+ while (((int)((unsigned char)*end) < 128)&&
+ (isspace(*end)))
+ {
+ if (*end == '\n')
+ {
+ break;
+ }
+ else if (*end == '\t')
+ {
+ tab_count++;
+ char_cnt = ((char_cnt / 8) + 1) * 8;
+ }
+ else
+ {
+ *end = ' ';
+ char_cnt++;
+ }
+ end++;
+ }
+ while (((int)((unsigned char)*end) > 127)||
+ ((!isspace(*end))&&(*end != '\0')))
+ {
+ end++;
+ char_cnt++;
+ }
+ }
+
+ /*
+ * Add the word to the end of this line, or insert
+ * a linefeed if the word is a lone linefeed.
+ * tabs expand to 8 spaces.
+ */
+ if (start != end)
+ {
+ int tlen;
+
+ tchar = *end;
+ *end = '\0';
+
+ tlen = char_cnt + 1;
+ if (tlen > CompWordLen)
+ {
+ CompWordLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompWordLen)
+ {
+ CompWordLen = tlen;
+ }
+ if (CompWord != NULL)
+ {
+ free(CompWord);
+ }
+ CompWord = (char *)malloc(CompWordLen);
+ }
+ ptr = CompWord;
+
+ /*
+ * If we have any tabs, expand them into spaces.
+ */
+ if (tab_count)
+ {
+ char *p1, *p2;
+ int i, new;
+
+ char_cnt = CharsInLine;
+ p1 = ptr;
+ p2 = start;
+ while (*p2 != '\0')
+ {
+ if (*p2 == '\t')
+ {
+ new = ((char_cnt / 8) + 1) * 8;
+ for (i=0; i<(new-char_cnt); i++)
+ {
+ *p1++ = ' ';
+ }
+ p2++;
+ char_cnt = new;
+ }
+ else
+ {
+ *p1++ = *p2++;
+ char_cnt++;
+ }
+ }
+ *p1 = '\0';
+ }
+ else
+ {
+ strcpy(ptr, start);
+ }
+
+#ifdef ASSUME_FIXED_WIDTH_PRE
+ all.width = currentFont->max_bounds.width * strlen(ptr);
+#else
+ XTextExtents(currentFont, ptr, strlen(ptr), &dir,
+ &ascent, &descent, &all);
+#endif /* ASSUME_FIXED_WIDTH_PRE */
+
+ if (*start == '\n')
+ {
+ if ((line != NULL)&&(line[0] != '\0'))
+ {
+ SetElement(hw, E_TEXT, currentFont,
+ line_x, *y, line);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = *x - line_x + 1;
+
+ AdjustBaseLine();
+ PF_LF_State = 0;
+
+ line[0] = '\0';
+ }
+
+ HardLineFeed(hw, x, y);
+ line_x = *x;
+ NeedSpace = 0;
+ }
+ else
+ {
+ char *tptr;
+ int tlen;
+
+ if (line == NULL)
+ {
+ tlen = strlen(ptr) + 1;
+ }
+ else
+ {
+ tlen = strlen(line) +
+ strlen(ptr) + 1;
+ }
+ if (tlen > CompLineLen)
+ {
+ CompLineLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompLineLen)
+ {
+ CompLineLen = tlen;
+ }
+ tptr = (char *)malloc(CompLineLen);
+ if (CompLine != NULL)
+ {
+ strcpy(tptr, CompLine);
+ free(CompLine);
+ }
+ else
+ {
+ tptr[0] = '\0';
+ }
+ CompLine = tptr;
+ }
+ line = CompLine;
+
+ strcat(line, ptr);
+
+ *x = *x + all.width;
+ CharsInLine = CharsInLine + strlen(ptr);
+ NeedSpace = 1;
+ }
+ *end = tchar;
+ }
+ }
+ if ((line != NULL)&&(line[0] != '\0'))
+ {
+ SetElement(hw, E_TEXT, currentFont,
+ line_x, *y, line);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = *x - line_x + 1;
+
+ AdjustBaseLine();
+ PF_LF_State = 0;
+ line[0] = '\0';
+ }
+}
+
+
+/*
+ * Format and place a piece of text. Add an element record for it.
+ */
+void
+FormatPlace(hw, mptr, x, y, width)
+ HTMLWidget hw;
+ struct mark_up *mptr;
+ int *x, *y;
+ unsigned int width;
+{
+ char *text;
+ char *start;
+ char *end;
+ char *ptr;
+ char tchar;
+#ifdef DOUBLE_SPACE_AFTER_PUNCT
+ char tchar2;
+#endif /* DOUBLE_SPACE_AFTER_PUNCT */
+ int stripped_space;
+ int added_space;
+ int double_space;
+ int dir, ascent, descent;
+ XCharStruct all;
+ char *line;
+ int line_x;
+
+ text = mptr->text;
+
+ line_x = *x;
+ line = CompLine;
+ if (line != NULL)
+ {
+ line[0] = '\0';
+ }
+ end = text;
+ while (*end != '\0')
+ {
+ /*
+ * make start and end point to one word.
+ * set flag if we removed any leading white space.
+ * set flag if we add any leading white space.
+ */
+ stripped_space = 0;
+ added_space = 0;
+ start = end;
+ while (((int)((unsigned char)*start) < 128)&&(isspace(*start)))
+ {
+ stripped_space = 1;
+ start++;
+ }
+
+ end = start;
+ while (((int)((unsigned char)*end) > 127)||
+ ((!isspace(*end))&&(*end != '\0')))
+ {
+ end++;
+ }
+
+ /*
+ * Add the word to the end of this line, or insert
+ * a linefeed an put the word at the start of the next line.
+ */
+ if (start != end)
+ {
+ int nobreak;
+ int tlen;
+
+ /*
+ * nobreak is a horrible hack that specifies special
+ * conditions where line breaks are just not allowed
+ */
+ nobreak = 0;
+
+ tchar = *end;
+ *end = '\0';
+
+ /*
+ * Malloc temp space if needed, leave room for
+ * 2 spaces and a end of string char
+ */
+ tlen = strlen(start) + 3;
+ if (tlen > CompWordLen)
+ {
+ CompWordLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompWordLen)
+ {
+ CompWordLen = tlen;
+ }
+ if (CompWord != NULL)
+ {
+ free(CompWord);
+ }
+ CompWord = (char *)malloc(CompWordLen);
+ }
+ ptr = CompWord;
+
+ if ((NeedSpace > 0)&&(stripped_space))
+ {
+ if (NeedSpace == 2)
+ {
+ strcpy(ptr, " ");
+ added_space = 2;
+ }
+ else
+ {
+ strcpy(ptr, " ");
+ added_space = 1;
+ }
+ }
+ else
+ {
+ strcpy(ptr, "");
+ }
+ strcat(ptr, start);
+
+#ifdef DOUBLE_SPACE_AFTER_PUNCT
+ /*
+ * If this text ends in '.', '!', or '?' we need
+ * to set up the addition of two spaces after it.
+ */
+ tchar2 = ptr[strlen(ptr) - 1];
+ if ((tchar2 == '.')||(tchar2 == '!')||(tchar2 == '?'))
+ {
+ double_space = 1;
+ }
+ else
+ {
+ double_space = 0;
+ }
+#else
+ double_space = 0;
+#endif /* DOUBLE_SPACE_AFTER_PUNCT */
+
+ XTextExtents(currentFont, ptr, strlen(ptr), &dir,
+ &ascent, &descent, &all);
+
+ /*
+ * Horrible hack for punctuation following
+ * font changes to not go on the next line.
+ */
+ if ((MY_ISPUNCT(*ptr))&&(added_space == 0))
+ {
+ char *tptr;
+
+ /*
+ * Take into account whole streams of
+ * punctuation.
+ */
+ nobreak = 1;
+ tptr = ptr;
+ while ((*tptr != '\0')&&(MY_ISPUNCT(*tptr)))
+ {
+ tptr++;
+ }
+ if (*tptr != '\0')
+ {
+ nobreak = 0;
+ }
+ }
+
+ /*
+ * No linebreaks if this whole line is just too
+ * long.
+ */
+ if (*x == TextIndent)
+ {
+ nobreak = 1;
+ }
+
+ if (((*x + all.width + MarginW) <= width)||(nobreak))
+ {
+ char *tptr;
+ int tlen;
+
+ if (line == NULL)
+ {
+ tlen = strlen(ptr) + 1;
+ }
+ else
+ {
+ tlen = strlen(line) +
+ strlen(ptr) + 1;
+ }
+ if (tlen > CompLineLen)
+ {
+ CompLineLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompLineLen)
+ {
+ CompLineLen = tlen;
+ }
+ tptr = (char *)malloc(CompLineLen);
+ if (CompLine != NULL)
+ {
+ strcpy(tptr, CompLine);
+ free(CompLine);
+ }
+ else
+ {
+ tptr[0] = '\0';
+ }
+ CompLine = tptr;
+ }
+ line = CompLine;
+
+ strcat(line, ptr);
+ }
+ else
+ {
+ char *tptr, *tptr2;
+ int tlen;
+
+ if ((line != NULL)&&(line[0] != '\0'))
+ {
+ SetElement(hw, E_TEXT, currentFont,
+ line_x, *y, line);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = *x - line_x + 1;
+
+ AdjustBaseLine();
+ PF_LF_State = 0;
+
+ line[0] = '\0';
+ }
+
+ LineFeed(hw, x, y);
+ line_x = *x;
+
+ /*
+ * If we added a space before, remove it now
+ * since we are at the beginning of a new line
+ */
+ if (added_space)
+ {
+ tptr2 = (char *)(ptr + added_space);
+ }
+ else
+ {
+ tptr2 = ptr;
+ }
+ XTextExtents(currentFont, tptr2,
+ strlen(tptr2), &dir,
+ &ascent, &descent, &all);
+
+ if (line == NULL)
+ {
+ tlen = strlen(tptr2) + 1;
+ }
+ else
+ {
+ tlen = strlen(line) +
+ strlen(tptr2) + 1;
+ }
+ if (tlen > CompLineLen)
+ {
+ CompLineLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompLineLen)
+ {
+ CompLineLen = tlen;
+ }
+ tptr = (char *)malloc(CompLineLen);
+ if (CompLine != NULL)
+ {
+ strcpy(tptr, CompLine);
+ free(CompLine);
+ }
+ else
+ {
+ tptr[0] = '\0';
+ }
+ CompLine = tptr;
+ }
+ line = CompLine;
+
+ strcat(line, tptr2);
+ }
+
+ /*
+ * Set NeedSpace for one or 2 spaces based on
+ * whether we are after a '.', '!', or '?'
+ * or not.
+ */
+ if (double_space)
+ {
+ NeedSpace = 2;
+ }
+ else
+ {
+ NeedSpace = 1;
+ }
+
+ *x = *x + all.width;
+ *end = tchar;
+ }
+ /*
+ * Else if there is trailing whitespace, add it now
+ */
+ else if ((NeedSpace > 0)&&(stripped_space))
+ {
+ char *tptr;
+ char *spc;
+ int tlen;
+
+ if (NeedSpace == 2)
+ {
+ spc = (char *)malloc(strlen(" ") + 1);
+ strcpy(spc, " ");
+ }
+ else
+ {
+ spc = (char *)malloc(strlen(" ") + 1);
+ strcpy(spc, " ");
+ }
+
+ XTextExtents(currentFont, spc, strlen(spc), &dir,
+ &ascent, &descent, &all);
+
+ /*
+ * Sigh, adding this one little space might force a
+ * line break.
+ */
+ if ((*x + all.width + MarginW) <= width)
+ {
+ if (line == NULL)
+ {
+ tlen = strlen(spc) + 1;
+ }
+ else
+ {
+ tlen = strlen(line) +
+ strlen(spc) + 1;
+ }
+ if (tlen > CompLineLen)
+ {
+ CompLineLen += COMP_LINE_BUF_LEN;
+ if (tlen > CompLineLen)
+ {
+ CompLineLen = tlen;
+ }
+ tptr = (char *)malloc(CompLineLen);
+ if (CompLine != NULL)
+ {
+ strcpy(tptr, CompLine);
+ free(CompLine);
+ }
+ else
+ {
+ tptr[0] = '\0';
+ }
+ CompLine = tptr;
+ }
+ line = CompLine;
+
+ strcat(line, spc);
+ }
+ /*
+ * Ok, the space forced a linefeed, but now we must
+ * also drop the space since we don't want it if we
+ * have a linefeed here.
+ */
+ else
+ {
+ if ((line != NULL)&&(line[0] != '\0'))
+ {
+ SetElement(hw, E_TEXT, currentFont,
+ line_x, *y, line);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = *x - line_x + 1;
+
+ AdjustBaseLine();
+ PF_LF_State = 0;
+
+ line[0] = '\0';
+ }
+
+ LineFeed(hw, x, y);
+ line_x = *x;
+
+ all.width = 0;
+ }
+
+ *x = *x + all.width;
+ if (spc)
+ free(spc);
+ NeedSpace = 0;
+ }
+ }
+ if ((line != NULL)&&(line[0] != '\0'))
+ {
+ SetElement(hw, E_TEXT, currentFont,
+ line_x, *y, line);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = *x - line_x + 1;
+
+ AdjustBaseLine();
+ PF_LF_State = 0;
+ line[0] = '\0';
+ }
+}
+
+
+/*
+ * Place an image. Add an element record for it.
+ */
+void
+ImagePlace(hw, mptr, x, y, width)
+ HTMLWidget hw;
+ struct mark_up *mptr;
+ int *x, *y;
+ unsigned int width;
+{
+ char *tptr;
+
+#ifdef SPACE_HACK
+ /*
+ * If we are starting an image in formatted
+ * text, and it needs a preceeding space, add
+ * that space now.
+ */
+ if ((!Preformat)&&(NeedSpace > 0))
+ {
+ int dir, ascent, descent;
+ XCharStruct all;
+
+ if (NeedSpace == 2)
+ {
+ tptr = (char *)malloc(strlen(" ") + 1);
+ strcpy(tptr, " ");
+ }
+ else
+ {
+ tptr = (char *)malloc(strlen(" ") + 1);
+ strcpy(tptr, " ");
+ }
+
+ XTextExtents(currentFont, tptr,
+ strlen(tptr), &dir, &ascent,
+ &descent, &all);
+ SetElement(hw, E_TEXT, currentFont,
+ *x, *y, tptr);
+ /*
+ * Save width here to avoid an
+ * XTextExtents call later.
+ */
+ Current->width = all.width;
+
+ AdjustBaseLine();
+ *x = *x + all.width;
+ CharsInLine = CharsInLine + strlen(tptr);
+ if (tptr)
+ free(tptr);
+ PF_LF_State = 0;
+ NeedSpace = 0;
+ }
+#endif /* SPACE_HACK */
+
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
+ SetElement(hw, E_IMAGE, currentFont, *x, *y, tptr);
+
+ /*
+ * Only after we have placed the image do we know its dimensions.
+ * So now look and see if the image is too wide, and if so go
+ * back and insert a linebreak.
+ */
+ if ((Current->pic_data != NULL)&&(!Preformat))
+ {
+ int extra;
+
+ if ((hw->html.border_images == True)||
+ ((Current->anchorHRef != NULL)&&
+ (!Current->pic_data->internal)))
+ {
+ extra = 2 * IMAGE_BORDER;
+ }
+ else
+ {
+ extra = 0;
+ }
+
+ if (((*x + Current->pic_data->width + extra + MarginW) >width)&&
+ (Current->prev != NULL)&&
+ (Current->prev->line_number == LineNumber))
+ {
+ Current = Current->prev;
+ LineFeed(hw, x, y);
+ SetElement(hw, E_IMAGE, currentFont, *x, *y, tptr);
+ }
+ }
+ /*
+ * Clean up parsed SRC string
+ */
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ /*
+ * Yank out the name field, and stick it in text.
+ * We may use this for ALT to at some later date.
+ */
+ if (Current->pic_data != NULL)
+ {
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "NAME");
+ Current->pic_data->text = tptr;
+ }
+
+ /*
+ * Check if this image has the ISMAP attribute, so we know the
+ * x,y coordinates of the image click are important.
+ * Due to a special case (see below), this code can acutally
+ * change the size, or anchor status of the image, thus we MUST
+ * doit before we muck with the Baseline and stuff.
+ */
+ if (Current->pic_data != NULL)
+ {
+ Current->pic_data->fptr = NULL;
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "ISMAP");
+ if (tptr != NULL)
+ {
+ free(tptr);
+ Current->pic_data->ismap = 1;
+ /*
+ * SUPER SPECIAL CASE! (Thanks Marc)
+ * If you have an ISMAP image inside a form,
+ * And that form doesn't already have an HREF
+ * by being inside an anchor,
+ * (Being a DelayedHRef is considered no href)
+ * clicking in that image will submit the form,
+ * adding the x,y coordinates of the click as part
+ * of the list of name/value pairs.
+ */
+ if ((CurrentForm != NULL)&&
+ ((Current->anchorHRef == NULL)||
+ (IsDelayedHRef(hw, Current->anchorHRef))))
+ {
+ Current->pic_data->fptr = CurrentForm;
+ Current->anchorHRef = IsMapForm(hw);
+ Current->fg = hw->html.anchor_fg;
+ }
+ }
+ else
+ {
+ Current->pic_data->ismap = 0;
+ }
+ }
+
+ /*
+ * Check if this image will be top aligned
+ */
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "ALIGN");
+ if (caseless_equal(tptr, "TOP"))
+ {
+ Current->alignment = ALIGN_TOP;
+ }
+ else if (caseless_equal(tptr, "MIDDLE"))
+ {
+ Current->alignment = ALIGN_MIDDLE;
+ }
+ else
+ {
+ Current->alignment = ALIGN_BOTTOM;
+ }
+ /*
+ * Clean up parsed ALIGN string
+ */
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ /*
+ * Advance x position, and check the max
+ * line height. We need to follow this
+ * image with a space.
+ */
+ if (Current->pic_data != NULL)
+ {
+ int extra;
+
+ if ((hw->html.border_images == True)||
+ ((Current->anchorHRef != NULL)&&
+ (!Current->pic_data->internal)))
+ {
+ extra = 2 * IMAGE_BORDER;
+ }
+ else
+ {
+ extra = 0;
+ }
+
+ if (BaseLine == -100)
+ {
+ BaseLine = 0;
+ }
+
+ *x = *x + Current->pic_data->width + extra;
+
+ if (Current->alignment == ALIGN_TOP)
+ {
+ Current->y_offset = 0;
+
+ if ((Current->pic_data->height + extra - BaseLine) >
+ LineBottom)
+ {
+ LineBottom = Current->pic_data->height + extra -
+ BaseLine;
+ }
+ }
+ else if (Current->alignment == ALIGN_MIDDLE)
+ {
+ int baseline;
+
+ baseline = (Current->pic_data->height + extra) / 2;
+
+ if (baseline <= BaseLine)
+ {
+ Current->y_offset = BaseLine - baseline;
+ }
+ else
+ {
+ struct ele_rec *eptr;
+ int line, incy;
+
+ Current->y_offset = 0;
+
+ incy = baseline - BaseLine;
+ BaseLine = baseline;
+
+ /*
+ * Go back over this line
+ * and move everything down
+ * a little.
+ */
+ eptr = Current;
+ line = eptr->line_number;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->line_number == line))
+ {
+ eptr = eptr->prev;
+ eptr->y_offset = eptr->y_offset + incy;
+ }
+ }
+
+ if ((Current->pic_data->height + extra - BaseLine) >
+ LineBottom)
+ {
+ LineBottom = Current->pic_data->height + extra -
+ BaseLine;
+ }
+ }
+ else if ((Current->pic_data->height + extra) <= BaseLine)
+ {
+ Current->y_offset = BaseLine -
+ (Current->pic_data->height + extra);
+ }
+ else if ((Current->pic_data->height + extra) > BaseLine)
+ {
+ struct ele_rec *eptr;
+ int line, incy;
+
+ incy = Current->pic_data->height + extra - BaseLine;
+ BaseLine = Current->pic_data->height + extra;
+
+ /*
+ * Go back over this line
+ * and move everything down
+ * a little.
+ */
+ eptr = Current;
+ line = eptr->line_number;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->line_number == line))
+ {
+ eptr = eptr->prev;
+ eptr->y_offset = eptr->y_offset + incy;
+ }
+ }
+
+ if (BaseLine == 0)
+ {
+ BaseLine = -100;
+ }
+ }
+ PF_LF_State = 0;
+ NeedSpace = 1;
+}
+
+
+/*
+ * Place an Widget. Add an element record for it.
+ */
+void
+WidgetPlace(hw, mptr, x, y, width)
+ HTMLWidget hw;
+ struct mark_up *mptr;
+ int *x, *y;
+ unsigned int width;
+{
+ SetElement(hw, E_WIDGET, currentFont, *x, *y, mptr->start);
+
+ /*
+ * Only after we have placed the widget do we know its dimensions.
+ * So now look and see if the widget is too wide, and if so go
+ * back and insert a linebreak.
+ */
+ if ((Current->widget_data != NULL)&&(!Preformat))
+ {
+ int extra;
+
+ extra = 2 * IMAGE_BORDER;
+
+ if (((*x + Current->widget_data->width + extra + MarginW) >
+ width)&&
+ (Current->prev != NULL)&&
+ (Current->prev->line_number == LineNumber))
+ {
+ WidgetId--;
+ Current = Current->prev;
+ LineFeed(hw, x, y);
+ SetElement(hw, E_WIDGET, currentFont, *x, *y,
+ mptr->start);
+ }
+ }
+
+ /*
+ * Advance x position, and check BaseLine and LineBottom.
+ * We need to follow this widget with a space.
+ */
+ if (Current->widget_data != NULL)
+ {
+ int extra;
+ int baseline;
+ XFontStruct *fp;
+
+ extra = 2 * IMAGE_BORDER;
+
+ /*
+ * Find the font used in this widget. Then find its baseline
+ */
+ fp = GetWidgetFont(hw, Current->widget_data);
+ if (fp == NULL)
+ {
+ baseline = Current->widget_data->height + extra;
+ }
+ /*
+ * If no font, the baseline is the bottum of the widget
+ */
+ else
+ {
+ int border;
+
+ border = ((Current->widget_data->height + extra) -
+ (fp->max_bounds.ascent + fp->max_bounds.descent));
+ baseline = (border / 2) + fp->max_bounds.ascent;
+ }
+
+ /*
+ * Baseline == -100 is the special unset baseline value.
+ */
+ if (BaseLine == -100)
+ {
+ BaseLine = baseline;
+ Current->y_offset = 0;
+ /*
+ * If linebottom isn't set, set it to
+ * whatever of the height is below the baseline.
+ */
+ if (LineBottom == 0)
+ {
+ LineBottom = Current->widget_data->height +
+ extra - baseline;
+ }
+ /*
+ * Else, it is possible that a linebottom has been
+ * set even when we have no baseline yet (like if
+ * the first item in the line was a top aligned image)
+ * It now needs to be corrected as we set a real
+ * BaseLine.
+ */
+ else
+ {
+ if ((Current->widget_data->height +
+ extra - baseline) >
+ (LineBottom - baseline))
+ {
+ LineBottom =
+ Current->widget_data->height +
+ extra - baseline;
+ }
+ else
+ {
+ LineBottom = LineBottom - baseline;
+ }
+ }
+ }
+ /*
+ * Else we already have a baseline, and it is greater that
+ * the baseline for this widget.
+ * Set y_offset, and check linebottom.
+ */
+ else if (baseline <= BaseLine)
+ {
+ if (baseline < BaseLine)
+ {
+ Current->y_offset = BaseLine - baseline;
+ }
+ else
+ {
+ Current->y_offset = 0;
+ }
+
+ /*
+ * Our line bottom may be greater than the
+ * old one.
+ */
+ if ((Current->widget_data->height + extra - baseline) >
+ LineBottom)
+ {
+ LineBottom = Current->widget_data->height +
+ extra - baseline;
+ }
+ }
+ else
+ /*
+ * Else we have a new baseline greater than the old baseline.
+ */
+ {
+ struct ele_rec *eptr;
+ int line, incy;
+
+ /*
+ * Figure out how much to move all the old stuff
+ */
+ incy = baseline - BaseLine;
+ BaseLine = baseline;
+
+ /*
+ * Go back over this line
+ * and move everything down
+ * a little.
+ */
+ eptr = Current;
+ line = eptr->line_number;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->line_number == line))
+ {
+ eptr = eptr->prev;
+ eptr->y_offset = eptr->y_offset + incy;
+ }
+
+ /*
+ * Our line bottom may be greater than the
+ * old one.
+ */
+ if ((Current->widget_data->height + extra - baseline) >
+ LineBottom)
+ {
+ LineBottom = Current->widget_data->height +
+ extra - baseline;
+ }
+ }
+
+ /*
+ * Advance the X position.
+ */
+ *x = *x + Current->widget_data->width + extra;
+ }
+ PF_LF_State = 0;
+ NeedSpace = 1;
+}
+
+
+static void
+PushFont(font)
+ XFontStruct *font;
+{
+ FontRec *fptr;
+
+ fptr = (FontRec *)malloc(sizeof(FontRec));
+ if (fptr == NULL)
+ {
+ fprintf(stderr, "No memory to expand font stack!\n");
+ return;
+ }
+
+ fptr->font = font;
+ fptr->next = FontStack;
+ FontStack = fptr;
+}
+
+
+static XFontStruct *
+PopFont()
+{
+ XFontStruct *font;
+ FontRec *fptr;
+
+ if (FontStack->next != NULL)
+ {
+ fptr = FontStack;
+ FontStack = FontStack->next;
+ font = fptr->font;
+ free((char *)fptr);
+ }
+ else
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "Warning, popping empty font stack!\n");
+#endif
+ font = FontStack->font;
+ }
+
+ return(font);
+}
+
+
+/*
+ * We've just terminated the current OPTION.
+ * Put it in the proper place in the SelectInfo structure.
+ * Move option_buf into options, and maybe copy into
+ * value if is_value is set.
+ */
+static void
+ProcessOption(sptr)
+ SelectInfo *sptr;
+{
+ int i, cnt;
+ char **tarray;
+
+ clean_white_space(sptr->option_buf);
+ tarray = sptr->options;
+ cnt = sptr->option_cnt + 1;
+ sptr->options = (char **)malloc(sizeof(char *) * cnt);
+ for (i=0; i<(cnt - 1); i++)
+ {
+ sptr->options[i] = tarray[i];
+ }
+ if (tarray != NULL)
+ {
+ free((char *)tarray);
+ }
+ sptr->options[cnt - 1] = sptr->option_buf;
+ sptr->option_cnt = cnt;
+
+ tarray = sptr->returns;
+ cnt = sptr->option_cnt;
+ sptr->returns = (char **)malloc(sizeof(char *) * cnt);
+ for (i=0; i<(cnt - 1); i++)
+ {
+ sptr->returns[i] = tarray[i];
+ }
+ if (tarray != NULL)
+ {
+ free((char *)tarray);
+ }
+ sptr->returns[cnt - 1] = sptr->retval_buf;
+
+ if (sptr->is_value)
+ {
+ tarray = sptr->value;
+ cnt = sptr->value_cnt + 1;
+ sptr->value = (char **)malloc(sizeof(char *) * cnt);
+ for (i=0; i<(cnt - 1); i++)
+ {
+ sptr->value[i] = tarray[i];
+ }
+ if (tarray != NULL)
+ {
+ free((char *)tarray);
+ }
+ sptr->value[cnt - 1] = (char *)malloc(
+ strlen(sptr->option_buf) + 1);
+ strcpy(sptr->value[cnt - 1], sptr->option_buf);
+ sptr->value_cnt = cnt;
+ }
+}
+
+
+/*
+ * Horrible code for the TEXTAREA element. Escape '\' and ''' by
+ * putting a '\' in front of them, then replace all '"' with '''.
+ * This lets us safely put the resultant value between double quotes.
+ */
+char *
+TextAreaAddValue(value, text)
+ char *value;
+ char *text;
+{
+ int extra;
+ char *buf;
+ char *bptr;
+ char *tptr;
+
+ if ((text == NULL)||(text[0] == '\0'))
+ {
+ return(value);
+ }
+
+ extra = 0;
+ tptr = text;
+ while (*tptr != '\0')
+ {
+ if (*tptr == '\\')
+ {
+ extra++;
+ }
+ else if (*tptr == '\'')
+ {
+ extra++;
+ }
+ tptr++;
+ }
+
+ buf = (char *)malloc(strlen(value) + strlen(text) + extra + 1);
+ if (buf == NULL)
+ {
+ return(value);
+ }
+ strcpy(buf, value);
+
+ tptr = text;
+ bptr = (char *)(buf + strlen(value));
+ while (*tptr != '\0')
+ {
+ if ((*tptr == '\\')||(*tptr == '\''))
+ {
+ *bptr++ = '\\';
+ *bptr++ = *tptr++;
+ }
+ else if (*tptr == '\"')
+ {
+ *bptr++ = '\'';
+ tptr++;
+ }
+ else
+ {
+ *bptr++ = *tptr++;
+ }
+ }
+ *bptr = '\0';
+
+ free(value);
+ return(buf);
+}
+
+
+/*
+ * Make necessary changes to formatting, based on the type of the
+ * parsed HTML text we are formatting.
+ * Some calls create elements that are added to the formatted element list.
+ */
+void
+TriggerMarkChanges(hw, mptr, x, y)
+ HTMLWidget hw;
+ struct mark_up *mptr;
+ int *x, *y;
+{
+ struct mark_up *mark;
+ XFontStruct *font;
+ int type, width;
+
+ mark = mptr;
+ type = mark->type;
+ font = NULL;
+
+ /*
+ * If Ignore is set, we ignore all further elements until we get to the
+ * end of the Ignore
+ * Let text through so we can grab the title text.
+ * Let title through so we can hit the end title.
+ * Now also used for SELECT parseing
+ * Let SELECT through so we can hit the end SELECT.
+ * Let OPTION through so we can hit the OPTIONs.
+ * Let TEXTAREA through so we can hit the TEXTAREAs.
+ */
+ if ((Ignore)&&(type != M_TITLE)&&(type != M_NONE)&&
+ (type != M_SELECT)&&(type != M_OPTION)&&
+ (type != M_TEXTAREA))
+ {
+ return;
+ }
+
+ switch(type)
+ {
+ /*
+ * Place the text. Different functions based on whether it
+ * is pre-formatted or not.
+ */
+ case M_NONE:
+ if ((Ignore)&&(CurrentSelect == NULL)&&
+ (TextAreaBuf == NULL))
+ {
+ if (TitleText == NULL)
+ {
+ TitleText = (char *)
+ malloc(strlen(mptr->text) + 1);
+ strcpy(TitleText, mptr->text);
+ }
+ else
+ {
+ char *tptr;
+
+ tptr = (char *)
+ malloc(strlen(TitleText) +
+ strlen(mptr->text) + 1);
+ strcpy(tptr, TitleText);
+ strcat(tptr, mptr->text);
+ free(TitleText);
+ TitleText = tptr;
+ }
+ }
+ else if ((Ignore)&&(CurrentSelect != NULL))
+ {
+ if (CurrentSelect->option_buf != NULL)
+ {
+ char *tptr;
+
+ tptr = (char *)malloc(strlen(
+ CurrentSelect->option_buf) +
+ strlen(mptr->text) + 1);
+ strcpy(tptr, CurrentSelect->option_buf);
+ strcat(tptr, mptr->text);
+ free(CurrentSelect->option_buf);
+ CurrentSelect->option_buf = tptr;
+ }
+ }
+ else if ((Ignore)&&(TextAreaBuf != NULL))
+ {
+ TextAreaBuf = TextAreaAddValue(TextAreaBuf,
+ mptr->text);
+ }
+ else if (Preformat)
+ {
+ PreformatPlace(hw, mptr, x, y, Width);
+ }
+ else
+ {
+ FormatPlace(hw, mptr, x, y, Width);
+ }
+ break;
+ /*
+ * Titles are just set into the widget for retrieval by
+ * XtGetValues().
+ */
+ case M_TITLE:
+ if (mark->is_end)
+ {
+ Ignore = 0;
+ hw->html.title = TitleText;
+ TitleText = NULL;
+ }
+ else
+ {
+ Ignore = 1;
+ TitleText = NULL;
+ }
+ break;
+ /*
+ * Formatting commands just change the current font.
+ */
+ case M_CODE:
+ case M_SAMPLE:
+ case M_KEYBOARD:
+ case M_FIXED:
+ if (mark->is_end)
+ {
+ font = PopFont();
+ }
+ else
+ {
+ PushFont(currentFont);
+ font = hw->html.fixed_font;
+ }
+ break;
+ case M_STRONG:
+ case M_BOLD:
+ if (mark->is_end)
+ {
+ font = PopFont();
+ }
+ else
+ {
+ PushFont(currentFont);
+ if (currentFont == hw->html.fixed_font ||
+ currentFont == hw->html.fixeditalic_font)
+ font = hw->html.fixedbold_font;
+ else if (currentFont == hw->html.plain_font ||
+ currentFont == hw->html.plainitalic_font)
+ font = hw->html.plainbold_font;
+ else
+ font = hw->html.bold_font;
+ }
+ break;
+ case M_EMPHASIZED:
+ case M_VARIABLE:
+ case M_CITATION:
+ case M_ITALIC:
+ if (mark->is_end)
+ {
+ font = PopFont();
+ }
+ else
+ {
+ PushFont(currentFont);
+ if (currentFont == hw->html.fixed_font ||
+ currentFont == hw->html.fixedbold_font)
+ font = hw->html.fixeditalic_font;
+ else if (currentFont == hw->html.plain_font ||
+ currentFont == hw->html.plainbold_font)
+ font = hw->html.plainitalic_font;
+ else
+ font = hw->html.italic_font;
+ }
+ break;
+ /*
+ * Strikeout means draw a line through the text.
+ * Right now we just set a boolean flag which gets shoved
+ * in the element record for all elements in the
+ * strikeout zone.
+ */
+ case M_STRIKEOUT:
+ if (mark->is_end)
+ {
+ Strikeout = False;
+ }
+ else
+ {
+ Strikeout = True;
+ }
+ break;
+ /*
+ * Headers are preceeded and followed by a linefeed,
+ * and the change the font.
+ */
+ case M_HEADER_1:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header1_font;
+ }
+ break;
+ case M_HEADER_2:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header2_font;
+ }
+ break;
+ case M_HEADER_3:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header3_font;
+ }
+ break;
+ case M_HEADER_4:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header4_font;
+ }
+ break;
+ case M_HEADER_5:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header5_font;
+ }
+ break;
+ case M_HEADER_6:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ PushFont(currentFont);
+ font = hw->html.header6_font;
+ }
+ break;
+ /*
+ * Anchors change the text color, and may set
+ * underlineing attributes.
+ * No linefeeds, so they can be imbedded anywhere.
+ */
+ case M_ANCHOR:
+ if (mark->is_end)
+ {
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ Fg = hw->manager.foreground;
+#else
+ Fg = hw->html.foreground;
+#endif /* MOTIF */
+ Underlines = 0;
+ DashedUnderlines = False;
+ AnchorText = NULL;
+ }
+ else
+ {
+ char *tptr;
+
+ /*
+ * Only change the color of anchors with
+ * HREF tags, because other anchors are
+ * not active.
+ */
+ tptr = ParseMarkTag(mark->start,
+ MT_ANCHOR, AT_HREF);
+ if (tptr != NULL)
+ {
+ /*
+ * If internal check our internal list
+ * to change color if visited before.
+ */
+ if (Internal == True)
+ {
+ struct ref_rec *hptr;
+
+ hptr = FindHRef(
+ hw->html.my_visited_hrefs,
+ tptr);
+ if (hptr != NULL)
+ {
+ Fg = hw->html.visitedAnchor_fg;
+ Underlines = hw->html.num_visitedAnchor_underlines;
+ DashedUnderlines = hw->html.dashed_visitedAnchor_lines;
+ }
+ else
+ {
+ Fg = hw->html.anchor_fg;
+ Underlines = hw->html.num_anchor_underlines;
+ DashedUnderlines = hw->html.dashed_anchor_lines;
+ }
+ }
+ /*
+ * Else we may want to send
+ * the href back somewhere else and
+ * find out if we've visited it before
+ */
+ else if (hw->html.previously_visited_test !=
+ NULL)
+ {
+ if ((*(visitTestProc)
+ (hw->html.previously_visited_test))
+ (hw, hw->html.vt_client_data, tptr))
+ {
+ Fg = hw->html.visitedAnchor_fg;
+ Underlines = hw->html.num_visitedAnchor_underlines;
+ DashedUnderlines = hw->html.dashed_visitedAnchor_lines;
+ }
+ else
+ {
+ Fg = hw->html.anchor_fg;
+ Underlines = hw->html.num_anchor_underlines;
+ DashedUnderlines = hw->html.dashed_anchor_lines;
+ }
+ }
+ else
+ {
+ Fg = hw->html.anchor_fg;
+ Underlines = hw->html.num_anchor_underlines;
+ DashedUnderlines = hw->html.dashed_anchor_lines;
+ }
+ if (tptr)
+ free(tptr);
+ }
+ AnchorText = mark->start;
+ }
+ break;
+ /*
+ * Just insert a linefeed, or ignore if this is prefomatted
+ * text because the <P> will be followed be a linefeed.
+ */
+ case M_PARAGRAPH:
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ break;
+ /*
+ * Just insert the image for now
+ */
+ case M_IMAGE:
+ ImagePlace(hw, mptr, x, y, Width);
+ break;
+ /*
+ * Can only be inside a SELECT tag.
+ */
+ case M_OPTION:
+ if (CurrentSelect != NULL)
+ {
+ char *tptr;
+
+ if (CurrentSelect->option_buf != NULL)
+ {
+ ProcessOption(CurrentSelect);
+ }
+ CurrentSelect->option_buf = (char *)malloc(1);
+ strcpy(CurrentSelect->option_buf, "");
+
+ /*
+ * Check if this option starts selected
+ */
+ tptr = ParseMarkTag(mark->start,
+ MT_OPTION, "SELECTED");
+ if (tptr != NULL)
+ {
+ CurrentSelect->is_value = 1;
+ free(tptr);
+ }
+ else
+ {
+ CurrentSelect->is_value = 0;
+ }
+
+ /*
+ * Check if this option has an different
+ * return value field.
+ */
+ tptr = ParseMarkTag(mark->start,
+ MT_OPTION, "VALUE");
+ if (tptr != NULL)
+ {
+ if (*tptr != '\0')
+ {
+ CurrentSelect->retval_buf = tptr;
+ }
+ else
+ {
+ CurrentSelect->retval_buf = NULL;
+ free(tptr);
+ }
+ }
+ else
+ {
+ CurrentSelect->retval_buf = NULL;
+ }
+ }
+ break;
+ /*
+ * Special INPUT tag. Allows an option menu or
+ * a scrolled list.
+ * Due to a restriction in SGML, this can't just be a
+ * subset of the INPUT markup. However, I can treat it
+ * that way to avoid duplicating code.
+ * As a result I combine SELECT and OPTION into a faked
+ * up INPUT mark.
+ */
+ case M_SELECT:
+ if (CurrentForm != NULL)
+ {
+ if ((mark->is_end)&&(CurrentSelect != NULL))
+ {
+ int len;
+ char *buf;
+ char *start;
+ char *options, *returns, *value;
+
+ if (CurrentSelect->option_buf != NULL)
+ {
+ ProcessOption(CurrentSelect);
+ }
+
+ options = ComposeCommaList(
+ CurrentSelect->options,
+ CurrentSelect->option_cnt);
+ returns = ComposeCommaList(
+ CurrentSelect->returns,
+ CurrentSelect->option_cnt);
+ value = ComposeCommaList(
+ CurrentSelect->value,
+ CurrentSelect->value_cnt);
+ FreeCommaList(
+ CurrentSelect->options,
+ CurrentSelect->option_cnt);
+ FreeCommaList(
+ CurrentSelect->returns,
+ CurrentSelect->option_cnt);
+ FreeCommaList(
+ CurrentSelect->value,
+ CurrentSelect->value_cnt);
+
+ /*
+ * Construct a fake INPUT tag.
+ */
+ len = strlen(MT_INPUT) +
+ strlen(options) +
+ strlen(returns) +
+ strlen(value) + strlen(
+ " type=select options=\"\" returns=\"\" value=\"\"");
+ buf = (char *)malloc(len +
+ strlen(CurrentSelect->mptr->start)
+ + 1);
+ strcpy(buf, MT_INPUT);
+ strcat(buf, " type=select");
+ strcat(buf, " options=\"");
+ strcat(buf, options);
+ strcat(buf, "\" returns=\"");
+ strcat(buf, returns);
+ strcat(buf, "\" value=\"");
+ strcat(buf, value);
+ strcat(buf, "\"");
+ strcat(buf, (char *)
+ (CurrentSelect->mptr->start +
+ strlen(MT_SELECT)));
+ /*
+ * stick the fake in, saving the
+ * real one.
+ */
+ start = CurrentSelect->mptr->start;
+ CurrentSelect->mptr->start = buf;
+ WidgetPlace(hw, CurrentSelect->mptr,
+ x, y, Width);
+ /*
+ * free the fake, put the original back
+ */
+ free(buf);
+ free(options);
+ free(returns);
+ free(value);
+ CurrentSelect->mptr->start = start;
+
+ free((char *)CurrentSelect);
+ CurrentSelect = NULL;
+ Ignore = 0;
+ }
+ else if ((!mark->is_end)&&(CurrentSelect == NULL))
+ {
+ CurrentSelect = (SelectInfo *)malloc(
+ sizeof(SelectInfo));
+ CurrentSelect->hw = (Widget)hw;
+ CurrentSelect->mptr = mptr;
+ CurrentSelect->option_cnt = 0;
+ CurrentSelect->returns = NULL;
+ CurrentSelect->retval_buf = NULL;
+ CurrentSelect->options = NULL;
+ CurrentSelect->option_buf = NULL;
+ CurrentSelect->value_cnt = 0;
+ CurrentSelect->value = NULL;
+ CurrentSelect->is_value = -1;
+ Ignore = 1;
+ }
+ }
+ break;
+ /*
+ * TEXTAREA is a replacement for INPUT type=text size=rows,cols
+ * because SGML will not allow an arbitrary length value
+ * field.
+ */
+ case M_TEXTAREA:
+ if (CurrentForm != NULL)
+ {
+ if ((mark->is_end)&&(TextAreaBuf != NULL))
+ {
+ char *start;
+ char *buf;
+
+ /*
+ * Finish a fake INPUT tag.
+ */
+ buf = (char *)malloc(
+ strlen(TextAreaBuf) + 2);
+ strcpy(buf, TextAreaBuf);
+ strcat(buf, "\"");
+
+ /*
+ * stick the fake in, saving the
+ * real one.
+ */
+ start = mark->start;
+ mark->start = buf;
+ mark->is_end = 0;
+ WidgetPlace(hw, mark, x, y, Width);
+
+ /*
+ * free the fake, put the original back
+ */
+ free(buf);
+ free(TextAreaBuf);
+ mark->start = start;
+ mark->is_end = 1;
+ TextAreaBuf = NULL;
+ Ignore = 0;
+ }
+ else if ((!mark->is_end)&&(TextAreaBuf == NULL))
+ {
+ char *buf;
+ int len;
+
+ /*
+ * Construct the start of
+ * a fake INPUT tag.
+ */
+ len = strlen(MT_INPUT) +
+ strlen(
+ " type=textarea value=\"\"");
+ buf = (char *)malloc(len +
+ strlen(mark->start)
+ + 1);
+ strcpy(buf, MT_INPUT);
+ strcat(buf, (char *)
+ (mark->start +
+ strlen(MT_TEXTAREA)));
+ strcat(buf, " type=textarea");
+ strcat(buf, " value=\"");
+
+ TextAreaBuf = buf;
+ Ignore = 1;
+ }
+ }
+ break;
+ /*
+ * Just insert the widget.
+ * Can only inside a FORM tag.
+ * Special case the type=image stuff to become a special
+ * IMG tag.
+ */
+ case M_INPUT:
+ if (CurrentForm != NULL)
+ {
+ char *tptr;
+ char *tptr2;
+
+ tptr = ParseMarkTag(mptr->start,
+ MT_INPUT, "TYPE");
+ if ((tptr != NULL)&&
+ (strcmp(tptr, "image") == 0))
+ {
+ free(tptr);
+ tptr = (char *)malloc(
+ strlen(mptr->start) +
+ strlen(" ISMAP") +
+ strlen(MT_IMAGE) -
+ strlen(MT_INPUT) + 1);
+ strcpy(tptr, MT_IMAGE);
+ strcat(tptr, (char *)
+ (mptr->start + strlen(MT_INPUT))
+ );
+ strcat(tptr, " ISMAP");
+ tptr2 = mptr->start;
+ mptr->start = tptr;
+ ImagePlace(hw, mptr, x, y, Width);
+ mptr->start = tptr2;
+ free(tptr);
+ }
+ /*
+ * hidden inputs have no element associated
+ * with them, just a widget record.
+ */
+ else if ((tptr != NULL)&&
+ (strcmp(tptr, "hidden") == 0))
+ {
+ free(tptr);
+ WidgetId++;
+ (void)MakeWidget(hw, mptr->start, x, y,
+ WidgetId, CurrentForm);
+ }
+ else
+ {
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+ WidgetPlace(hw, mptr, x, y, Width);
+ }
+ }
+ break;
+ /*
+ * Fillout forms. Cannot be nested.
+ */
+ case M_FORM:
+ ConditionalLineFeed(hw, x, y, 1);
+ if ((mark->is_end)&&(CurrentForm != NULL))
+ {
+ CurrentForm->end = WidgetId;
+ ConditionalLineFeed(hw, x, y, 2);
+ AddNewForm(hw, CurrentForm);
+ CurrentForm = NULL;
+ }
+ else if ((!mark->is_end)&&(CurrentForm == NULL))
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ CurrentForm = (FormInfo *)malloc(
+ sizeof(FormInfo));
+ CurrentForm->next = NULL;
+ CurrentForm->hw = (Widget)hw;
+ CurrentForm->action = ParseMarkTag(mark->start,
+ MT_FORM, "ACTION");
+ CurrentForm->method = ParseMarkTag(mark->start,
+ MT_FORM, "METHOD");
+ CurrentForm->enctype = ParseMarkTag(mark->start,
+ MT_FORM, "ENCTYPE");
+ CurrentForm->enc_entity = ParseMarkTag(
+ mark->start, MT_FORM, "ENCENTITY");
+ CurrentForm->start = WidgetId;
+ CurrentForm->end = -1;
+ }
+ break;
+ /*
+ * Addresses are just like headers. A linefeed before and
+ * after, and change the font.
+ */
+ case M_ADDRESS:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ font = PopFont();
+ }
+ else
+ {
+ PushFont(currentFont);
+ font = hw->html.address_font;
+ }
+ break;
+ /*
+ * Blockquotes increase the margin width.
+ * They cannot be nested.
+ */
+ case M_BLOCKQUOTE:
+ ConditionalLineFeed(hw, x, y, 1);
+ if (mark->is_end)
+ {
+ MarginW = hw->html.margin_width;
+ /*
+ * Only unindent if we think we indented
+ * when we started the blockquote
+ */
+ if (TextIndent <= (2 * MarginW))
+ {
+ TextIndent = MarginW;
+ }
+ ConditionalLineFeed(hw, x, y, 2);
+ /*
+ * The linefeed should have set x to TextIndent
+ * but since it is conditional, it might not
+ * have, so check it here.
+ */
+ if (*x > TextIndent)
+ {
+ *x = TextIndent;
+ }
+ }
+ else
+ {
+ MarginW = 2 * hw->html.margin_width;
+ /*
+ * Only indent if the current indent
+ * is less than what we want.
+ */
+ if (TextIndent < MarginW)
+ {
+ TextIndent = MarginW;
+ }
+ ConditionalLineFeed(hw, x, y, 2);
+ /*
+ * The linefeed should have set x to TextIndent
+ * but since it is conditional, it might not
+ * have, so check it here.
+ */
+ if (*x < TextIndent)
+ {
+ *x = TextIndent;
+ }
+ }
+ break;
+ /*
+ * Plain text. A single pre-formatted chunk of text
+ * in its own font.
+ */
+ case M_PLAIN_TEXT:
+ if (mark->is_end)
+ {
+ Preformat = 0;
+ /*
+ * Properly convert the Linefeed state
+ * variable from preformat to formatted
+ * state.
+ */
+ if (PF_LF_State == 2)
+ {
+ PF_LF_State = 1;
+ }
+ else
+ {
+ PF_LF_State = 0;
+ }
+ ConditionalLineFeed(hw, x, y, 1);
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ Preformat = 1;
+ PF_LF_State = 0;
+ PushFont(currentFont);
+ font = hw->html.plain_font;
+ }
+ break;
+ /*
+ * Listing text. A different pre-formatted chunk of text
+ * in its own font.
+ */
+ case M_LISTING_TEXT:
+ if (mark->is_end)
+ {
+ Preformat = 0;
+ /*
+ * Properly convert the Linefeed state
+ * variable from preformat to formatted
+ * state.
+ */
+ if (PF_LF_State == 2)
+ {
+ PF_LF_State = 1;
+ }
+ else
+ {
+ PF_LF_State = 0;
+ }
+ ConditionalLineFeed(hw, x, y, 1);
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ Preformat = 1;
+ PF_LF_State = 0;
+ PushFont(currentFont);
+ font = hw->html.listing_font;
+ }
+ break;
+ /*
+ * Plain text. The rest of the text is pre-formatted.
+ * There is not end for this mark.
+ */
+ case M_PLAIN_FILE:
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ Preformat = 1;
+ PF_LF_State = 0;
+ PushFont(currentFont);
+ font = hw->html.plain_font;
+ break;
+ /*
+ * Numbered lists, Unnumbered lists, Menus.
+ * Currently also lump directory listings into this.
+ * Save state for each indent level.
+ * Change the value of the TxtIndent (can be nested)
+ * Linefeed at the end of the list.
+ */
+ case M_NUM_LIST:
+ case M_UNUM_LIST:
+ case M_MENU:
+ case M_DIRECTORY:
+ ConditionalLineFeed(hw, x, y, 1);
+ width = hw->html.font->max_bounds.width;
+ /*
+ * If this is the outermost level of indentation,
+ * add another linefeed for more white space.
+ */
+ if ((TextIndent <= MarginW)||((mark->is_end)&&
+ ((TextIndent - ((INDENT_SPACES + 1) * width)) <=
+ MarginW)))
+ {
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ if (mark->is_end)
+ {
+ TextIndent = TextIndent -
+ ((INDENT_SPACES + 1) * width);
+ if (TextIndent < MarginW)
+ {
+ TextIndent = MarginW;
+ }
+ IndentLevel--;
+ if (IndentLevel < 0)
+ {
+ IndentLevel = 0;
+ }
+
+ /*
+ * restore the old state if there is one
+ */
+ if (ListData->next != NULL)
+ {
+ DescRec *dptr;
+
+ dptr = ListData;
+ ListData = ListData->next;
+ free((char *)dptr);
+ }
+ }
+ else
+ {
+ DescRec *dptr;
+
+ dptr = (DescRec *)malloc(sizeof(DescRec));
+ /*
+ * Save the old state, and start a new
+ */
+ if (type == M_NUM_LIST)
+ {
+ dptr->type = D_OLIST;
+ dptr->count = 1;
+ }
+ else
+ {
+ dptr->type = D_ULIST;
+ dptr->count = 0;
+ }
+ dptr->next = ListData;
+ ListData = dptr;
+
+ TextIndent = TextIndent +
+ ((INDENT_SPACES + 1) * width);
+ IndentLevel++;
+ }
+ *x = TextIndent;
+ break;
+ /*
+ * Place the bullet element at the beginning of this item.
+ */
+ case M_LIST_ITEM:
+ if (!mark->is_end)
+ {
+ ConditionalLineFeed(hw, x, y, 1);
+ /*
+ * for ordered/numbered lists
+ * put numbers in place of bullets.
+ */
+ if (ListData->type == D_OLIST)
+ {
+ ListNumberPlace(hw, x, y,
+ ListData->count);
+ ListData->count++;
+ }
+ else
+ {
+ BulletPlace(hw, x, y);
+ }
+ }
+ break;
+ /*
+ * Description lists
+ */
+ case M_DESC_LIST:
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ width = hw->html.font->max_bounds.width;
+ if (mark->is_end)
+ {
+ if (DescType->type == D_TEXT)
+ {
+ TextIndent = TextIndent -
+ ((INDENT_SPACES + 1) * width);
+ if (TextIndent < MarginW)
+ {
+ TextIndent = MarginW;
+ }
+ }
+ /*
+ * restore the old state if there is one
+ */
+ if (DescType->next != NULL)
+ {
+ DescRec *dptr;
+
+ dptr = DescType;
+ DescType = DescType->next;
+ free((char *)dptr);
+ /*
+ * If the old state had forced an
+ * indent, outdent it now.
+ */
+ if (DescType->type == D_TITLE)
+ {
+ TextIndent = TextIndent -
+ ((INDENT_SPACES + 1) * width);
+ if (TextIndent < MarginW)
+ {
+ TextIndent = MarginW;
+ }
+ }
+ }
+ }
+ else
+ {
+ DescRec *dptr;
+ char *tptr;
+
+ dptr = (DescRec *)malloc(sizeof(DescRec));
+ /*
+ * Check is this is a compact list
+ */
+ tptr = ParseMarkTag(mark->start,
+ MT_DESC_LIST, "COMPACT");
+ if (tptr != NULL)
+ {
+ free(tptr);
+ dptr->compact = 1;
+ }
+ else
+ {
+ dptr->compact = 0;
+ }
+ /*
+ * Description list stared after a title needs
+ * a forced indentation here
+ */
+ if (DescType->type == D_TITLE)
+ {
+ TextIndent = TextIndent +
+ ((INDENT_SPACES + 1) * width);
+ }
+ /*
+ * Save the old state, and start a new
+ */
+ dptr->type = D_TITLE;
+ dptr->next = DescType;
+ DescType = dptr;
+ }
+ *x = TextIndent;
+ break;
+ case M_DESC_TITLE:
+ ConditionalLineFeed(hw, x, y, 1);
+ width = hw->html.font->max_bounds.width;
+ /*
+ * Special hack. Don't indent again for
+ * multiple <dt>'s in a row.
+ */
+ if (DescType->type == D_TEXT)
+ {
+ TextIndent = TextIndent -
+ ((INDENT_SPACES + 1) * width);
+ if (TextIndent < MarginW)
+ {
+ TextIndent = MarginW;
+ }
+ }
+ DescType->type = D_TITLE;
+ *x = TextIndent;
+ break;
+ case M_DESC_TEXT:
+ width = hw->html.font->max_bounds.width;
+
+ /*
+ * For a compact list we want to stay on the same
+ * line if there is room and we are the first line
+ * after a title.
+ */
+ if ((DescType->compact)&&(DescType->type == D_TITLE)&&
+ (*x < (TextIndent + (INDENT_SPACES * width))))
+ {
+ NeedSpace = 0;
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 1);
+ }
+
+ /*
+ * Special hack. Don't indent again for
+ * multiple <dd>'s in a row.
+ */
+ if (DescType->type == D_TITLE)
+ {
+ TextIndent = TextIndent +
+ ((INDENT_SPACES + 1) * width);
+ }
+ DescType->type = D_TEXT;
+ *x = TextIndent;
+ break;
+ case M_PREFORMAT:
+ if (mark->is_end)
+ {
+ Preformat = 0;
+ /*
+ * Properly convert the Linefeed state
+ * variable from preformat to formatted
+ * state.
+ */
+ if (PF_LF_State == 2)
+ {
+ PF_LF_State = 1;
+ }
+ else
+ {
+ PF_LF_State = 0;
+ }
+ ConditionalLineFeed(hw, x, y, 1);
+ if (saveFont != NULL)
+ {
+ hw->html.font = saveFont;
+ saveFont = NULL;
+ }
+ font = PopFont();
+ NewFont(font);
+ currentFont = font;
+ ConditionalLineFeed(hw, x, y, 2);
+ }
+ else
+ {
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ Preformat = 1;
+ PF_LF_State = 2;
+ if (saveFont == NULL)
+ {
+ saveFont = hw->html.font;
+ hw->html.font = hw->html.plain_font;
+ }
+ PushFont(currentFont);
+ font = hw->html.font;
+ }
+ break;
+ /*
+ * Now with forms, <INDEX> is the same as:
+ * <FORM>
+ * <HR>
+ * This is a searchable index. Enter search keywords:
+ * <INPUT NAME="isindex">
+ * <HR>
+ * </FORM>
+ * Also, <INDEX> will take an ACTION tag to specify a
+ * different URL to submit the query to.
+ */
+ case M_INDEX:
+ hw->html.is_index = True;
+ /*
+ * No index inside a form
+ */
+ if (CurrentForm == NULL)
+ {
+ struct mark_up mark_tmp;
+
+ /*
+ * Start the form
+ */
+ ConditionalLineFeed(hw, x, y, 1);
+ ConditionalLineFeed(hw, x, y, 2);
+ CurrentForm = (FormInfo *)malloc(
+ sizeof(FormInfo));
+ CurrentForm->next = NULL;
+ CurrentForm->hw = (Widget)hw;
+ CurrentForm->action = NULL;
+ CurrentForm->action = ParseMarkTag(mark->start,
+ MT_INDEX, "ACTION");
+ CurrentForm->method = ParseMarkTag(mark->start,
+ MT_INDEX, "METHOD");
+ CurrentForm->enctype = ParseMarkTag(mark->start,
+ MT_INDEX, "ENCTYPE");
+ CurrentForm->enc_entity = ParseMarkTag(
+ mark->start, MT_INDEX, "ENCENTITY");
+ CurrentForm->start = WidgetId;
+ CurrentForm->end = -1;
+
+ /*
+ * Horizontal rule
+ */
+ ConditionalLineFeed(hw, x, y, 1);
+ HRulePlace(hw, x, y, Width);
+ ConditionalLineFeed(hw, x, y, 1);
+
+ /*
+ * Text: "This is a searchable index.
+ * Enter search keywords: "
+ */
+ mark_tmp.text = (char *)malloc(
+ strlen("This is a searchable index. Enter search keywords: ") + 1);
+ strcpy(mark_tmp.text,"This is a searchable index. Enter search keywords: ");
+ FormatPlace(hw, &mark_tmp, x, y, Width);
+
+ /*
+ * Fake up the text INPUT tag.
+ */
+ mark_tmp.start = (char *)malloc(
+ strlen("input SIZE=25 NAME=\"isindex\"") + 1);
+ strcpy(mark_tmp.start,"input SIZE=25 NAME=\"isindex\"");
+ WidgetPlace(hw, &mark_tmp, x, y, Width);
+
+#ifdef ISINDEX_SUBMIT
+ /*
+ * Text: ";<CR> press this button to submit
+ * the query: "
+ */
+ mark_tmp.text = (char *)malloc(
+ strlen(";\n press this button to submit the query: ") + 1);
+ strcpy(mark_tmp.text,";\n press this button to submit the query: ");
+ FormatPlace(hw, &mark_tmp, x, y, Width);
+
+ /*
+ * Fake up the submit INPUT tag.
+ */
+ mark_tmp.start = (char *)malloc(
+ strlen("input TYPE=\"submit\"") + 1);
+ strcpy(mark_tmp.start, "input TYPE=\"submit\"");
+ WidgetPlace(hw, &mark_tmp, x, y, Width);
+
+ /*
+ * Text: ".<CR>"
+ */
+ mark_tmp.text = (char *)malloc(
+ strlen(".\n") + 1);
+ strcpy(mark_tmp.text, ".\n");
+ FormatPlace(hw, &mark_tmp, x, y, Width);
+#endif /* ISINDEX_SUBMIT */
+
+ /*
+ * Horizontal rule
+ */
+ ConditionalLineFeed(hw, x, y, 1);
+ HRulePlace(hw, x, y, Width);
+ ConditionalLineFeed(hw, x, y, 1);
+
+ /*
+ * Close the form
+ */
+ ConditionalLineFeed(hw, x, y, 1);
+ CurrentForm->end = WidgetId;
+ ConditionalLineFeed(hw, x, y, 2);
+ AddNewForm(hw, CurrentForm);
+ CurrentForm = NULL;
+ }
+ break;
+ case M_HRULE:
+ ConditionalLineFeed(hw, x, y, 1);
+ HRulePlace(hw, x, y, Width);
+ ConditionalLineFeed(hw, x, y, 1);
+ break;
+ case M_LINEBREAK:
+ LineFeed(hw, x, y);
+ break;
+ default:
+ break;
+ }
+ if ((font != NULL)&&(font != currentFont))
+ {
+ NewFont(font);
+ currentFont = font;
+ }
+}
+
+
+/*
+ * Format all the objects in the passed Widget's
+ * parsed object list to fit the locally global Width.
+ * Passes in the x,y coords of where to start placing the
+ * formatted text.
+ * Returns the ending x,y in same variables.
+ * Title objects are ignored, and not formatted.
+ *
+ * The locally global variables are assumed to have been initialized
+ * before this function was called.
+ */
+void
+FormatChunk(hw, x, y)
+ HTMLWidget hw;
+ int *x, *y;
+{
+ struct mark_up *mptr;
+
+ /*
+ * Format all objects
+ */
+ mptr = hw->html.html_objects;
+ Last = NULL;
+ while (mptr != NULL)
+ {
+ TriggerMarkChanges(hw, mptr, x, y);
+ /*
+ * Save last non-text mark
+ */
+ if (mptr->type != M_NONE)
+ {
+ Last = mptr;
+ }
+ mptr = mptr->next;
+ }
+}
+
+
+/*
+ * Called by the widget to format all the objects in the
+ * parsed object list to fit its current window size.
+ * Returns the max_height of the entire document.
+ * Title objects are ignored, and not formatted.
+ */
+int
+FormatAll(hw, Fwidth)
+ HTMLWidget hw;
+ int *Fwidth;
+{
+ int x, y;
+ int width;
+ struct mark_up *msave;
+#ifdef TIMING
+gettimeofday(&Tv, &Tz);
+fprintf(stderr, "FormatAll enter (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
+#endif
+
+ width = *Fwidth;
+ MaxWidth = width;
+
+ /*
+ * Clear the is_index flag
+ */
+ hw->html.is_index = False;
+
+ /*
+ * Initialize local variables, some from the widget
+ */
+ MarginW = hw->html.margin_width;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ Fg = hw->manager.foreground;
+#else
+ Fg = hw->html.foreground;
+#endif /* MOTIF */
+ Bg = hw->core.background_pixel;
+ Underlines = 0;
+ DashedUnderlines = False;
+ Width = width;
+ TextIndent = MarginW;
+ ElementId = 0;
+ WidgetId = 0;
+ LineNumber = 1;
+ LineBottom = 0;
+ BaseLine = -100;
+ CharsInLine = 0;
+ IndentLevel = 0;
+ Ignore = 0;
+ Preformat = 0;
+ PF_LF_State = 0;
+ NeedSpace = 0;
+ Internal = False;
+ Strikeout = False;
+ AnchorText = NULL;
+ DescType = &BaseDesc;
+ ListData = &BaseDesc;
+ DescType->type = D_NONE;
+ DescType->count = 0;
+ DescType->compact = 0;
+ DescType->next = NULL;
+ CurrentForm = NULL;
+ CurrentSelect = NULL;
+ TextAreaBuf = NULL;
+
+ /*
+ * Free the old title, if there is one.
+ */
+ if (hw->html.title != NULL)
+ {
+ free(hw->html.title);
+ hw->html.title = NULL;
+ }
+ TitleText = NULL;
+
+#ifdef THROW_AWAY_OLD_LIST
+ /*
+ * Free up previously formatted elements
+ */
+ FreeLineList(hw->html.formatted_elements);
+ hw->html.formatted_elements = NULL;
+#endif
+
+ /*
+ * Clear any previous selections
+ */
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+
+ /*
+ * Set up a starting font, and starting x, y, position
+ */
+ NewFont(hw->html.font);
+ currentFont = hw->html.font;
+ saveFont = NULL;
+ FontStack = &FontBase;
+ FontStack->font = hw->html.font;
+
+ x = TextIndent;
+ y = hw->html.margin_height;
+
+ /*
+ * Start a null element list, to be filled in as we go.
+ */
+ Current = NULL;
+
+ /*
+ * If we have parsed special header text, fill it in now.
+ */
+ if (hw->html.html_header_objects != NULL)
+ {
+ msave = hw->html.html_objects;
+ hw->html.html_objects = hw->html.html_header_objects;
+ FormatChunk(hw, &x, &y);
+
+ if (saveFont != NULL)
+ {
+ hw->html.font = saveFont;
+ saveFont = NULL;
+ }
+ NewFont(hw->html.font);
+ currentFont = hw->html.font;
+
+ ConditionalLineFeed(hw, &x, &y, 1);
+
+ hw->html.html_objects = msave;
+ }
+
+ /*
+ * Format all objects for width
+ */
+ FormatChunk(hw, &x, &y);
+
+ /*
+ * If we have parsed special footer text, fill it in now.
+ */
+ if (hw->html.html_footer_objects != NULL)
+ {
+ if (saveFont != NULL)
+ {
+ hw->html.font = saveFont;
+ saveFont = NULL;
+ }
+ NewFont(hw->html.font);
+ currentFont = hw->html.font;
+
+ Preformat = 0;
+ PF_LF_State = 0;
+ NeedSpace = 0;
+
+ ConditionalLineFeed(hw, &x, &y, 1);
+
+ msave = hw->html.html_objects;
+ hw->html.html_objects = hw->html.html_footer_objects;
+ FormatChunk(hw, &x, &y);
+
+ hw->html.html_objects = msave;
+ }
+
+ /*
+ * Ensure a linefeed after the final element.
+ */
+ ConditionalLineFeed(hw, &x, &y, 1);
+
+ /*
+ * Restore the proper font from unterminated preformatted text
+ * sequences.
+ */
+ if (saveFont != NULL)
+ {
+ hw->html.font = saveFont;
+ saveFont = NULL;
+ }
+
+ /*
+ * Free any extra of the pre-allocated list.
+ * Terminate the element list.
+ */
+ if ((Current != NULL)&&(Current->next != NULL))
+ {
+ FreeLineList(Current->next);
+ Current->next = NULL;
+ }
+ else if ((Current == NULL)&&(hw->html.formatted_elements != NULL))
+ {
+ FreeLineList(hw->html.formatted_elements);
+ hw->html.formatted_elements = NULL;
+ }
+
+ /*
+ * Add the bottom margin to the max height.
+ */
+ y = y + hw->html.margin_height;
+
+ /*
+ * Make the line array indexed into the element list
+ * and store it into the widget
+ */
+ hw->html.line_count = LineNumber;
+ if (hw->html.line_array != NULL)
+ {
+ free((char *)hw->html.line_array);
+ }
+ hw->html.line_array = MakeLineList(hw->html.formatted_elements,
+ LineNumber);
+
+ /*
+ * If the passed in MaxWidth was wrong, correct it.
+ */
+ if (MaxWidth != width)
+ {
+ *Fwidth = MaxWidth;
+ }
+
+#ifdef TIMING
+gettimeofday(&Tv, &Tz);
+fprintf(stderr, "FormatAll exit (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
+#endif
+ return(y);
+}
+
+
+/*
+ * Redraw a linefeed.
+ * Basically a filled rectangle at the end of a line.
+ */
+void
+LinefeedRefresh(hw, eptr)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+{
+ int x1, y1;
+ unsigned int width, height;
+
+#ifdef NO_EXTRA_FILLS
+ /*
+ * The actualt height of the rectangle to fill is strange, based
+ * an a differente between eptr->font->(ascent/descent) and
+ * eptr->font->max_bounds.(ascent/descent) which I don't quite
+ * understand. But it works.
+ * Deal with bad Lucidia descents.
+ */
+ x1 = eptr->x;
+ if (x1 > (int)hw->core.width)
+ {
+ width = 0;
+ }
+ else
+ {
+ width = hw->core.width - x1;
+ }
+#ifdef SHORT_LINEFEEDS
+ y1 = eptr->y + eptr->y_offset + eptr->font->max_bounds.ascent -
+ eptr->font->ascent;
+ height = eptr->font->ascent + eptr->font->descent;
+#else
+ y1 = eptr->y + eptr->font->max_bounds.ascent - eptr->font->ascent;
+ height = eptr->line_height;
+#endif /* SHORT_LINEFEEDS */
+#else
+ x1 = eptr->x;
+ if (x1 > (int)hw->core.width)
+ {
+ width = 0;
+ }
+ else
+ {
+ width = hw->core.width - x1;
+ }
+#ifdef SHORT_LINEFEEDS
+ y1 = eptr->y + eptr->y_offset;
+ if (eptr->font->descent > eptr->font->max_bounds.descent)
+ {
+ height = eptr->font->max_bounds.ascent +
+ eptr->font->descent;
+ }
+ else
+ {
+ height = eptr->font->max_bounds.ascent +
+ eptr->font->max_bounds.descent;
+ }
+#else
+ y1 = eptr->y;
+ height = eptr->line_height;
+#endif /* SHORT_LINEFEEDS */
+#endif /* NO_EXTRA_FILLS */
+
+ x1 = x1 - hw->html.scroll_x;
+ y1 = y1 - hw->html.scroll_y;
+
+ if (eptr->selected == True)
+ {
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
+ }
+ else
+ {
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
+ }
+ XFillRectangle(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ x1, y1, width, height);
+}
+
+
+/*
+ * Redraw part of a formatted text element, in the passed fg and bg
+ */
+void
+PartialRefresh(hw, eptr, start_pos, end_pos, fg, bg)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+ int start_pos, end_pos;
+ unsigned long fg, bg;
+{
+ int ascent;
+ char *tdata;
+ int tlen;
+ int x, y, width;
+ int partial;
+
+ XSetFont(XtDisplay(hw), hw->html.drawGC, eptr->font->fid);
+ ascent = eptr->font->max_bounds.ascent;
+ width = -1;
+ partial = 0;
+
+ if (start_pos != 0)
+ {
+ int dir, nascent, descent;
+ XCharStruct all;
+
+#ifdef ASSUME_FIXED_WIDTH_PRE
+ if (eptr->font == hw->html.plain_font)
+ {
+ all.width = eptr->font->max_bounds.width * start_pos;
+ }
+ else
+ {
+ XTextExtents(eptr->font, (char *)eptr->edata,
+ start_pos, &dir, &nascent, &descent, &all);
+ }
+#else
+ XTextExtents(eptr->font, (char *)eptr->edata,
+ start_pos, &dir, &nascent, &descent, &all);
+#endif /* ASSUME_FIXED_WIDTH_PRE */
+ x = eptr->x + all.width;
+ tdata = (char *)(eptr->edata + start_pos);
+ partial = 1;
+ }
+ else
+ {
+ x = eptr->x;
+ tdata = (char *)eptr->edata;
+ }
+
+ if (end_pos != (eptr->edata_len - 2))
+ {
+ tlen = end_pos - start_pos + 1;
+ partial = 1;
+ }
+ else
+ {
+ tlen = eptr->edata_len - start_pos - 1;
+ }
+
+ y = eptr->y + eptr->y_offset;
+
+ x = x - hw->html.scroll_x;
+ y = y - hw->html.scroll_y;
+
+#ifndef NO_EXTRA_FILLS
+ {
+ int dir, nascent, descent;
+ XCharStruct all;
+ int height;
+
+ /*
+ * May be safe to used the cached full width of this
+ * string, and thus avoid a call to XTextExtents
+ */
+ if ((!partial)&&(eptr->width != 0))
+ {
+ all.width = eptr->width;
+ }
+ else
+ {
+#ifdef ASSUME_FIXED_WIDTH_PRE
+ if (eptr->font == hw->html.plain_font)
+ {
+ all.width = eptr->font->max_bounds.width * tlen;
+ }
+ else
+ {
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent, &all);
+ }
+#else
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent, &all);
+#endif /* ASSUME_FIXED_WIDTH_PRE */
+ }
+
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, bg);
+
+ height = (eptr->font->max_bounds.ascent - eptr->font->ascent);
+ if (height > 0)
+ {
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, x, y,
+ (unsigned int)all.width, (unsigned int)height);
+ }
+ height = (eptr->font->max_bounds.descent - eptr->font->descent);
+ if (height > 0)
+ {
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, x,
+ (int)(y + eptr->font->max_bounds.ascent +
+ eptr->font->descent),
+ (unsigned int)all.width, (unsigned int)height);
+ }
+ width = all.width;
+ }
+#endif /* NO_EXTRA_FILLS */
+
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, fg);
+ XSetBackground(XtDisplay(hw), hw->html.drawGC, bg);
+
+ XDrawImageString(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ x, y + ascent,
+ (char *)tdata, tlen);
+
+ if (eptr->underline_number)
+ {
+ int i, ly;
+
+ if (eptr->dashed_underline)
+ {
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineDoubleDash, CapButt, JoinBevel);
+ }
+ else
+ {
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineSolid, CapButt, JoinBevel);
+ }
+
+ if (width == -1)
+ {
+ int dir, nascent, descent;
+ XCharStruct all;
+
+#ifdef ASSUME_FIXED_WIDTH_PRE
+ if (eptr->font == hw->html.plain_font)
+ {
+ all.width = eptr->font->max_bounds.width * tlen;
+ }
+ else
+ {
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent,&all);
+ }
+#else
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent,&all);
+#endif /* ASSUME_FIXED_WIDTH_PRE */
+ width = all.width;
+ }
+
+ ly = (int)(y + eptr->font->max_bounds.ascent +
+ eptr->font->descent - 1);
+
+ for (i=0; i<eptr->underline_number; i++)
+ {
+ XDrawLine(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, ly, (int)(x + width), ly);
+ ly -= 2;
+ }
+ }
+
+ if (eptr->strikeout == True)
+ {
+ int ly;
+
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineSolid, CapButt, JoinBevel);
+
+ if (width == -1)
+ {
+ int dir, nascent, descent;
+ XCharStruct all;
+
+#ifdef ASSUME_FIXED_WIDTH_PRE
+ if (eptr->font == hw->html.plain_font)
+ {
+ all.width = eptr->font->max_bounds.width * tlen;
+ }
+ else
+ {
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent,&all);
+ }
+#else
+ XTextExtents(eptr->font, (char *)tdata,
+ tlen, &dir, &nascent, &descent,&all);
+#endif /* ASSUME_FIXED_WIDTH_PRE */
+ width = all.width;
+ }
+
+ ly = (int)(y + eptr->font->max_bounds.ascent +
+ eptr->font->descent - 1);
+ ly = ly - ((hw->html.font->max_bounds.ascent +
+ hw->html.font->descent) / 2);
+
+ XDrawLine(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ x, ly, (int)(x + width), ly);
+ }
+}
+
+
+/*
+ * Redraw a formatted text element
+ */
+void
+TextRefresh(hw, eptr, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+ int start_pos, end_pos;
+{
+ if (eptr->selected == False)
+ {
+ PartialRefresh(hw, eptr, start_pos, end_pos,
+ eptr->fg, eptr->bg);
+ }
+ else if ((start_pos >= eptr->start_pos)&&(end_pos <= eptr->end_pos))
+ {
+ PartialRefresh(hw, eptr, start_pos, end_pos,
+ eptr->bg, eptr->fg);
+ }
+ else
+ {
+ if (start_pos < eptr->start_pos)
+ {
+ PartialRefresh(hw, eptr, start_pos, eptr->start_pos - 1,
+ eptr->fg, eptr->bg);
+ start_pos = eptr->start_pos;
+ }
+ if (end_pos > eptr->end_pos)
+ {
+ PartialRefresh(hw, eptr, eptr->end_pos + 1, end_pos,
+ eptr->fg, eptr->bg);
+ end_pos = eptr->end_pos;
+ }
+ PartialRefresh(hw, eptr, start_pos, end_pos,
+ eptr->bg, eptr->fg);
+ }
+}
+
+
+/*
+ * Redraw a formatted bullet element
+ */
+void
+BulletRefresh(hw, eptr)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+{
+ int width, line_height;
+ int x1, y1;
+
+/*
+ width = eptr->font->max_bounds.width;
+*/
+ width = eptr->font->max_bounds.lbearing +
+ eptr->font->max_bounds.rbearing;
+ /*
+ * Deal with bad Lucidia descents.
+ */
+ if (eptr->font->descent > eptr->font->max_bounds.descent)
+ {
+ line_height = eptr->font->max_bounds.ascent +
+ eptr->font->descent;
+ }
+ else
+ {
+ line_height = eptr->font->max_bounds.ascent +
+ eptr->font->max_bounds.descent;
+ }
+ x1 = eptr->x;
+ y1 = eptr->y + eptr->y_offset + (line_height / 2) - (width / 4);
+ x1 = x1 - hw->html.scroll_x;
+ y1 = y1 - hw->html.scroll_y;
+ XSetFont(XtDisplay(hw), hw->html.drawGC, eptr->font->fid);
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
+ XSetBackground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
+ if (eptr->indent_level < 2)
+ {
+ XFillArc(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ (x1 - width), y1,
+ (width / 2), (width / 2), 0, 23040);
+ }
+ else if (eptr->indent_level == 2)
+ {
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineSolid, CapButt, JoinBevel);
+ XDrawRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ (x1 - width), y1,
+ (width / 2), (width / 2));
+ }
+ else if (eptr->indent_level > 2)
+ {
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineSolid, CapButt, JoinBevel);
+ XDrawArc(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ (x1 - width), y1,
+ (width / 2), (width / 2), 0, 23040);
+ }
+}
+
+
+/*
+ * Redraw a formatted horizontal rule element
+ */
+void
+HRuleRefresh(hw, eptr)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+{
+ int width, height;
+ int x1, y1;
+
+ width = (int)hw->html.view_width - (int)(2 * hw->html.margin_width);
+ if (width < 0)
+ {
+ width = 0;
+ }
+
+ x1 = eptr->x;
+ y1 = eptr->y;
+ x1 = x1 - hw->html.scroll_x;
+ y1 = y1 - hw->html.scroll_y;
+ height = eptr->line_height;
+
+ /* blank out area */
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
+ XFillRectangle(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC, x1, y1, width, height);
+ y1 = y1 + (height / 2) - 1;
+
+ XSetLineAttributes(XtDisplay(hw), hw->html.drawGC, 1,
+ LineSolid, CapButt, JoinBevel);
+#ifdef MOTIF
+ XDrawLine(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->manager.bottom_shadow_GC,
+ x1, y1, (int)(x1 + width), y1);
+ XDrawLine(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->manager.top_shadow_GC,
+ x1, y1 + 1, (int)(x1 + width), y1 + 1);
+#else
+ /* changing the GC back and forth is not the most efficient way.... */
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
+ XDrawLine(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ x1, y1, (int)(x1 + width), y1);
+ XDrawLine(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ hw->html.drawGC,
+ x1, y1 + 1, (int)(x1 + width), y1 + 1);
+#endif
+}
+
+
+/*
+ * Redraw a formatted image element.
+ * The color of the image border reflects whether it is an active anchor
+ * or not.
+ * Actual Pixmap creation was put off until now to make sure we
+ * had a window. If it hasn't been already created, make the Pixmap
+ * now.
+ */
+void
+ImageRefresh(hw, eptr)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+{
+ if (eptr->pic_data != NULL)
+ {
+ int x, y, extra;
+
+ x = eptr->x;
+ y = eptr->y + eptr->y_offset;
+
+ if ((hw->html.border_images == True)||
+ ((eptr->anchorHRef != NULL)&&
+ (!eptr->pic_data->internal)))
+ {
+ extra = IMAGE_BORDER;
+ }
+ else
+ {
+ extra = 0;
+ }
+
+ x = x - hw->html.scroll_x;
+ y = y - hw->html.scroll_y;
+
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
+ XSetBackground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, y,
+ (eptr->pic_data->width + (2 * extra)),
+ extra);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x,
+ (y + eptr->pic_data->height + extra),
+ (eptr->pic_data->width + (2 * extra)),
+ extra);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, y,
+ extra,
+ (eptr->pic_data->height + (2 * extra)));
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ (x + eptr->pic_data->width + extra),
+ y,
+ extra,
+ (eptr->pic_data->height + (2 * extra)));
+
+ if (eptr->pic_data->image == (Pixmap)NULL)
+ {
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->image = InfoToImage(hw,
+ eptr->pic_data);
+ }
+ else
+ {
+ if (eptr->pic_data->delayed)
+ {
+ if ((eptr->anchorHRef != NULL)&&
+ (!IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (!IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ eptr->pic_data->image = DelayedImage(
+ hw, True);
+ }
+ else
+ {
+ eptr->pic_data->image = DelayedImage(
+ hw, False);
+ }
+ }
+ else
+ {
+ /*
+ * Could be that the user opened another
+ * window, and the Pixmap was freed, and
+ * then they overflowed the cache,
+ * and the XImage data was freed.
+ * If this image was ever successfully
+ * fetched, try again before giving up.
+ */
+ if ((eptr->pic_data->fetched)&&
+ (hw->html.resolveDelayedImage != NULL))
+ {
+ ImageInfo *pdata;
+
+ pdata = eptr->pic_data;
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw,
+ eptr->edata);
+ if (eptr->pic_data != NULL)
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * Copy over state information from
+ * the last time we had this image
+ */
+ eptr->pic_data->ismap =
+ pdata->ismap;
+ eptr->pic_data->fptr =
+ pdata->fptr;
+ eptr->pic_data->internal =
+ pdata->internal;
+ eptr->pic_data->text =
+ pdata->text;
+ }
+ else
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ }
+ else
+ {
+ eptr->pic_data->image = NoImage(hw);
+ }
+ }
+ }
+ }
+
+ if (eptr->pic_data->image != (Pixmap)NULL)
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ eptr->pic_data->image,
+ XtWindow(hw->html.view), hw->html.drawGC, 0, 0,
+ eptr->pic_data->width, eptr->pic_data->height,
+ (x + extra),
+ (y + extra));
+
+ }
+ if ((eptr->pic_data->delayed)&&(eptr->anchorHRef != NULL)&&
+ (!IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (!IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ XSetForeground(XtDisplay(hw), hw->html.drawGC,
+ eptr->fg);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, (y + AnchoredHeight(hw)),
+ (eptr->pic_data->width + (2 * extra)),
+ extra);
+ }
+ }
+}
+
+
+void
+RefreshTextRange(hw, start, end)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+{
+ struct ele_rec *eptr;
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ if (eptr->type == E_TEXT)
+ {
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ }
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ if (eptr->type == E_TEXT)
+ {
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ }
+ }
+}
+
+
+/*
+ * Refresh all elements on a single line into the widget's window
+ */
+void
+PlaceLine(hw, line)
+ HTMLWidget hw;
+ int line;
+{
+ struct ele_rec *eptr;
+
+ /*
+ * Item list for this line
+ */
+ eptr = hw->html.line_array[line];
+
+ while ((eptr != NULL)&&(eptr->line_number == (line + 1)))
+ {
+ switch(eptr->type)
+ {
+ case E_TEXT:
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ break;
+ case E_BULLET:
+ BulletRefresh(hw, eptr);
+ break;
+ case E_HRULE:
+ HRuleRefresh(hw, eptr);
+ break;
+ case E_LINEFEED:
+ LinefeedRefresh(hw, eptr);
+ break;
+ case E_IMAGE:
+ ImageRefresh(hw, eptr);
+ break;
+ case E_WIDGET:
+ WidgetRefresh(hw, eptr);
+ break;
+ }
+ eptr = eptr->next;
+ }
+}
+
+
+/*
+ * Locate the element (if any) that is at the passed location
+ * in the widget. If there is no corresponding element, return
+ * NULL. If an element is found return the position of the character
+ * you are at in the pos pointer passed.
+ */
+struct ele_rec *
+LocateElement(hw, x, y, pos)
+ HTMLWidget hw;
+ int x, y;
+ int *pos;
+{
+ struct ele_rec *eptr;
+ struct ele_rec *rptr;
+ int i, start, end, line, guess;
+ int tx1, tx2, ty1, ty2;
+
+ x = x + hw->html.scroll_x;
+ y = y + hw->html.scroll_y;
+
+ /*
+ * Narrow the search down to a 2 line range
+ * before beginning to search element by element
+ */
+ start = -1;
+ end = -1;
+
+ /*
+ * Heuristic to speed up redraws by guessing at the starting line.
+ */
+ guess = y / (hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent);
+ if (guess > (hw->html.line_count - 1))
+ {
+ guess = hw->html.line_count - 1;
+ }
+ while (guess > 0)
+ {
+ if ((hw->html.line_array[guess] != NULL)&&
+ (hw->html.line_array[guess]->y <= y))
+ {
+ break;
+ }
+ guess--;
+ }
+ if (guess < 0)
+ {
+ guess = 0;
+ }
+
+ for (i=guess; i<hw->html.line_count; i++)
+ {
+ if (hw->html.line_array[i] == NULL)
+ {
+ continue;
+ }
+ else if (hw->html.line_array[i]->y <= y)
+ {
+ start = i;
+ continue;
+ }
+ else
+ {
+ end = i;
+ break;
+ }
+ }
+
+ /*
+ * Search may have already failed, or it may be a one line
+ * range.
+ */
+ if ((start == -1)&&(end == -1))
+ {
+ return(NULL);
+ }
+ else if (start == -1)
+ {
+ start = end;
+ }
+ else if (end == -1)
+ {
+ end = start;
+ }
+
+ /*
+ * Search element by element, for now we only search
+ * text elements, images, and linefeeds.
+ */
+ eptr = hw->html.line_array[start];
+ ty1 = eptr->y;
+ /*
+ * Deal with bad Lucidia descents.
+ */
+ if (eptr->font->descent > eptr->font->max_bounds.descent)
+ {
+ ty2 = eptr->y + eptr->font->max_bounds.ascent +
+ eptr->font->descent;
+ }
+ else
+ {
+ ty2 = eptr->y + eptr->font->max_bounds.ascent +
+ eptr->font->max_bounds.descent;
+ }
+ line = eptr->line_number;
+ /*
+ * Searches on this line should extend to the top of the
+ * next line, if possible. Which might be far away if there
+ * is an image on this line.
+ */
+ if (((line + 1) < hw->html.line_count)&&
+ (hw->html.line_array[line + 1] != NULL))
+ {
+ ty2 = hw->html.line_array[line + 1]->y - 1;
+ }
+ /*
+ * Else we are at the last line, and need to find its height.
+ * The linefeed at the end should know the max height of the line.
+ */
+ else
+ {
+ struct ele_rec *teptr;
+
+ teptr = eptr;
+ while (teptr != NULL)
+ {
+ if (teptr->type == E_LINEFEED)
+ {
+ break;
+ }
+ teptr = teptr->next;
+ }
+ if (teptr != NULL)
+ {
+ ty2 = teptr->y + teptr->line_height - 1;
+ }
+ }
+
+ rptr = NULL;
+ while ((eptr != NULL)&&(eptr->line_number <= (end + 1)))
+ {
+ if (eptr->line_number != line)
+ {
+ ty1 = ty2;
+ /*
+ * Deal with bad Lucidia descents.
+ */
+ if(eptr->font->descent > eptr->font->max_bounds.descent)
+ {
+ ty2 = eptr->y + eptr->font->max_bounds.ascent +
+ eptr->font->descent;
+ }
+ else
+ {
+ ty2 = eptr->y + eptr->font->max_bounds.ascent +
+ eptr->font->max_bounds.descent;
+ }
+ line = eptr->line_number;
+ /*
+ * Searches on this line should extend to the top of
+ * the next line, if possible. Which might be far
+ * away if there is an image on this line.
+ */
+ if (((line + 1) < hw->html.line_count)&&
+ (hw->html.line_array[line + 1] != NULL))
+ {
+ ty2 = hw->html.line_array[line + 1]->y - 1;
+ }
+ /*
+ * Else we are at the last line, and need to find its
+ * height. The linefeed at the end should know the
+ * max height of the line.
+ */
+ else
+ {
+ struct ele_rec *teptr;
+
+ teptr = eptr;
+ while (teptr != NULL)
+ {
+ if (teptr->type == E_LINEFEED)
+ {
+ break;
+ }
+ teptr = teptr->next;
+ }
+ if (teptr != NULL)
+ {
+ ty2 = teptr->y + teptr->line_height - 1;
+ }
+ }
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ int dir, ascent, descent;
+ XCharStruct all;
+
+ tx1 = eptr->x;
+ XTextExtents(eptr->font, (char *)eptr->edata,
+ eptr->edata_len - 1, &dir,
+ &ascent, &descent, &all);
+ tx2 = eptr->x + all.width;
+ if ((x >= tx1)&&(x <= tx2)&&(y >= ty1)&&(y <= ty2))
+ {
+ rptr = eptr;
+ break;
+ }
+ }
+ else if ((eptr->type == E_IMAGE)&&(eptr->pic_data != NULL))
+ {
+ tx1 = eptr->x;
+ tx2 = eptr->x + eptr->pic_data->width;
+ if ((x >= tx1)&&(x <= tx2)&&(y >= ty1)&&(y <= ty2))
+ {
+ rptr = eptr;
+ break;
+ }
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ tx1 = eptr->x;
+ if ((x >= tx1)&&(y >= ty1)&&(y <= ty2))
+ {
+ rptr = eptr;
+ break;
+ }
+ else if (eptr->next == NULL)
+ {
+ rptr = eptr;
+ break;
+ }
+ else if (eptr->next != NULL)
+ {
+ int tmpy;
+
+ tmpy = eptr->next->y + eptr->next->line_height;
+ tx2 = eptr->next->x;
+ if ((x < tx2)&&(y >= ty2)&&(y <= tmpy))
+ {
+ rptr = eptr;
+ break;
+ }
+ }
+ }
+ eptr = eptr->next;
+ }
+
+ /*
+ * If we found an element, locate the exact character position within
+ * that element.
+ */
+ if (rptr != NULL)
+ {
+ int dir, ascent, descent;
+ XCharStruct all;
+ int epos;
+
+ /*
+ * Start assuming fixed width font. The real position should
+ * always be <= to this, but just in case, start at the end
+ * of the string if it is not.
+ */
+ epos = ((x - rptr->x) / rptr->font->max_bounds.width) + 1;
+ if (epos >= rptr->edata_len - 1)
+ {
+ epos = rptr->edata_len - 2;
+ }
+ XTextExtents(rptr->font, (char *)rptr->edata,
+ (epos + 1), &dir, &ascent, &descent, &all);
+ if (x > (int)(rptr->x + all.width))
+ {
+ epos = rptr->edata_len - 3;
+ }
+ else
+ {
+ epos--;
+ }
+
+ while (epos >= 0)
+ {
+ XTextExtents(rptr->font, (char *)rptr->edata,
+ (epos + 1), &dir, &ascent, &descent, &all);
+ if ((int)(rptr->x + all.width) <= x)
+ {
+ break;
+ }
+ epos--;
+ }
+ epos++;
+ *pos = epos;
+ }
+ return(rptr);
+}
+
+
+/*
+ * Used by ParseTextToPrettyString to let it be sloppy about its
+ * string creation, and never overflow the buffer.
+ * It concatonates the passed string to the current string, managing
+ * both the current string length, and the total buffer length.
+ */
+void
+strcpy_or_grow(str, slen, blen, add)
+ char **str;
+ int *slen;
+ int *blen;
+ char *add;
+{
+ int newlen;
+ int addlen;
+ char *buf;
+
+ /*
+ * If necessary, initialize this string buffer
+ */
+ if (*str == NULL)
+ {
+ *str = (char *)malloc(1024 * sizeof(char));
+ if (*str == NULL)
+ {
+ return;
+ }
+ *blen = 1024;
+ strcpy(*str, "");
+ *slen = 0;
+ }
+
+ buf = *str;
+ if ((buf == NULL)||(add == NULL))
+ {
+ return;
+ }
+
+ addlen = strlen(add);
+
+ newlen = *slen + addlen;
+ if (newlen >= *blen)
+ {
+ newlen = ((newlen / 1024) + 1) * 1024;
+ buf = (char *)malloc(newlen * sizeof(char));
+ if (buf == NULL)
+ {
+ return;
+ }
+ bcopy(*str, buf, *blen);
+ free((char *)*str);
+ *str = buf;
+ *blen = newlen;
+ }
+
+ bcopy(add, (char *)(buf + *slen), addlen + 1);
+
+ *slen = *slen + addlen;
+}
+
+
+/*
+ * Parse all the formatted text elements from start to end
+ * into an ascii text string, and return it.
+ * space_width and lmargin tell us how many spaces
+ * to indent lines.
+ */
+char *
+ParseTextToString(elist, startp, endp, start_pos, end_pos, space_width, lmargin)
+ struct ele_rec *elist;
+ struct ele_rec *startp;
+ struct ele_rec *endp;
+ int start_pos, end_pos;
+ int space_width;
+ int lmargin;
+{
+ int newline;
+ int epos;
+ char *text;
+ int t_slen, t_blen;
+ struct ele_rec *eptr;
+ struct ele_rec *start;
+ struct ele_rec *end;
+
+ if (startp == NULL)
+ {
+ return(NULL);
+ }
+
+ if (SwapElements(startp, endp, start_pos, end_pos))
+ {
+ start = endp;
+ end = startp;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+ else
+ {
+ start = startp;
+ end = endp;
+ }
+
+ text = NULL;
+ newline = 0;
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ int i, spaces;
+ char *tptr;
+
+ if (eptr == start)
+ {
+ tptr = (char *)(eptr->edata + start_pos);
+ }
+ else
+ {
+ tptr = (char *)eptr->edata;
+ }
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen,
+ " ");
+ }
+ }
+ strcpy_or_grow(&text, &t_slen, &t_blen, tptr);
+ newline = 0;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ newline = 1;
+ }
+ eptr = eptr->next;
+ }
+ if ((eptr != NULL)&&(eptr->internal == False))
+ {
+ if (eptr->type == E_TEXT)
+ {
+ int i, spaces;
+ char *tptr;
+ char *tend, tchar;
+
+ if (eptr == start)
+ {
+ tptr = (char *)(eptr->edata + start_pos);
+ }
+ else
+ {
+ tptr = (char *)eptr->edata;
+ }
+
+ if (eptr == end)
+ {
+ tend = (char *)(eptr->edata + end_pos + 1);
+ tchar = *tend;
+ *tend = '\0';
+ }
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen,
+ " ");
+ }
+ }
+ strcpy_or_grow(&text, &t_slen, &t_blen, tptr);
+ newline = 0;
+
+ if (eptr == end)
+ {
+ *tend = tchar;
+ }
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ newline = 1;
+ }
+ }
+ return(text);
+}
+
+
+/*
+ * Parse all the formatted text elements from start to end
+ * into an ascii text string, and return it.
+ * Very like ParseTextToString() except the text is prettied up
+ * to show headers and the like.
+ * space_width and lmargin tell us how many spaces
+ * to indent lines.
+ */
+char *
+ParseTextToPrettyString(hw, elist, startp, endp, start_pos, end_pos,
+ space_width, lmargin)
+ HTMLWidget hw;
+ struct ele_rec *elist;
+ struct ele_rec *startp;
+ struct ele_rec *endp;
+ int start_pos, end_pos;
+ int space_width;
+ int lmargin;
+{
+ int line;
+ int newline;
+ int lead_spaces;
+ int epos;
+ char *text;
+ int t_slen, t_blen;
+ char *line_buf;
+ int l_slen, l_blen;
+ char lchar;
+ struct ele_rec *eptr;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ struct ele_rec *last;
+
+ if (startp == NULL)
+ {
+ return(NULL);
+ }
+
+ if (SwapElements(startp, endp, start_pos, end_pos))
+ {
+ start = endp;
+ end = startp;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+ else
+ {
+ start = startp;
+ end = endp;
+ }
+
+ text = NULL;
+ line_buf = NULL;
+
+ /*
+ * We need to know if we should consider the indentation or bullet
+ * that might be just before the first selected element to also be
+ * selected. This current hack looks to see if they selected the
+ * Whole line, and assumes if they did, they also wanted the beginning.
+ *
+ * If we are at the beginning of the list, or the beginning of
+ * a line, or just behind a bullett, assume this is the start of
+ * a line that we may want to include the indent for.
+ */
+ if ((start_pos == 0)&&
+ ((start->prev == NULL)||(start->prev->type == E_BULLET)||
+ (start->prev->line_number != start->line_number)))
+ {
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end)&&
+ (eptr->type != E_LINEFEED))
+ {
+ eptr = eptr->next;
+ }
+ if ((eptr != NULL)&&(eptr->type == E_LINEFEED))
+ {
+ newline = 1;
+ if ((start->prev != NULL)&&
+ (start->prev->type == E_BULLET))
+ {
+ start = start->prev;
+ }
+ }
+ else
+ {
+ newline = 0;
+ }
+ }
+ else
+ {
+ newline = 0;
+ }
+
+ lead_spaces = 0;
+ last = start;
+ eptr = start;
+ line = eptr->line_number;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_BULLET)
+ {
+ int i, spaces;
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ spaces -= 2;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ lead_spaces = spaces;
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&line_buf,
+ &l_slen, &l_blen, " ");
+ }
+ }
+ newline = 0;
+
+ strcpy_or_grow(&line_buf, &l_slen, &l_blen, "o ");
+ lead_spaces += 2;
+ }
+ else if (eptr->type == E_TEXT)
+ {
+ int i, spaces;
+ char *tptr;
+
+ if (eptr == start)
+ {
+ tptr = (char *)(eptr->edata + start_pos);
+ }
+ else
+ {
+ tptr = (char *)eptr->edata;
+ }
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ lead_spaces = spaces;
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&line_buf,
+ &l_slen, &l_blen, " ");
+ }
+ }
+ strcpy_or_grow(&line_buf, &l_slen, &l_blen, tptr);
+ newline = 0;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ newline = 1;
+ lchar = '\0';
+ if (eptr->font == hw->html.header1_font)
+ {
+ lchar = '*';
+ }
+ else if (eptr->font == hw->html.header2_font)
+ {
+ lchar = '=';
+ }
+ else if (eptr->font == hw->html.header3_font)
+ {
+ lchar = '+';
+ }
+ else if (eptr->font == hw->html.header4_font)
+ {
+ lchar = '-';
+ }
+ else if (eptr->font == hw->html.header5_font)
+ {
+ lchar = '~';
+ }
+ else if (eptr->font == hw->html.header6_font)
+ {
+ lchar = '.';
+ }
+ if (lchar != '\0')
+ {
+ char *ptr;
+ int cnt;
+
+ cnt = 0;
+ ptr = line_buf;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ cnt++;
+ if (cnt > lead_spaces)
+ {
+ *ptr = lchar;
+ }
+ ptr++;
+ }
+ strcpy_or_grow(&text,&t_slen,&t_blen, line_buf);
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ }
+ if (line_buf != NULL)
+ {
+ free(line_buf);
+ line_buf = NULL;
+ }
+ }
+ last = eptr;
+ eptr = eptr->next;
+ }
+ if ((eptr != NULL)&&(eptr->internal == False))
+ {
+ if (eptr->type == E_BULLET)
+ {
+ int i, spaces;
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ spaces -= 2;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ lead_spaces = spaces;
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&line_buf,
+ &l_slen, &l_blen, " ");
+ }
+ }
+ newline = 0;
+
+ strcpy_or_grow(&line_buf, &l_slen, &l_blen, "o ");
+ lead_spaces += 2;
+ }
+ else if (eptr->type == E_TEXT)
+ {
+ int i, spaces;
+ char *tptr;
+ char *tend, tchar;
+
+ if (eptr == start)
+ {
+ tptr = (char *)(eptr->edata + start_pos);
+ }
+ else
+ {
+ tptr = (char *)eptr->edata;
+ }
+
+ if (eptr == end)
+ {
+ tend = (char *)(eptr->edata + end_pos + 1);
+ tchar = *tend;
+ *tend = '\0';
+ }
+
+ if (newline)
+ {
+ spaces = (eptr->x - lmargin) / space_width;
+ if (spaces < 0)
+ {
+ spaces = 0;
+ }
+ lead_spaces = spaces;
+ for (i=0; i<spaces; i++)
+ {
+ strcpy_or_grow(&line_buf,
+ &l_slen, &l_blen, " ");
+ }
+ }
+ strcpy_or_grow(&line_buf, &l_slen, &l_blen, tptr);
+ newline = 0;
+
+ if (eptr == end)
+ {
+ *tend = tchar;
+ }
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ newline = 1;
+ lchar = '\0';
+ if (eptr->font == hw->html.header1_font)
+ {
+ lchar = '*';
+ }
+ else if (eptr->font == hw->html.header2_font)
+ {
+ lchar = '=';
+ }
+ else if (eptr->font == hw->html.header3_font)
+ {
+ lchar = '+';
+ }
+ else if (eptr->font == hw->html.header4_font)
+ {
+ lchar = '-';
+ }
+ else if (eptr->font == hw->html.header5_font)
+ {
+ lchar = '~';
+ }
+ else if (eptr->font == hw->html.header6_font)
+ {
+ lchar = '.';
+ }
+ if (lchar != '\0')
+ {
+ char *ptr;
+ int cnt;
+
+ cnt = 0;
+ ptr = line_buf;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ cnt++;
+ if (cnt > lead_spaces)
+ {
+ *ptr = lchar;
+ }
+ ptr++;
+ }
+ strcpy_or_grow(&text,&t_slen,&t_blen, line_buf);
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ }
+ if (line_buf != NULL)
+ {
+ free(line_buf);
+ line_buf = NULL;
+ }
+ }
+ last = eptr;
+ }
+ if (line_buf != NULL)
+ {
+ strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
+ lchar = '\0';
+ if (last->font == hw->html.header1_font)
+ {
+ lchar = '*';
+ }
+ else if (last->font == hw->html.header2_font)
+ {
+ lchar = '=';
+ }
+ else if (last->font == hw->html.header3_font)
+ {
+ lchar = '+';
+ }
+ else if (last->font == hw->html.header4_font)
+ {
+ lchar = '-';
+ }
+ else if (last->font == hw->html.header5_font)
+ {
+ lchar = '~';
+ }
+ else if (last->font == hw->html.header6_font)
+ {
+ lchar = '.';
+ }
+ if (lchar != '\0')
+ {
+ char *ptr;
+ int cnt;
+
+ cnt = 0;
+ ptr = line_buf;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ cnt++;
+ if (cnt > lead_spaces)
+ {
+ *ptr = lchar;
+ }
+ ptr++;
+ }
+ strcpy_or_grow(&text, &t_slen, &t_blen, "\n");
+ strcpy_or_grow(&text, &t_slen, &t_blen, line_buf);
+ }
+ }
+ if (line_buf != NULL)
+ {
+ free(line_buf);
+ line_buf = NULL;
+ }
+ return(text);
+}
+
+
+/*
+ * Find the preferred width of a parsed HTML document
+ * Currently unformatted plain text, unformatted listing text, plain files
+ * and preformatted text require special width.
+ * Preferred width = (width of longest plain text line in document) *
+ * (width of that text's font)
+ */
+int
+DocumentWidth(hw, list)
+ HTMLWidget hw;
+ struct mark_up *list;
+{
+ struct mark_up *mptr;
+ int plain_text;
+ int listing_text;
+ int pcnt, lcnt, pwidth, lwidth;
+ int width;
+ char *ptr;
+
+ /*
+ * Loop through object list looking at the plain, preformatted,
+ * and listing text
+ */
+ width = 0;
+ pwidth = 0;
+ lwidth = 0;
+ plain_text = 0;
+ listing_text = 0;
+ mptr = list;
+ while (mptr != NULL)
+ {
+ /*
+ * All text blocks between the starting and ending
+ * plain and pre text markers are plain text blocks.
+ * Manipulate flags so we recognize these blocks.
+ */
+ if ((mptr->type == M_PLAIN_TEXT)||
+ (mptr->type == M_PLAIN_FILE)||
+ (mptr->type == M_PREFORMAT))
+ {
+ if (mptr->is_end)
+ {
+ plain_text--;
+ if (plain_text < 0)
+ {
+ plain_text = 0;
+ }
+ }
+ else
+ {
+ plain_text++;
+ }
+ pcnt = 0;
+ lcnt = 0;
+ }
+ /*
+ * All text blocks between the starting and ending
+ * listing markers are listing text blocks.
+ */
+ else if (mptr->type == M_LISTING_TEXT)
+ {
+ if (mptr->is_end)
+ {
+ listing_text--;
+ if (listing_text < 0)
+ {
+ listing_text = 0;
+ }
+ }
+ else
+ {
+ listing_text++;
+ }
+ lcnt = 0;
+ pcnt = 0;
+ }
+ /*
+ * If this is a plain text block, add to line length.
+ * Find the Max of all line lengths.
+ */
+ else if ((plain_text)&&(mptr->type == M_NONE))
+ {
+ ptr = mptr->text;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ ptr = MaxTextWidth(ptr, &pcnt);
+ if (pcnt > pwidth)
+ {
+ pwidth = pcnt;
+ }
+ }
+ }
+ /*
+ * If this is a listing text block, add to line length.
+ * Find the Max of all line lengths.
+ */
+ else if ((listing_text)&&(mptr->type == M_NONE))
+ {
+ ptr = mptr->text;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ ptr = MaxTextWidth(ptr, &lcnt);
+ if (lcnt > lwidth)
+ {
+ lwidth = lcnt;
+ }
+ }
+ }
+ mptr = mptr->next;
+ }
+ width = pwidth * hw->html.plain_font->max_bounds.width;
+ lwidth = lwidth * hw->html.listing_font->max_bounds.width;
+ if (lwidth > width)
+ {
+ width = lwidth;
+ }
+ return(width);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/HTMLimages.c b/vendor/x11iraf/obm/ObmW/HTMLimages.c
new file mode 100644
index 00000000..fe33a6ee
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLimages.c
@@ -0,0 +1,891 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <ctype.h>
+#include "HTMLP.h"
+#include "bitmaps/NoImage.xbm"
+#include "bitmaps/DelayedImage.xbm"
+#include "bitmaps/AnchoredImage.xbm"
+
+
+#define IMAGE_BORDER 2
+
+
+ImageInfo no_image;
+ImageInfo delayed_image;
+ImageInfo anchored_image;
+
+static int allocation_index[256];
+
+
+/*
+ * Free all the colors in the default colormap that we have allocated so far.
+ */
+void
+FreeColors(dsp, colormap)
+ Display *dsp;
+ Colormap colormap;
+{
+ int i, j;
+ unsigned long pix;
+
+ for (i=0; i<256; i++)
+ {
+ if (allocation_index[i])
+ {
+ pix = (unsigned long)i;
+ /*
+ * Because X is stupid, we have to Free the color
+ * once for each time we've allocated it.
+ */
+ for (j=0; j<allocation_index[i]; j++)
+ {
+ XFreeColors(dsp, colormap, &pix, 1, 0L);
+ }
+ }
+ allocation_index[i] = 0;
+ }
+}
+
+
+/*
+ * Free up all the pixmaps allocated for this document.
+ */
+void
+FreeImages(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *eptr;
+
+ eptr = hw->html.formatted_elements;
+ while (eptr != NULL)
+ {
+ if ((eptr->type == E_IMAGE)&&(eptr->pic_data != NULL))
+ {
+ /*
+ * Don't free the no_image default image
+ */
+ if ((eptr->pic_data->image != (Pixmap)NULL)&&
+ (eptr->pic_data->image != delayed_image.image)&&
+ (eptr->pic_data->image != anchored_image.image)&&
+ (eptr->pic_data->image != no_image.image))
+ {
+ /*
+ * Don't free internal images
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata, INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ }
+ else
+ {
+ XFreePixmap(XtDisplay(hw),
+ eptr->pic_data->image);
+ eptr->pic_data->image = (Pixmap)NULL;
+ }
+ }
+ }
+ eptr = eptr->next;
+ }
+}
+
+
+/*
+ * Find the closest color by allocating it, or picking an already allocated
+ * color
+ */
+void
+FindColor(dsp, colormap, colr)
+ Display *dsp;
+ Colormap colormap;
+ XColor *colr;
+{
+ int i, match;
+#ifdef MORE_ACCURATE
+ double rd, gd, bd, dist, mindist;
+#else
+ int rd, gd, bd, dist, mindist;
+#endif /* MORE_ACCURATE */
+ int cindx;
+static XColor def_colrs[256];
+static int have_colors = 0;
+ int NumCells;
+
+ match = XAllocColor(dsp, colormap, colr);
+ if (match == 0)
+ {
+ NumCells = DisplayCells(dsp, DefaultScreen(dsp));
+ if (!have_colors)
+ {
+ for (i=0; i<NumCells; i++)
+ {
+ def_colrs[i].pixel = i;
+ }
+ XQueryColors(dsp, colormap, def_colrs, NumCells);
+ have_colors = 1;
+ }
+#ifdef MORE_ACCURATE
+ mindist = 196608.0; /* 256.0 * 256.0 * 3.0 */
+ cindx = colr->pixel;
+ for (i=0; i<NumCells; i++)
+ {
+ rd = (def_colrs[i].red - colr->red) / 256.0;
+ gd = (def_colrs[i].green - colr->green) / 256.0;
+ bd = (def_colrs[i].blue - colr->blue) / 256.0;
+ dist = (rd * rd) +
+ (gd * gd) +
+ (bd * bd);
+ if (dist < mindist)
+ {
+ mindist = dist;
+ cindx = def_colrs[i].pixel;
+ if (dist == 0.0)
+ {
+ break;
+ }
+ }
+ }
+#else
+ mindist = 196608; /* 256 * 256 * 3 */
+ cindx = colr->pixel;
+ for (i=0; i<NumCells; i++)
+ {
+ rd = ((int)(def_colrs[i].red >> 8) -
+ (int)(colr->red >> 8));
+ gd = ((int)(def_colrs[i].green >> 8) -
+ (int)(colr->green >> 8));
+ bd = ((int)(def_colrs[i].blue >> 8) -
+ (int)(colr->blue >> 8));
+ dist = (rd * rd) +
+ (gd * gd) +
+ (bd * bd);
+ if (dist < mindist)
+ {
+ mindist = dist;
+ cindx = def_colrs[i].pixel;
+ if (dist == 0)
+ {
+ break;
+ }
+ }
+ }
+#endif /* MORE_ACCURATE */
+ colr->pixel = cindx;
+ colr->red = def_colrs[cindx].red;
+ colr->green = def_colrs[cindx].green;
+ colr->blue = def_colrs[cindx].blue;
+ }
+ else
+ {
+ /*
+ * Keep a count of how many times we have allocated the
+ * same color, so we can properly free them later.
+ */
+ allocation_index[colr->pixel]++;
+
+ /*
+ * If this is a new color, we've actually changed the default
+ * colormap, and may have to re-query it later.
+ */
+ if (allocation_index[colr->pixel] == 1)
+ {
+ have_colors = 0;
+ }
+ }
+}
+
+
+static int
+highbit(ul)
+unsigned long ul;
+{
+ /*
+ * returns position of highest set bit in 'ul' as an integer (0-31),
+ * or -1 if none.
+ */
+
+ int i;
+ for (i=31; ((ul&0x80000000) == 0) && i>=0; i--, ul<<=1);
+ return i;
+}
+
+
+/*
+ * Make am image of appropriate depth for display from image data.
+ */
+XImage *
+MakeImage(dsp, data, width, height, depth, img_info)
+ Display *dsp;
+ unsigned char *data;
+ int width, height;
+ int depth;
+ ImageInfo *img_info;
+{
+ int linepad, shiftnum;
+ int shiftstart, shiftstop, shiftinc;
+ int bytesperline;
+ int temp;
+ int w, h;
+ XImage *newimage;
+ unsigned char *bit_data, *bitp, *datap;
+ Visual *theVisual;
+ int bmap_order;
+ unsigned long c;
+ int rshift, gshift, bshift;
+
+ switch(depth)
+ {
+ case 6:
+ case 8:
+ bit_data = (unsigned char *)malloc(width * height);
+ bcopy(data, bit_data, (width * height));
+ bytesperline = width;
+ newimage = XCreateImage(dsp,
+ DefaultVisual(dsp, DefaultScreen(dsp)),
+ depth, ZPixmap, 0, (char *)bit_data,
+ width, height, 8, bytesperline);
+ break;
+ case 1:
+ case 2:
+ case 4:
+ if (BitmapBitOrder(dsp) == LSBFirst)
+ {
+ shiftstart = 0;
+ shiftstop = 8;
+ shiftinc = depth;
+ }
+ else
+ {
+ shiftstart = 8 - depth;
+ shiftstop = -depth;
+ shiftinc = -depth;
+ }
+ linepad = 8 - (width % 8);
+ bit_data = (unsigned char *)malloc(((width + linepad) * height)
+ + 1);
+ bitp = bit_data;
+ datap = data;
+ *bitp = 0;
+ shiftnum = shiftstart;
+ for (h=0; h<height; h++)
+ {
+ for (w=0; w<width; w++)
+ {
+ temp = *datap++ << shiftnum;
+ *bitp = *bitp | temp;
+ shiftnum = shiftnum + shiftinc;
+ if (shiftnum == shiftstop)
+ {
+ shiftnum = shiftstart;
+ bitp++;
+ *bitp = 0;
+ }
+ }
+ for (w=0; w<linepad; w++)
+ {
+ shiftnum = shiftnum + shiftinc;
+ if (shiftnum == shiftstop)
+ {
+ shiftnum = shiftstart;
+ bitp++;
+ *bitp = 0;
+ }
+ }
+ }
+ bytesperline = (width + linepad) * depth / 8;
+ newimage = XCreateImage(dsp,
+ DefaultVisual(dsp, DefaultScreen(dsp)),
+ depth, ZPixmap, 0, (char *)bit_data,
+ (width + linepad), height, 8, bytesperline);
+ break;
+ /*
+ * WARNING: This depth 16 code is donated code for 16 but
+ * TrueColor displays. I have no access to such displays, so I
+ * can't really test it.
+ * Donated by - andrew@icarus.demon.co.uk
+ */
+ case 16:
+ bit_data = (unsigned char *)malloc(width * height * 2);
+ bitp = bit_data;
+ datap = data;
+ for (w = (width * height); w > 0; w--)
+ {
+ temp = (((img_info->reds[(int)*datap] >> 1)& 0x7c00) |
+ ((img_info->greens[(int)*datap] >> 6)& 0x03e0) |
+ ((img_info->blues[(int)*datap] >> 11)& 0x001f));
+
+ if (BitmapBitOrder(dsp) == MSBFirst)
+ {
+ *bitp++ = (temp >> 8) & 0xff;
+ *bitp++ = temp & 0xff;
+ }
+ else
+ {
+ *bitp++ = temp & 0xff;
+ *bitp++ = (temp >> 8) & 0xff;
+ }
+
+ datap++;
+ }
+
+ newimage = XCreateImage(dsp,
+ DefaultVisual(dsp, DefaultScreen(dsp)),
+ depth, ZPixmap, 0, (char *)bit_data,
+ width, height, 16, 0);
+ break;
+ case 24:
+ bit_data = (unsigned char *)malloc(width * height * 4);
+
+ theVisual = DefaultVisual(dsp, DefaultScreen(dsp));
+ rshift = highbit(theVisual->red_mask) - 7;
+ gshift = highbit(theVisual->green_mask) - 7;
+ bshift = highbit(theVisual->blue_mask) - 7;
+ bmap_order = BitmapBitOrder(dsp);
+
+ bitp = bit_data;
+ datap = data;
+ for (w = (width * height); w > 0; w--)
+ {
+ c =
+ (((img_info->reds[(int)*datap] >> 8) & 0xff) << rshift) |
+ (((img_info->greens[(int)*datap] >> 8) & 0xff) << gshift) |
+ (((img_info->blues[(int)*datap] >> 8) & 0xff) << bshift);
+
+ datap++;
+
+ if (bmap_order == MSBFirst)
+ {
+ *bitp++ = (unsigned char)((c >> 24) & 0xff);
+ *bitp++ = (unsigned char)((c >> 16) & 0xff);
+ *bitp++ = (unsigned char)((c >> 8) & 0xff);
+ *bitp++ = (unsigned char)(c & 0xff);
+ }
+ else
+ {
+ *bitp++ = (unsigned char)(c & 0xff);
+ *bitp++ = (unsigned char)((c >> 8) & 0xff);
+ *bitp++ = (unsigned char)((c >> 16) & 0xff);
+ *bitp++ = (unsigned char)((c >> 24) & 0xff);
+ }
+ }
+
+ newimage = XCreateImage(dsp,
+ DefaultVisual(dsp, DefaultScreen(dsp)),
+ depth, ZPixmap, 0, (char *)bit_data,
+ width, height, 32, 0);
+ break;
+ default:
+ fprintf(stderr, "Don't know how to format image for display of depth %d\n", depth);
+ return(NULL);
+ }
+
+ return(newimage);
+}
+
+
+int
+AnchoredHeight(hw)
+ HTMLWidget hw;
+{
+ return((int)(AnchoredImage_height + IMAGE_BORDER));
+}
+
+
+char *
+IsMapForm(hw)
+ HTMLWidget hw;
+{
+ char *str;
+
+ str = (char *)malloc(strlen("ISMAP Form") + 1);
+ if (str != NULL)
+ {
+ strcpy(str, "ISMAP Form");
+ }
+ return(str);
+}
+
+
+int
+IsIsMapForm(hw, href)
+ HTMLWidget hw;
+ char *href;
+{
+ if ((href != NULL)&&(strcmp(href, "ISMAP Form") == 0))
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+char *
+DelayedHRef(hw)
+ HTMLWidget hw;
+{
+ char *str;
+
+ str = (char *)malloc(strlen("Delayed Image") + 1);
+ if (str != NULL)
+ {
+ strcpy(str, "Delayed Image");
+ }
+ return(str);
+}
+
+
+int
+IsDelayedHRef(hw, href)
+ HTMLWidget hw;
+ char *href;
+{
+ if ((href != NULL)&&(strcmp(href, "Delayed Image") == 0))
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+Pixmap
+DelayedImage(hw, anchored)
+ HTMLWidget hw;
+ Boolean anchored;
+{
+ if (delayed_image.image == (Pixmap)NULL)
+ {
+ delayed_image.image = XCreatePixmapFromBitmapData(
+ XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), DelayedImage_bits,
+ DelayedImage_width, DelayedImage_height,
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ hw->manager.foreground,
+#else
+ hw->html.foreground,
+#endif /* MOTIF */
+ hw->core.background_pixel,
+ DefaultDepthOfScreen(XtScreen(hw)));
+ }
+
+ if ((anchored == True)&&(anchored_image.image == (Pixmap)NULL))
+ {
+ Pixmap pix;
+
+ anchored_image.image = XCreatePixmapFromBitmapData(
+ XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), AnchoredImage_bits,
+ AnchoredImage_width, AnchoredImage_height,
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ hw->manager.foreground,
+#else
+ hw->html.foreground,
+#endif /* MOTIF */
+ hw->core.background_pixel,
+ DefaultDepthOfScreen(XtScreen(hw)));
+ pix = XCreatePixmap(
+ XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ DelayedImage_width,
+ (DelayedImage_height + AnchoredImage_height +
+ IMAGE_BORDER),
+ DefaultDepthOfScreen(XtScreen(hw)));
+ XSetForeground(XtDisplay(hw), hw->html.drawGC,
+ hw->core.background_pixel);
+ XFillRectangle(XtDisplay(hw->html.view), pix,
+ hw->html.drawGC, 0, 0,
+ DelayedImage_width,
+ (DelayedImage_height + AnchoredImage_height +
+ IMAGE_BORDER));
+ XCopyArea(XtDisplay(hw->html.view),
+ anchored_image.image, pix, hw->html.drawGC,
+ 0, 0, AnchoredImage_width, AnchoredImage_height,
+ 0, 0);
+ XCopyArea(XtDisplay(hw->html.view),
+ delayed_image.image, pix, hw->html.drawGC,
+ 0, 0, DelayedImage_width, DelayedImage_height,
+ 0, (AnchoredImage_height + IMAGE_BORDER));
+ XFreePixmap(XtDisplay(hw->html.view), anchored_image.image);
+ anchored_image.image = pix;
+
+ return(anchored_image.image);
+ }
+
+ return(delayed_image.image);
+}
+
+
+ImageInfo *
+DelayedImageData(hw, anchored)
+ HTMLWidget hw;
+ Boolean anchored;
+{
+ delayed_image.delayed = 1;
+ delayed_image.internal = 0;
+ delayed_image.fetched = 0;
+ delayed_image.width = DelayedImage_width;
+ delayed_image.height = DelayedImage_height;
+ delayed_image.num_colors = 0;
+ delayed_image.reds = NULL;
+ delayed_image.greens = NULL;
+ delayed_image.blues = NULL;
+ delayed_image.image_data = NULL;
+ delayed_image.image = (Pixmap)NULL;
+
+ if (anchored == True)
+ {
+ anchored_image.delayed = 0;
+ anchored_image.internal = 0;
+ anchored_image.fetched = 0;
+ anchored_image.width = DelayedImage_width;
+ anchored_image.height = DelayedImage_height +
+ AnchoredImage_height + IMAGE_BORDER;
+ anchored_image.num_colors = 0;
+ anchored_image.reds = NULL;
+ anchored_image.greens = NULL;
+ anchored_image.blues = NULL;
+ anchored_image.image_data = NULL;
+ anchored_image.image = (Pixmap)NULL;
+
+ return(&anchored_image);
+ }
+
+ return(&delayed_image);
+}
+
+
+Pixmap
+NoImage(hw)
+ HTMLWidget hw;
+{
+ if (no_image.image == (Pixmap)NULL)
+ {
+ no_image.image = XCreatePixmapFromBitmapData(
+ XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), NoImage_bits,
+ NoImage_width, NoImage_height,
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ hw->manager.foreground,
+#else
+ hw->html.foreground,
+#endif /* MOTIF */
+ hw->core.background_pixel,
+ DefaultDepthOfScreen(XtScreen(hw)));
+ }
+ return(no_image.image);
+}
+
+
+ImageInfo *
+NoImageData(hw)
+ HTMLWidget hw;
+{
+ no_image.delayed = 0;
+ no_image.internal = 0;
+ no_image.fetched = 0;
+ no_image.width = NoImage_width;
+ no_image.height = NoImage_height;
+ no_image.num_colors = 0;
+ no_image.reds = NULL;
+ no_image.greens = NULL;
+ no_image.blues = NULL;
+ no_image.image_data = NULL;
+ no_image.image = (Pixmap)NULL;
+
+ return(&no_image);
+}
+
+
+Pixmap
+InfoToImage(hw, img_info)
+ HTMLWidget hw;
+ ImageInfo *img_info;
+{
+ int i, size;
+ int delta, not_right_col, not_last_row;
+ Pixmap Img;
+ XImage *tmpimage;
+ XColor tmpcolr;
+ int *Mapping;
+ unsigned char *tmpdata;
+ unsigned char *ptr;
+ unsigned char *ptr2;
+ int Vclass;
+ XVisualInfo vinfo, *vptr;
+ Boolean need_to_dither;
+ unsigned long black_pixel;
+ unsigned long white_pixel;
+
+ /* find the visual class. */
+ vinfo.visualid = XVisualIDFromVisual(DefaultVisual(XtDisplay(hw),
+ DefaultScreen(XtDisplay(hw))));
+ vptr = XGetVisualInfo(XtDisplay(hw), VisualIDMask, &vinfo, &i);
+ Vclass = vptr->class;
+ if (vptr->depth == 1)
+ {
+ need_to_dither = True;
+ black_pixel = BlackPixel(XtDisplay(hw),
+ DefaultScreen(XtDisplay(hw)));
+ white_pixel = WhitePixel(XtDisplay(hw),
+ DefaultScreen(XtDisplay(hw)));
+ }
+ else
+ {
+ need_to_dither = False;
+ }
+ XFree((char *)vptr);
+
+ Mapping = (int *)malloc(img_info->num_colors * sizeof(int));
+
+ for (i=0; i < img_info->num_colors; i++)
+ {
+ tmpcolr.red = img_info->reds[i];
+ tmpcolr.green = img_info->greens[i];
+ tmpcolr.blue = img_info->blues[i];
+ tmpcolr.flags = DoRed|DoGreen|DoBlue;
+ if ((Vclass == TrueColor) || (Vclass == DirectColor))
+ {
+ Mapping[i] = i;
+ }
+ else if (need_to_dither == True)
+ {
+ Mapping[i] = (int)((tmpcolr.red>>5)*11 +
+ (tmpcolr.green>>5)*16 +
+ (tmpcolr.blue>>5)*5) / (65504/64);
+ }
+ else
+ {
+ FindColor(XtDisplay(hw),
+ DefaultColormapOfScreen(XtScreen(hw)),
+ &tmpcolr);
+ Mapping[i] = tmpcolr.pixel;
+ }
+ }
+
+ /*
+ * Special case: For 2 color non-black&white images, instead
+ * of 2 dither patterns, we will always drop them to be
+ * black on white.
+ */
+ if ((need_to_dither == True)&&(img_info->num_colors == 2))
+ {
+ if (Mapping[0] < Mapping[1])
+ {
+ Mapping[0] = 0;
+ Mapping[1] = 64;
+ }
+ else
+ {
+ Mapping[0] = 64;
+ Mapping[1] = 0;
+ }
+ }
+
+ size = img_info->width * img_info->height;
+ if (size == 0)
+ {
+ tmpdata = NULL;
+ }
+ else
+ {
+ tmpdata = (unsigned char *)malloc(size);
+ }
+ if (tmpdata == NULL)
+ {
+ tmpimage = NULL;
+ Img = (Pixmap)NULL;
+ }
+ else
+ {
+ ptr = img_info->image_data;
+ ptr2 = tmpdata;
+
+ if (need_to_dither == True)
+ {
+ int cx, cy;
+
+ for (ptr2 = tmpdata, ptr = img_info->image_data;
+ ptr2 < tmpdata+(size-1); ptr2++, ptr++)
+ {
+ *ptr2 = Mapping[(int)*ptr];
+ }
+
+ ptr2 = tmpdata;
+ for (cy=0; cy < img_info->height; cy++)
+ {
+ for (cx=0; cx < img_info->width; cx++)
+ {
+ /*
+ * Assume high numbers are
+ * really negative.
+ */
+ if (*ptr2 > 128)
+ {
+ *ptr2 = 0;
+ }
+ if (*ptr2 > 64)
+ {
+ *ptr2 = 64;
+ }
+
+ /*
+ * Traditional Floyd-Steinberg
+ */
+ if (*ptr2 < 32)
+ {
+ delta = *ptr2;
+ *ptr2 = black_pixel;
+ }
+ else
+ {
+ delta = *ptr2 - 64;
+ *ptr2 = white_pixel;
+ }
+ if (not_right_col =
+ (cx < (img_info->width-1)))
+ {
+ *(ptr2+1) += delta*7 >> 4;
+ }
+
+ if (not_last_row =
+ (cy < (img_info->height-1)))
+ {
+ (*(ptr2+img_info->width)) +=
+ delta*5 >> 4;
+ }
+
+ if (not_right_col && not_last_row)
+ {
+ (*(ptr2+img_info->width+1)) +=
+ delta >> 4;
+ }
+
+ if (cx && not_last_row)
+ {
+ (*(ptr2+img_info->width-1)) +=
+ delta*3 >> 4;
+ }
+ ptr2++;
+ }
+ }
+ } /* end if (need_to_dither==True) */
+ else
+ {
+
+ for (i=0; i < size; i++)
+ {
+ *ptr2++ = (unsigned char)Mapping[(int)*ptr];
+ ptr++;
+ }
+ }
+
+ tmpimage = MakeImage(XtDisplay(hw), tmpdata,
+ img_info->width, img_info->height,
+ DefaultDepthOfScreen(XtScreen(hw)), img_info);
+
+ /* Caught by Purify; should be OK. */
+ free (tmpdata);
+
+ Img = XCreatePixmap(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ img_info->width, img_info->height,
+ DefaultDepthOfScreen(XtScreen(hw)));
+ }
+
+ if ((tmpimage == NULL)||(Img == (Pixmap)NULL))
+ {
+ if (tmpimage != NULL)
+ {
+ XDestroyImage(tmpimage);
+ }
+ if (Img != (Pixmap)NULL)
+ {
+ XFreePixmap(XtDisplay(hw), Img);
+ }
+ img_info->width = NoImage_width;
+ img_info->height = NoImage_height;
+ Img = NoImage(hw);
+ }
+ else
+ {
+ XPutImage(XtDisplay(hw), Img, hw->html.drawGC, tmpimage, 0, 0,
+ 0, 0, img_info->width, img_info->height);
+ XDestroyImage(tmpimage);
+ }
+
+ /* Caught by Purify; should be OK. */
+ free((char *)Mapping);
+
+ return(Img);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/HTMLjot.c b/vendor/x11iraf/obm/ObmW/HTMLjot.c
new file mode 100644
index 00000000..75efb2b3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLjot.c
@@ -0,0 +1,642 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+/* #ifdef MOTIF */
+
+#include <stdio.h>
+#include "inkstore.h"
+#include "HTMLP.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef struct stroke_rec {
+ Boolean draw;
+ int x, y;
+ struct stroke_rec *next;
+} Stroke;
+
+typedef struct jot_rec {
+ Widget w;
+ int width, height;
+ Pixmap pix;
+ Boolean drawing;
+ int last_x, last_y;
+ int min_x, min_y;
+ int max_x, max_y;
+ int stroke_cnt;
+ Stroke *strokes;
+ Stroke *last_stroke;
+ struct jot_rec *next;
+} JotInfo;
+
+
+static JotInfo *JotList = NULL;
+static JotInfo *JotCurrent = NULL;
+
+
+
+void
+NewJot(w, width, height)
+ Widget w;
+ int width, height;
+{
+ if (JotCurrent == NULL)
+ {
+ JotList = (JotInfo *)malloc(sizeof(JotInfo));
+ JotCurrent = JotList;
+ JotCurrent->w = w;
+ JotCurrent->width = width;
+ JotCurrent->height = height;
+ JotCurrent->pix = NULL;
+ JotCurrent->drawing = False;
+ JotCurrent->strokes = NULL;
+ JotCurrent->last_stroke = NULL;
+ JotCurrent->stroke_cnt = 0;
+ JotCurrent->min_x = width;
+ JotCurrent->max_x = 0;
+ JotCurrent->min_y = height;
+ JotCurrent->max_y = 0;
+ JotCurrent->next = NULL;
+ }
+ else
+ {
+ JotCurrent->next = (JotInfo *)malloc(sizeof(JotInfo));
+ JotCurrent = JotCurrent->next;
+ JotCurrent->w = w;
+ JotCurrent->width = width;
+ JotCurrent->height = height;
+ JotCurrent->pix = NULL;
+ JotCurrent->drawing = False;
+ JotCurrent->strokes = NULL;
+ JotCurrent->last_stroke = NULL;
+ JotCurrent->stroke_cnt = 0;
+ JotCurrent->min_x = width;
+ JotCurrent->max_x = 0;
+ JotCurrent->min_y = height;
+ JotCurrent->max_y = 0;
+ JotCurrent->next = NULL;
+ }
+}
+
+
+JotInfo *
+GetJot(w)
+ Widget w;
+{
+ JotInfo *jptr;
+
+ jptr = JotList;
+ while (jptr != NULL)
+ {
+ if (jptr->w == w)
+ {
+ break;
+ }
+ jptr = jptr->next;
+ }
+ return(jptr);
+}
+
+
+void
+FreeStrokes(sptr)
+ Stroke *sptr;
+{
+ Stroke *tptr;
+
+ while (sptr != NULL)
+ {
+ tptr = sptr;
+ sptr = sptr->next;
+ tptr->next = NULL;
+ free((char *)tptr);
+ }
+}
+
+
+void
+ClearJot(hw, w, width, height)
+ HTMLWidget hw;
+ Widget w;
+ int width, height;
+{
+ JotInfo *jptr;
+
+ XClearArea(XtDisplay(w), XtWindow(w),
+ 0, 0, width, height, False);
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return;
+ }
+
+ if (jptr->pix != NULL)
+ {
+ XSetForeground(XtDisplay(w), hw->html.drawGC,
+ hw->core.background_pixel);
+ XFillRectangle(XtDisplay(w), jptr->pix,
+ hw->html.drawGC,
+ 0, 0, jptr->width, jptr->height);
+ }
+
+ FreeStrokes(jptr->strokes);
+ jptr->strokes = NULL;
+ jptr->last_stroke = NULL;
+ jptr->stroke_cnt = 0;
+ jptr->drawing = False;
+ jptr->min_x = width;
+ jptr->max_x = 0;
+ jptr->min_y = height;
+ jptr->max_y = 0;
+}
+
+
+void
+AddStroke(jptr, sptr, drawing)
+ JotInfo *jptr;
+ Stroke *sptr;
+ Boolean drawing;
+{
+ if (jptr->strokes == NULL)
+ {
+ jptr->strokes = sptr;
+ jptr->last_stroke = jptr->strokes;
+ jptr->last_stroke->next = NULL;
+ }
+ else
+ {
+ jptr->last_stroke->next = sptr;
+ jptr->last_stroke = jptr->last_stroke->next;
+ jptr->last_stroke->next = NULL;
+ }
+ jptr->last_x = sptr->x;
+ jptr->last_y = sptr->y;
+ jptr->drawing = drawing;
+ if (sptr->x < jptr->min_x)
+ {
+ jptr->min_x = sptr->x;
+ }
+ if (sptr->x > jptr->max_x)
+ {
+ jptr->max_x = sptr->x;
+ }
+ if (sptr->y < jptr->min_y)
+ {
+ jptr->min_y = sptr->y;
+ }
+ if (sptr->y > jptr->max_y)
+ {
+ jptr->max_y = sptr->y;
+ }
+ jptr->stroke_cnt++;
+}
+
+
+void
+EVJotExpose(w, data, event)
+ Widget w;
+ XtPointer data;
+ XEvent *event;
+{
+ XExposeEvent *ExEvent = (XExposeEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ JotInfo *jptr;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return;
+ }
+
+ if (jptr->pix == NULL)
+ {
+ jptr->pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
+ jptr->width, jptr->height,
+ XDefaultDepth(XtDisplay(w), XDefaultScreen(XtDisplay(w))));
+ if (jptr->pix == NULL)
+ {
+ return;
+ }
+ XSetForeground(XtDisplay(w), hw->html.drawGC,
+ hw->core.background_pixel);
+ XFillRectangle(XtDisplay(w), jptr->pix,
+ hw->html.drawGC,
+ 0, 0, jptr->width, jptr->height);
+ }
+
+ XCopyArea(XtDisplay(w), jptr->pix, XtWindow(w),
+ hw->html.drawGC,
+ ExEvent->x, ExEvent->y,
+ ExEvent->width, ExEvent->height,
+ ExEvent->x, ExEvent->y);
+}
+
+
+void
+EVJotPress(w, data, event)
+ Widget w;
+ XtPointer data;
+ XEvent *event;
+{
+ XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ JotInfo *jptr;
+ Stroke *sptr;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return;
+ }
+
+ sptr = (Stroke *)malloc(sizeof(Stroke));
+ if (sptr == NULL)
+ {
+ return;
+ }
+ sptr->x = BuEvent->x;
+ sptr->y = BuEvent->y;
+ sptr->draw = False;
+ sptr->next = NULL;
+
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+ XSetForeground(XtDisplay(w), hw->html.drawGC,
+#ifdef MOTIF
+ hw->manager.foreground);
+#else
+ hw->html.foreground);
+#endif /* MOTIF */
+ XDrawPoint(XtDisplay(w), XtWindow(w),
+ hw->html.drawGC, sptr->x, sptr->y);
+ if (jptr->pix != NULL)
+ {
+ XDrawPoint(XtDisplay(w), jptr->pix,
+ hw->html.drawGC, sptr->x, sptr->y);
+ }
+
+ AddStroke(jptr, sptr, True);
+}
+
+
+void
+EVJotMove(w, data, event)
+ Widget w;
+ XtPointer data;
+ XEvent *event;
+{
+ XPointerMovedEvent *MoEvent = (XPointerMovedEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ JotInfo *jptr;
+ Stroke *sptr;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return;
+ }
+
+ if (jptr->drawing == False)
+ {
+ return;
+ }
+
+ sptr = (Stroke *)malloc(sizeof(Stroke));
+ if (sptr == NULL)
+ {
+ return;
+ }
+ sptr->x = MoEvent->x;
+ sptr->y = MoEvent->y;
+ sptr->draw = True;
+ sptr->next = NULL;
+
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+ XSetForeground(XtDisplay(w), hw->html.drawGC,
+#ifdef MOTIF
+ hw->manager.foreground);
+#else
+ hw->html.foreground);
+#endif /* MOTIF */
+ XDrawLine(XtDisplay(w), XtWindow(w), hw->html.drawGC,
+ jptr->last_x, jptr->last_y, sptr->x, sptr->y);
+ if (jptr->pix != NULL)
+ {
+ XDrawLine(XtDisplay(w), jptr->pix, hw->html.drawGC,
+ jptr->last_x, jptr->last_y, sptr->x, sptr->y);
+ }
+
+ AddStroke(jptr, sptr, True);
+}
+
+
+void
+EVJotRelease(w, data, event)
+ Widget w;
+ XtPointer data;
+ XEvent *event;
+{
+ XButtonReleasedEvent *BuEvent = (XButtonReleasedEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ JotInfo *jptr;
+ Stroke *sptr;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return;
+ }
+
+ if (jptr->drawing == False)
+ {
+ return;
+ }
+
+ sptr = (Stroke *)malloc(sizeof(Stroke));
+ if (sptr == NULL)
+ {
+ return;
+ }
+ sptr->x = BuEvent->x;
+ sptr->y = BuEvent->y;
+ sptr->draw = True;
+ sptr->next = NULL;
+
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+ XSetForeground(XtDisplay(w), hw->html.drawGC,
+#ifdef MOTIF
+ hw->manager.foreground);
+#else
+ hw->html.foreground);
+#endif /* MOTIF */
+ XDrawLine(XtDisplay(w), XtWindow(w), hw->html.drawGC,
+ jptr->last_x, jptr->last_y, sptr->x, sptr->y);
+ if (jptr->pix != NULL)
+ {
+ XDrawLine(XtDisplay(w), jptr->pix, hw->html.drawGC,
+ jptr->last_x, jptr->last_y, sptr->x, sptr->y);
+ }
+
+ AddStroke(jptr, sptr, True);
+}
+
+
+char *
+EJB_JOTfromJot(w)
+ Widget w;
+{
+ int i, cnt;
+ int dlen, total;
+ u_long val;
+ unsigned char uchar;
+ JotInfo *jptr;
+ Stroke *sptr;
+ unsigned char *data;
+ unsigned char *dptr;
+ unsigned char *buffer;
+ unsigned char *bptr;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return(NULL);
+ }
+
+ dlen = (2 * sizeof(u_long) + sizeof(char)) * jptr->stroke_cnt;
+ data = (unsigned char *)malloc(dlen);
+
+ cnt = 0;
+ sptr = jptr->strokes;
+ dptr = data;
+ while ((sptr != NULL)&&(cnt < jptr->stroke_cnt))
+ {
+ val = htonl((u_long)sptr->x);
+ bcopy((char *)&val, (char *)dptr, sizeof(u_long));
+ dptr = dptr + sizeof(u_long);
+
+ val = htonl((u_long)sptr->y);
+ bcopy((char *)&val, (char *)dptr, sizeof(u_long));
+ dptr = dptr + sizeof(u_long);
+
+ if (sptr->draw == False)
+ {
+ uchar = 0;
+ }
+ else
+ {
+ uchar = 1;
+ }
+ *dptr++ = uchar;
+
+ cnt++;
+ sptr = sptr->next;
+ }
+ for (i=cnt; i<jptr->stroke_cnt; i++)
+ {
+ val = 0;
+ bcopy((char *)&val, (char *)dptr, sizeof(u_long));
+ dptr = dptr + sizeof(u_long);
+ val = 0;
+ bcopy((char *)&val, (char *)dptr, sizeof(u_long));
+ dptr = dptr + sizeof(u_long);
+ uchar = 0;
+ *dptr++ = uchar;
+ }
+fprintf(stderr, "Packaging up %d points\n", jptr->stroke_cnt);
+
+ cnt = 0;
+ dptr = data;
+ for (i=0; i<dlen; i++)
+ {
+ if ((*dptr == 0)||(*dptr == 1))
+ {
+ cnt++;
+ }
+ dptr++;
+ }
+
+ total = dlen + cnt + 1;
+ buffer = (unsigned char *)malloc(total);
+ bptr = buffer;
+ dptr = data;
+ for (i=0; i<dlen; i++)
+ {
+ if (*dptr == 0)
+ {
+ *bptr++ = (unsigned char)'o';
+ *bptr++ = (unsigned char)'O';
+ }
+ else if (*dptr == 'o')
+ {
+ *bptr++ = (unsigned char)'o';
+ *bptr++ = (unsigned char)'o';
+ }
+ else
+ {
+ *bptr++ = *dptr;
+ }
+ dptr++;
+ }
+ *bptr = (unsigned char)'\0';
+ free((char *)data);
+
+ return((char *)buffer);
+}
+
+
+
+typedef struct my_INK_POINT {
+ XY32 position;
+ INK_BUTTONS buttons;
+} MY_INK_POINT;
+
+
+unsigned char *
+JOTfromJot(w, buffer_len)
+ Widget w;
+ int *buffer_len;
+{
+ int i, cnt;
+ int dlen, total;
+ JotInfo *jptr;
+ Stroke *sptr;
+ MY_INK_POINT *dataArray;
+ INK_BUNDLE_RECORD *iptr;
+ INK_PENDATA_RECORD *pptr;
+ INK_END_RECORD *eptr;
+ unsigned char *buffer;
+
+ jptr = GetJot(w);
+ if (jptr == NULL)
+ {
+ return(NULL);
+ }
+
+ dlen = sizeof(MY_INK_POINT) * jptr->stroke_cnt;
+
+ dataArray = (MY_INK_POINT *)malloc(dlen);
+ cnt = 0;
+ sptr = jptr->strokes;
+ while ((sptr != NULL)&&(cnt < jptr->stroke_cnt));
+ {
+ dataArray[cnt].position.x = sptr->x;
+ dataArray[cnt].position.y = sptr->y;
+ dataArray[cnt].buttons = inkPointDefaultButtons;
+ dataArray[cnt].buttons |= flag0;
+ if ((sptr->next != NULL)&&(sptr->next->draw == False))
+ {
+ }
+ else
+ {
+ dataArray[cnt].buttons |= flag1;
+ }
+ cnt++;
+ sptr = sptr->next;
+ }
+ for (i=cnt; i<jptr->stroke_cnt; i++)
+ {
+ dataArray[i].position.x = 0;
+ dataArray[i].position.y = 0;
+ dataArray[i].buttons = inkPointDefaultButtons;
+ }
+
+ iptr = (INK_BUNDLE_RECORD *)malloc(inkRecordBundleSize);
+ iptr->header.recordType = inkRecordBundle;
+ iptr->header.recordLength = inkRecordBundleSize;
+ iptr->version = inkPointDefaultVersion;
+ iptr->compactionType = inkNoCompression;
+ iptr->flags = (inkPointDefaultBundleFlags | inkButtonDataPresent);
+ iptr->penUnitsPerX = inkPointDefaultPenUnitsPerX;
+ iptr->penUnitsPerY = inkPointDefaultPenUnitsPerY;
+
+ pptr = (INK_PENDATA_RECORD *)malloc(inkRecordPenDataSize(dlen));
+ pptr->header.recordType = inkRecordPenData;
+ pptr->header.recordLength = inkRecordPenDataSize(dlen);
+ pptr->bounds.origin.x = jptr->min_x;
+ pptr->bounds.origin.y = jptr->min_y;
+ pptr->bounds.size.w = jptr->max_x - jptr->min_x + 1;
+ pptr->bounds.size.h = jptr->max_y - jptr->min_y + 1;
+ bcopy((char *)dataArray, (char *)pptr->inkData, dlen);
+ free((char *)dataArray);
+/*
+ pptr->inkData = dataArray;
+*/
+
+ eptr = (INK_END_RECORD *)malloc(inkRecordEndSize);
+ eptr->header.recordType = inkRecordEnd;
+
+ total = inkRecordBundleSize + inkRecordPenDataSize(dlen) +
+ inkRecordEndSize;
+ buffer = (unsigned char *)malloc(total);
+ bcopy((char *)iptr, buffer, inkRecordBundleSize);
+ bcopy((char *)pptr, (char *)(buffer + inkRecordBundleSize),
+ inkRecordPenDataSize(dlen));
+ bcopy((char *)eptr, (char *)(buffer + inkRecordBundleSize +
+ inkRecordPenDataSize(dlen)), inkRecordEndSize);
+ free((char *)iptr);
+ free((char *)pptr);
+ free((char *)eptr);
+ *buffer_len = total;
+ return(buffer);
+}
+/* #endif /* MOTIF */
diff --git a/vendor/x11iraf/obm/ObmW/HTMLlists.c b/vendor/x11iraf/obm/ObmW/HTMLlists.c
new file mode 100644
index 00000000..dfe3578d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLlists.c
@@ -0,0 +1,897 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include "HTML.h"
+
+/*
+ * Code to manage a linked list of parsed HTML objects generated
+ * from a raw text file.
+ * Also code to manage a linked list of formatted elements that
+ * make up a page of a formatted document.
+ */
+
+
+/*
+ * Free up the passed linked list of parsed elements, freeing
+ * all memory associates with each element.
+ */
+void
+FreeObjList(List)
+ struct mark_up *List;
+{
+ struct mark_up *current;
+ struct mark_up *mptr;
+
+ current = List;
+ while (current != NULL)
+ {
+ mptr = current;
+ current = current->next;
+ mptr->next = NULL;
+ if (mptr->start != NULL)
+ {
+ free((char *)mptr->start);
+ }
+ if (mptr->text != NULL)
+ {
+ free((char *)mptr->text);
+ }
+ if (mptr->end != NULL)
+ {
+ free((char *)mptr->end);
+ }
+ free((char *)mptr);
+ }
+}
+
+
+/*
+ * Add an object to the parsed object list.
+ * return a pointer to the current (end) position in the list.
+ * If the object is a normal text object containing nothing but
+ * white space, throw it out, unless we have been told to keep
+ * white space.
+ */
+struct mark_up *
+AddObj(listp, current, mark, keep_wsp)
+ struct mark_up **listp;
+ struct mark_up *current;
+ struct mark_up *mark;
+ int keep_wsp;
+{
+ if (mark == NULL)
+ {
+ return(current);
+ }
+
+ /*
+ * Throw out normal text blocks that are only white space,
+ * unless keep_wsp is set.
+ */
+ if ((mark->type == M_NONE)&&(!keep_wsp))
+ {
+ char *ptr;
+
+ ptr = mark->text;
+ if (ptr == NULL)
+ {
+ free((char *)mark);
+ return(current);
+ }
+
+/*
+ * No longer throw out whitespace, it is important to keep
+ * white space between tags.
+ while ((*ptr == ' ')||(*ptr == '\t')||(*ptr == '\n'))
+ {
+ ptr++;
+ }
+ *
+ */
+
+ if (*ptr == '\0')
+ {
+ free(mark->text);
+ free((char *)mark);
+ return(current);
+ }
+ }
+
+ /*
+ * Add object to either the head of the list for a new list,
+ * or at the end after the current pointer.
+ */
+ if (*listp == NULL)
+ {
+ *listp = mark;
+ current = *listp;
+ }
+ else
+ {
+ current->next = mark;
+ current = current->next;
+ }
+
+ current->next = NULL;
+
+ return(current);
+}
+
+
+#ifdef DEBUG
+
+/*
+ * Convert type number to a printed string for debug
+ */
+void
+PrintType(type)
+ int type;
+{
+ switch(type)
+ {
+ case M_NONE:
+ printf("M_NONE");
+ break;
+ case M_TITLE:
+ printf("M_TITLE");
+ break;
+ case M_FIXED:
+ printf("M_FIXED");
+ break;
+ case M_BOLD:
+ printf("M_BOLD");
+ break;
+ case M_ITALIC:
+ printf("M_ITALIC");
+ break;
+ case M_EMPHASIZED:
+ printf("M_EMPHASIZED");
+ break;
+ case M_STRONG:
+ printf("M_STRONG");
+ break;
+ case M_CODE:
+ printf("M_CODE");
+ break;
+ case M_SAMPLE:
+ printf("M_SAMPLE");
+ break;
+ case M_KEYBOARD:
+ printf("M_KEYBOARD");
+ break;
+ case M_VARIABLE:
+ printf("M_VARIABLE");
+ break;
+ case M_CITATION:
+ printf("M_CITATION");
+ break;
+ case M_STRIKEOUT:
+ printf("M_STRIKEOUT");
+ break;
+ case M_HEADER_1:
+ printf("M_HEADER_1");
+ break;
+ case M_HEADER_2:
+ printf("M_HEADER_2");
+ break;
+ case M_HEADER_3:
+ printf("M_HEADER_3");
+ break;
+ case M_HEADER_4:
+ printf("M_HEADER_4");
+ break;
+ case M_HEADER_5:
+ printf("M_HEADER_5");
+ break;
+ case M_HEADER_6:
+ printf("M_HEADER_6");
+ break;
+ case M_ANCHOR:
+ printf("M_ANCHOR");
+ break;
+ case M_PARAGRAPH:
+ printf("M_PARAGRAPH");
+ break;
+ case M_ADDRESS:
+ printf("M_ADDRESS");
+ break;
+ case M_PLAIN_TEXT:
+ printf("M_PLAIN_TEXT");
+ break;
+ case M_LISTING_TEXT:
+ printf("M_LISTING_TEXT");
+ break;
+ case M_UNUM_LIST:
+ printf("M_UNUM_LIST");
+ break;
+ case M_NUM_LIST:
+ printf("M_NUM_LIST");
+ break;
+ case M_MENU:
+ printf("M_MENU");
+ break;
+ case M_DIRECTORY:
+ printf("M_DIRECTORY");
+ break;
+ case M_LIST_ITEM:
+ printf("M_LIST_ITEM");
+ break;
+ case M_DESC_LIST:
+ printf("M_DESC_LIST");
+ break;
+ case M_DESC_TITLE:
+ printf("M_DESC_TITLE");
+ break;
+ case M_DESC_TEXT:
+ printf("M_DESC_TEXT");
+ break;
+ case M_IMAGE:
+ printf("M_IMAGE");
+ break;
+ case M_SELECT:
+ printf("M_SELECT");
+ break;
+ case M_OPTION:
+ printf("M_OPTION");
+ break;
+ case M_INPUT:
+ printf("M_INPUT");
+ break;
+ case M_TEXTAREA:
+ printf("M_TEXTAREA");
+ break;
+ case M_FORM:
+ printf("M_FORM");
+ break;
+ case M_INDEX:
+ printf("M_INDEX");
+ break;
+ case M_HRULE:
+ printf("M_HRULE");
+ break;
+ case M_BASE:
+ printf("M_BASE");
+ break;
+ case M_LINEBREAK:
+ printf("M_LINEBREAK");
+ break;
+ case M_BLOCKQUOTE:
+ printf("M_BLOCKQUOTE");
+ break;
+ default:
+ printf("UNKNOWN %d", type);
+ break;
+ }
+}
+
+
+/*
+ * Print the contents of a parsed object list, for debug
+ */
+void
+PrintList(list)
+ struct mark_up *list;
+{
+ struct mark_up *mptr;
+
+ mptr = list;
+ while (mptr != NULL)
+ {
+ PrintType(mptr->type);
+ if (mptr->is_end)
+ {
+ printf(" END");
+ }
+ else
+ {
+ printf(" START");
+ }
+ if (mptr->text != NULL)
+ {
+ printf("\n{\n\t");
+ printf("%s", mptr->text);
+ printf("}\n");
+ }
+ else
+ {
+ printf("\n");
+ }
+ mptr = mptr->next;
+ }
+}
+
+#endif /* DEBUG */
+
+
+/*
+ * Used to find the longest line (in characters) in a collection
+ * of text blocks. cnt is the running count of characters, and
+ * txt is the pointer to the current text block. Since we are
+ * finding line widths, a newline resets the width count.
+ */
+char *
+MaxTextWidth(txt, cnt)
+ char *txt;
+ int *cnt;
+{
+ char *start;
+ char *end;
+ int width;
+
+ if (txt == NULL)
+ {
+ return(NULL);
+ }
+
+ width = *cnt;
+ start = txt;
+
+ /*
+ * If this blocks starts with a newline, reset the width
+ * count, and skip the newline.
+ */
+ if (*start == '\n')
+ {
+ width = 0;
+ start++;
+ }
+
+ end = start;
+
+ /*
+ * count characters, stoping either at a newline, or at the
+ * end of this text block. Expand tabs.
+ */
+ while ((*end != '\0')&&(*end != '\n'))
+ {
+ if (*end == '\t')
+ {
+ width = ((width / 8) + 1) * 8;
+ }
+ else
+ {
+ width++;
+ }
+ end++;
+ }
+
+ *cnt = width;
+ return(end);
+}
+
+
+/*
+ * Free up the passed linked list of formatted elements, freeing
+ * all memory associates with each element.
+ */
+void
+FreeLineList(list)
+ struct ele_rec *list;
+{
+ struct ele_rec *current;
+ struct ele_rec *eptr;
+
+ current = list;
+ while (current != NULL)
+ {
+ eptr = current;
+ current = current->next;
+ eptr->next = NULL;
+ if (eptr->edata != NULL)
+ {
+ free((char *)eptr->edata);
+ }
+ if (eptr->anchorHRef != NULL)
+ {
+ free((char *)eptr->anchorHRef);
+ }
+ if (eptr->anchorName != NULL)
+ {
+ free((char *)eptr->anchorName);
+ }
+ free((char *)eptr);
+ }
+}
+
+
+/*
+ * Add an element to the linked list of formatted elements.
+ * return a pointer to the current (end) position in the list.
+ */
+struct ele_rec *
+AddEle(elistp, current, eptr)
+ struct ele_rec **elistp;
+ struct ele_rec *current;
+ struct ele_rec *eptr;
+{
+ if (eptr == NULL)
+ {
+ return(current);
+ }
+
+ /*
+ * Add object to either the head of the list for a new list,
+ * or at the end after the current pointer.
+ */
+ if (*elistp == NULL)
+ {
+ *elistp = eptr;
+ (*elistp)->next = NULL;
+ (*elistp)->prev = NULL;
+ current = *elistp;
+ }
+ else
+ {
+ current->next = eptr;
+ eptr->prev = current;
+ current = current->next;
+ current->next = NULL;
+ }
+ return(current);
+}
+
+
+/*
+ * Contruct and return an array of pointers into the element list that
+ * indexes the elements by line number.
+ * Note, lines containing only while space will have NULL pointers
+ * into the element list.
+ */
+struct ele_rec **
+MakeLineList(elist, max_line)
+ struct ele_rec *elist;
+ int max_line;
+{
+ int i;
+ struct ele_rec *eptr;
+ struct ele_rec **ll;
+
+ /*
+ * malloc index array
+ */
+ ll = (struct ele_rec **)malloc(sizeof(struct ele_rec *) * max_line);
+ if (ll == NULL)
+ {
+ fprintf(stderr, "cannot allocate space for line list\n");
+ exit(1);
+ }
+
+ /*
+ * zero the index array
+ */
+ for (i=0; i<max_line; i++)
+ {
+ ll[i] = NULL;
+ }
+
+ /*
+ * fill in pointers to beginning of the lines
+ */
+ eptr = elist;
+ while (eptr != NULL)
+ {
+ if (eptr->line_number > max_line)
+ {
+ break;
+ }
+
+ if (ll[eptr->line_number - 1] == NULL)
+ {
+ ll[eptr->line_number - 1] = eptr;
+ }
+
+ eptr = eptr->next;
+ }
+ return(ll);
+}
+
+
+/*
+ * Passed in 2 element pointers, and element positions.
+ * Function should return 1 if if start occurs before end.
+ * Otherwise return 0.
+ */
+int
+ElementLessThan(start, end, start_pos, end_pos)
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *current;
+
+ /*
+ * Deal with start or end being NULL
+ */
+ if ((start == NULL)&&(end == NULL))
+ {
+ return(0);
+ }
+ else if ((start == NULL)&&(end != NULL))
+ {
+ return(1);
+ }
+ else if ((start != NULL)&&(end == NULL))
+ {
+ return(0);
+ }
+
+ /*
+ * Deal with easy identical case
+ */
+ if (start == end)
+ {
+ if (start_pos < end_pos)
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+ }
+
+ /*
+ * We know element Ids are always equal or increasing within a
+ * list.
+ */
+ if (start->ele_id < end->ele_id)
+ {
+ return(1);
+ }
+ else if (start->ele_id == end->ele_id)
+ {
+ current = start;
+ while (current != NULL)
+ {
+ if (current->ele_id != start->ele_id)
+ {
+ break;
+ }
+ else if (current == end)
+ {
+ break;
+ }
+ current = current->next;
+ }
+ if (current == end)
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+/*
+ * Passed in 2 element pointers, and element positions.
+ * Function should return 1 if they need to be swapped in order for then
+ * to proceed left to right and top to bottom in the text.
+ * Otherwise return 0.
+ */
+int
+SwapElements(start, end, start_pos, end_pos)
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *current;
+
+ /*
+ * Deal with start or end being NULL
+ */
+ if ((start == NULL)&&(end == NULL))
+ {
+ return(0);
+ }
+ else if ((start == NULL)&&(end != NULL))
+ {
+ return(1);
+ }
+ else if ((start != NULL)&&(end == NULL))
+ {
+ return(0);
+ }
+
+ /*
+ * Deal with easy identical case
+ */
+ if (start == end)
+ {
+ if (start_pos > end_pos)
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+ }
+
+ /*
+ * We know element Ids are always equal or increasing within a
+ * list.
+ */
+ if (start->ele_id < end->ele_id)
+ {
+ return(0);
+ }
+ else if (start->ele_id == end->ele_id)
+ {
+ current = start;
+ while (current != NULL)
+ {
+ if (current->ele_id != start->ele_id)
+ {
+ break;
+ }
+ else if (current == end)
+ {
+ break;
+ }
+ current = current->next;
+ }
+ if (current == end)
+ {
+ return(0);
+ }
+ else
+ {
+ return(1);
+ }
+ }
+ else
+ {
+ return(1);
+ }
+}
+
+
+/*
+ * Free up the allocated list of internal hrefs.
+ */
+void
+FreeHRefs(list)
+ struct ref_rec *list;
+{
+ struct ref_rec *hptr;
+ struct ref_rec *tptr;
+
+ hptr = list;
+ while (hptr != NULL)
+ {
+ tptr = hptr;
+ hptr = hptr->next;
+ if (tptr->anchorHRef != NULL)
+ {
+ free((char *)tptr->anchorHRef);
+ }
+ free((char *)tptr);
+ }
+}
+
+
+/*
+ * Find an element in the linked list of Internal HREFS.
+ * return a pointer to the element, or NULL if not found.
+ */
+struct ref_rec *
+FindHRef(list, href)
+ struct ref_rec *list;
+ char *href;
+{
+ struct ref_rec *hptr;
+
+ if (href == NULL)
+ {
+ return(NULL);
+ }
+
+ hptr = list;
+ while (hptr != NULL)
+ {
+ if (strcmp(hptr->anchorHRef, href) == 0)
+ {
+ break;
+ }
+ hptr = hptr->next;
+ }
+ return(hptr);
+}
+
+
+/*
+ * Add an element to the linked list of Internal HREFS we
+ * have visited before.
+ * return a pointer to the head of the new list.
+ */
+struct ref_rec *
+AddHRef(list, href)
+ struct ref_rec *list;
+ char *href;
+{
+ struct ref_rec *hptr;
+
+ if (href == NULL)
+ {
+ return(list);
+ }
+
+ hptr = FindHRef(list, href);
+
+ if (hptr == NULL)
+ {
+ hptr = (struct ref_rec *)malloc(sizeof(struct ref_rec));
+ if (hptr == NULL)
+ {
+ fprintf(stderr, "cannot extend internal href list\n");
+ return(list);
+ }
+ hptr->anchorHRef = (char *)malloc(strlen(href) + 1);
+ if (hptr->anchorHRef == NULL)
+ {
+ free((char *)hptr);
+ fprintf(stderr, "cannot extend internal href list\n");
+ return(list);
+ }
+ strcpy(hptr->anchorHRef, href);
+ hptr->next = list;
+ list = hptr;
+ }
+
+ return(list);
+}
+
+
+/*
+ * Free up the allocated list of visited delayed images
+ */
+void
+FreeDelayedImages(list)
+ struct delay_rec *list;
+{
+ struct delay_rec *iptr;
+ struct delay_rec *tptr;
+
+ iptr = list;
+ while (iptr != NULL)
+ {
+ tptr = iptr;
+ iptr = iptr->next;
+ if (tptr->src != NULL)
+ {
+ free((char *)tptr->src);
+ }
+ free((char *)tptr);
+ }
+}
+
+
+/*
+ * Find an element in the linked list of visited delayed images.
+ * return a pointer to the element, or NULL if not found.
+ */
+struct delay_rec *
+FindDelayedImage(list, src)
+ struct delay_rec *list;
+ char *src;
+{
+ struct delay_rec *iptr;
+
+ if (src == NULL)
+ {
+ return(NULL);
+ }
+
+ iptr = list;
+ while (iptr != NULL)
+ {
+ if (strcmp(iptr->src, src) == 0)
+ {
+ break;
+ }
+ iptr = iptr->next;
+ }
+ return(iptr);
+}
+
+
+/*
+ * Add an element to the linked list of visited delayed images.
+ * return a pointer to the head of the new list.
+ */
+struct delay_rec *
+AddDelayedImage(list, src)
+ struct delay_rec *list;
+ char *src;
+{
+ struct delay_rec *iptr;
+
+ if (src == NULL)
+ {
+ return(list);
+ }
+
+ iptr = FindDelayedImage(list, src);
+
+ if (iptr == NULL)
+ {
+ iptr = (struct delay_rec *)malloc(sizeof(struct delay_rec));
+ if (iptr == NULL)
+ {
+ fprintf(stderr, "cannot extend visited delayed images list\n");
+ return(list);
+ }
+ iptr->src = (char *)malloc(strlen(src) + 1);
+ if (iptr->src == NULL)
+ {
+ free((char *)iptr);
+ fprintf(stderr, "cannot extend visited delayed images list\n");
+ return(list);
+ }
+ strcpy(iptr->src, src);
+ iptr->next = list;
+ list = iptr;
+ }
+
+ return(list);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/HTMLparse.c b/vendor/x11iraf/obm/ObmW/HTMLparse.c
new file mode 100644
index 00000000..4b603c98
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLparse.c
@@ -0,0 +1,1373 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#ifdef TIMING
+#include <sys/time.h>
+struct timeval Tv;
+struct timezone Tz;
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#ifndef sun
+/* To get atoi. */
+#include <stdlib.h>
+#endif
+#include "HTML.h"
+#include "HTMLamp.h"
+
+
+extern void FreeObjList();
+extern struct mark_up *AddObj();
+
+
+#ifdef NOT_ASCII
+#define TOLOWER(x) (tolower(x))
+#else
+
+/*
+ * A hack to speed up caseless_equal. Thanks to Quincey Koziol for
+ * developing it for me
+ */
+unsigned char map_table[256]={
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
+ 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
+ 45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,97,98,
+ 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,
+ 116,117,118,119,120,121,122,91,92,93,94,95,96,97,98,99,100,101,102,
+ 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,
+ 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,
+ 137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,
+ 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,
+ 171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
+ 188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
+ 205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,
+ 222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,
+ 239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};
+
+#define TOLOWER(x) (map_table[x])
+#endif /* NOT_ASCII */
+
+
+/*
+ * Check if two strings are equal, ignoring case.
+ * The strings must be of the same length to be equal.
+ * return 1 if equal, 0 otherwise.
+ */
+int
+caseless_equal(str1, str2)
+ char *str1;
+ char *str2;
+{
+ if ((str1 == NULL)||(str2 == NULL))
+ {
+ return(0);
+ }
+
+ while ((*str1 != '\0')&&(*str2 != '\0'))
+ {
+ if (TOLOWER(*str1) != TOLOWER(*str2))
+ {
+ return(0);
+ }
+ str1++;
+ str2++;
+ }
+
+ if ((*str1 == '\0')&&(*str2 == '\0'))
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+/*
+ * Check if two strings are equal in the first count characters, ignoring case.
+ * The strings must both be at least of length count to be equal.
+ * return 1 if equal, 0 otherwise.
+ */
+int
+caseless_equal_prefix(str1, str2, cnt)
+ char *str1;
+ char *str2;
+ int cnt;
+{
+ int i;
+
+ if ((str1 == NULL)||(str2 == NULL))
+ {
+ return(0);
+ }
+
+ if (cnt < 1)
+ {
+ return(1);
+ }
+
+ for (i=0; i < cnt; i++)
+ {
+ if (TOLOWER(*str1) != TOLOWER(*str2))
+ {
+ return(0);
+ }
+ str1++;
+ str2++;
+ }
+
+ return(1);
+}
+
+
+/*
+ * Clean up the white space in a string.
+ * Remove all leading and trailing whitespace, and turn all
+ * internal whitespace into single spaces separating words.
+ * The cleaning is done by rearranging the chars in the passed
+ * txt buffer. The resultant string will probably be shorter,
+ * it can never get longer.
+ */
+void
+clean_white_space(txt)
+ char *txt;
+{
+ char *ptr;
+ char *start;
+
+ start = txt;
+ ptr = txt;
+
+ /*
+ * Remove leading white space
+ */
+ while (isspace((int)*ptr))
+ {
+ ptr++;
+ }
+
+ /*
+ * find a word, copying if we removed some space already
+ */
+ if (start == ptr)
+ {
+ while ((!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ start = ptr;
+ }
+ else
+ {
+ while ((!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ *start++ = *ptr++;
+ }
+ }
+
+ while (*ptr != '\0')
+ {
+ /*
+ * Remove trailing whitespace.
+ */
+ while (isspace((int)*ptr))
+ {
+ ptr++;
+ }
+ if (*ptr == '\0')
+ {
+ break;
+ }
+
+ /*
+ * If there are more words, insert a space and if space was
+ * removed move up remaining text.
+ */
+ *start++ = ' ';
+ if (start == ptr)
+ {
+ while ((!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ start = ptr;
+ }
+ else
+ {
+ while ((!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ *start++ = *ptr++;
+ }
+ }
+ }
+
+ *start = '\0';
+}
+
+
+/*
+ * parse an amperstand escape, and return the appropriate character, or
+ * '\0' on error.
+ * we should really only use caseless_equal_prefix for unterminated, and use
+ * caseless_equal otherwise, but since there are so many escapes, and I
+ * don't want to type everything twice, I always use caseless_equal_prefix
+ * Turns out the escapes are case sensitive, use strncmp.
+ * termination states:
+ * 0: terminated with a ';'
+ * 1: unterminated
+ * 2: terminated with whitespace
+ */
+char
+ExpandEscapes(esc, endp, termination)
+ char *esc;
+ char **endp;
+ int termination;
+{
+ int cnt;
+ char val;
+ int unterminated;
+
+ unterminated = (termination & 0x01);
+
+ esc++;
+ if (*esc == '#')
+ {
+ if (unterminated)
+ {
+ char *tptr;
+ char tchar;
+
+ tptr = (char *)(esc + 1);
+ while (isdigit((int)*tptr))
+ {
+ tptr++;
+ }
+ tchar = *tptr;
+ *tptr = '\0';
+ val = (char)atoi((esc + 1));
+ *tptr = tchar;
+ *endp = tptr;
+ }
+ else
+ {
+ val = (char)atoi((esc + 1));
+ *endp = (char *)(esc + strlen(esc));
+ }
+ }
+ else
+ {
+ cnt = 0;
+ while (AmpEscapes[cnt].tag != NULL)
+ {
+ if (strncmp(esc, AmpEscapes[cnt].tag,
+ strlen(AmpEscapes[cnt].tag)) == 0)
+ {
+ val = AmpEscapes[cnt].value;
+ *endp = (char *)(esc +
+ strlen(AmpEscapes[cnt].tag));
+ break;
+ }
+ cnt++;
+ }
+ if (AmpEscapes[cnt].tag == NULL)
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "Error bad & string\n");
+#endif
+ val = '\0';
+ *endp = (char *)NULL;
+ }
+ }
+
+ return(val);
+}
+
+
+/*
+ * Clean the special HTML character escapes out of the text and replace
+ * them with the appropriate characters "&lt;" = "<", "&gt;" = ">",
+ * "&amp;" = "&"
+ * GAG: apperantly &lt etc. can be left unterminated, what a nightmare.
+ * Ok, better, they have to be terminated with white-space or ';'.
+ * the '&' character must be immediately followed by a letter to be
+ * a valid escape sequence. Other &'s are left alone.
+ * The cleaning is done by rearranging chars in the passed txt buffer.
+ * if any escapes are replaced, the string becomes shorter.
+ */
+void
+clean_text(txt)
+ char *txt;
+{
+ int unterminated;
+ int space_terminated;
+ char *ptr;
+ char *ptr2;
+ char *start;
+ char *text;
+ char *tend;
+ char tchar;
+ char val;
+
+ if (txt == NULL)
+ {
+ return;
+ }
+
+ /*
+ * Quick scan to find escape sequences.
+ * Escape is '&' followed by a letter (or a hash mark).
+ * return if there are none.
+ */
+ ptr = txt;
+ while (*ptr != '\0')
+ {
+ if ((*ptr == '&')&&
+ ((isalpha((int)*(ptr + 1)))||(*(ptr + 1) == '#')))
+ {
+ break;
+ }
+ ptr++;
+ }
+ if (*ptr == '\0')
+ {
+ return;
+ }
+
+ /*
+ * Loop, replaceing escape sequences, and moving up remaining
+ * text.
+ */
+ ptr2 = ptr;
+ while (*ptr != '\0')
+ {
+
+ unterminated = 0;
+ space_terminated = 0;
+ /*
+ * Extract the escape sequence from start to ptr
+ */
+ start = ptr;
+ while ((*ptr != ';')&&(!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ if (*ptr == '\0')
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "warning: unterminated & (%s)\n",
+ start);
+#endif
+ unterminated = 1;
+ }
+ else if (isspace((int)*ptr))
+ {
+ space_terminated = 1;
+ }
+
+ /*
+ * Copy the escape sequence into a separate buffer.
+ * Then clean spaces so the "& lt ;" = "&lt;" etc.
+ * The cleaning should be unnecessary.
+ */
+ tchar = *ptr;
+ *ptr = '\0';
+ text = (char *)malloc(strlen(start) + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "Cannot malloc space for & text\n");
+ *ptr = tchar;
+ return;
+ }
+ strcpy(text, start);
+ *ptr = tchar;
+ clean_white_space(text);
+
+ /*
+ * Replace escape sequence with appropriate character
+ */
+ val = ExpandEscapes(text, &tend,
+ ((space_terminated << 1) + unterminated));
+ if (val != '\0')
+ {
+ if (unterminated)
+ {
+ tchar = *tend;
+ *tend = '\0';
+ ptr = (char *)(start + strlen(text) - 1);
+ *tend = tchar;
+ }
+ else if (space_terminated)
+ {
+ ptr--;
+ }
+ *ptr2 = val;
+ unterminated = 0;
+ space_terminated = 0;
+ }
+ /*
+ * invalid escape sequence. skip it.
+ */
+ else
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "Error bad & string\n");
+#endif
+ ptr = start;
+ *ptr2 = *ptr;
+ }
+ free(text);
+
+ /*
+ * Copy forward remaining text until you find the next
+ * escape sequence
+ */
+ ptr2++;
+ ptr++;
+ while (*ptr != '\0')
+ {
+ if ((*ptr == '&')&&
+ ((isalpha((int)*(ptr + 1)))||(*(ptr + 1) == '#')))
+ {
+ break;
+ }
+ *ptr2++ = *ptr++;
+ }
+ }
+ *ptr2 = '\0';
+}
+
+
+/*
+ * Get a block of text from a HTML document.
+ * All text from start to the end, or the first mark
+ * (a mark is '<' or '</' followed by any letter or a '!')
+ * is returned in a malloced buffer. Also, endp returns
+ * a pointer to the next '<' or '\0'
+ * The returned text has already expanded '&' escapes.
+ */
+char *
+get_text(start, endp)
+ char *start;
+ char **endp;
+{
+ char *ptr;
+ char *text;
+ char tchar;
+
+ if (start == NULL)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Copy text up to beginning of a mark, or the end
+ */
+ ptr = start;
+ while (*ptr != '\0')
+ {
+ if (*ptr == '<')
+ {
+ if (isalpha((int)(*(ptr + 1))))
+ {
+ break;
+ }
+ else if (*(ptr + 1) == '/')
+ {
+ if (isalpha((int)(*(ptr + 2))))
+ {
+ break;
+ }
+ }
+ else if (*(ptr + 1) == '!') /* a comment */
+ {
+ break;
+ }
+ }
+ ptr++;
+ }
+ *endp = ptr;
+
+ if (ptr == start)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Copy the text into its own buffer, and clean it
+ * of escape sequences.
+ */
+ tchar = *ptr;
+ *ptr = '\0';
+ text = (char *)malloc(strlen(start) + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "Cannot malloc space for text\n");
+ *ptr = tchar;
+ return(NULL);
+ }
+ strcpy(text, start);
+ *ptr = tchar;
+ clean_text(text);
+
+ return(text);
+}
+
+
+/*
+ * Get the mark text between '<' and '>'. From the text, determine
+ * its type, and fill in a mark_up structure to return. Also returns
+ * endp pointing to the ttrailing '>' in the original string.
+ */
+struct mark_up *
+get_mark(start, endp)
+ char *start;
+ char **endp;
+{
+ char *ptr;
+ char *text;
+ char tchar;
+ struct mark_up *mark;
+
+ if (start == NULL)
+ {
+ return(NULL);
+ }
+
+ if (*start != '<')
+ {
+ return(NULL);
+ }
+
+ start++;
+
+ mark = (struct mark_up *)malloc(sizeof(struct mark_up));
+ if (mark == NULL)
+ {
+ fprintf(stderr, "Cannot malloc space for mark_up struct\n");
+ return(NULL);
+ }
+
+ /*
+ * Grab the mark text
+ */
+ ptr = start;
+ while ((*ptr != '>')&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ *endp = ptr;
+
+ if (*ptr != '>')
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "error: bad mark format\n");
+#endif
+ return(NULL);
+ }
+
+ /*
+ * Copy the mark text to its own buffer, and
+ * clean it of escapes, and odd white space.
+ */
+ tchar = *ptr;
+ *ptr = '\0';
+ text = (char *)malloc(strlen(start) + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "Cannot malloc space for mark\n");
+ *ptr = tchar;
+ return(NULL);
+ }
+ strcpy(text, start);
+ *ptr = tchar;
+ clean_text(text);
+/*
+ * No longer needed because the parsing code is now smarter
+ *
+ clean_white_space(text);
+ *
+ */
+
+ /*
+ * Set whether this is the start or end of a mark
+ * block, as well as determining its type.
+ */
+ if (*text == '/')
+ {
+ mark->is_end = 1;
+ mark->type = ParseMarkType((char *)(text + 1));
+ mark->start = NULL;
+ mark->text = NULL;
+ mark->end = text;
+ }
+ else
+ {
+ mark->is_end = 0;
+ mark->type = ParseMarkType(text);
+ mark->start = text;
+ mark->text = NULL;
+ mark->end = NULL;
+ }
+ mark->text = NULL;
+ mark->next = NULL;
+
+ return(mark);
+}
+
+
+/*
+ * Special version of get_text. It reads all text up to the
+ * end of the plain text mark, or the end of the file.
+ */
+char *
+get_plain_text(start, endp)
+ char *start;
+ char **endp;
+{
+ char *ptr;
+ char *text;
+ char tchar;
+
+ if (start == NULL)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Read until stopped by end plain text mark.
+ */
+ ptr = start;
+ while (*ptr != '\0')
+ {
+ /*
+ * Beginning of a mark is '<' followed by any letter,
+ * or followed by '!' for a comment,
+ * or '</' followed by any letter.
+ */
+ if ((*ptr == '<')&&
+ ((isalpha((int)(*(ptr + 1))))||
+ (*(ptr + 1) == '!')||
+ ((*(ptr + 1) == '/')&&(isalpha((int)(*(ptr + 2)))))))
+ {
+ struct mark_up *mp;
+ char *ep;
+
+ /*
+ * We think we found a mark. If it is the
+ * end of plain text, break out
+ */
+ mp = get_mark(ptr, &ep);
+ if (mp != NULL)
+ {
+ if (((mp->type == M_PLAIN_TEXT)||
+ (mp->type == M_LISTING_TEXT))&&(mp->is_end))
+ {
+ if (mp->end != NULL)
+ {
+ free((char *)mp->end);
+ }
+ free((char *)mp);
+ break;
+ }
+ if (mp->start != NULL)
+ {
+ free((char *)mp->start);
+ }
+ if (mp->end != NULL)
+ {
+ free((char *)mp->end);
+ }
+ free((char *)mp);
+ }
+ }
+ ptr++;
+ }
+ *endp = ptr;
+
+ if (ptr == start)
+ {
+ return(NULL);
+ }
+
+ /*
+ * Copy text to its own malloced buffer, and clean it of
+ * HTML escapes.
+ */
+ tchar = *ptr;
+ *ptr = '\0';
+ text = (char *)malloc(strlen(start) + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "Cannot malloc space for text\n");
+ *ptr = tchar;
+ return(NULL);
+ }
+ strcpy(text, start);
+ *ptr = tchar;
+ clean_text(text);
+
+ return(text);
+}
+
+
+/*
+ * Main parser of HTML text. Takes raw text, and produces a linked
+ * list of mark objects. Mark objects are either text strings, or
+ * starting and ending mark delimiters.
+ * The old list is passed in so it can be freed, and in the future we
+ * may want to add code to append to the old list.
+ */
+struct mark_up *
+HTMLParse(old_list, str)
+ struct mark_up *old_list;
+ char *str;
+{
+ int preformat;
+ char *start, *end;
+ char *text, *tptr;
+ struct mark_up *mark;
+ struct mark_up *list;
+ struct mark_up *current;
+#ifdef TIMING
+gettimeofday(&Tv, &Tz);
+fprintf(stderr, "HTMLParse enter (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
+#endif
+
+ preformat = 0;
+
+ /*
+ * Free up the previous Object List if one exists
+ */
+ FreeObjList(old_list);
+
+ if (str == NULL)
+ {
+ return(NULL);
+ }
+
+ list = NULL;
+ current = NULL;
+
+ start = str;
+ end = str;
+
+ mark = NULL;
+ while (*start != '\0')
+ {
+ /*
+ * Get some text (if any). If our last mark was
+ * a begin plain text we call different function
+ * If last mark was <PLAINTEXT> we lump all the rest of
+ * the text in.
+ */
+ if ((mark != NULL)&&(mark->type == M_PLAIN_FILE)&&
+ (!mark->is_end))
+ {
+ text = start;
+ end = text;
+ while (*end != '\0')
+ {
+ end++;
+ }
+ /*
+ * Copy text to its own malloced buffer, and clean it of
+ * HTML escapes.
+ */
+ tptr = (char *)malloc(strlen(text) + 1);
+ if (tptr == NULL)
+ {
+ fprintf(stderr,
+ "Cannot malloc space for text\n");
+ return(list);
+ }
+ strcpy(tptr, text);
+ text = tptr;
+ }
+ else if ((mark != NULL)&&
+ ((mark->type == M_PLAIN_TEXT)||
+ (mark->type == M_LISTING_TEXT))&&
+ (!mark->is_end))
+ {
+ text = get_plain_text(start, &end);
+ }
+ else
+ {
+ text = get_text(start, &end);
+ }
+
+ /*
+ * If text is OK, put it into a mark structure, and add
+ * it to the linked list.
+ */
+ if (text == NULL)
+ {
+ if (start != end)
+ {
+ fprintf(stderr, "error parsing text, bailing out\n");
+ return(list);
+ }
+ }
+ else
+ {
+ mark = (struct mark_up *)malloc(sizeof(struct mark_up));
+ if (mark == NULL)
+ {
+ fprintf(stderr, "Cannot malloc for mark_up struct\n");
+ return(list);
+ }
+ mark->type = M_NONE;
+ mark->is_end = 0;
+ mark->start = NULL;
+ mark->text = text;
+ mark->end = NULL;
+ mark->next = NULL;
+ current = AddObj(&list, current, mark, preformat);
+ }
+ start = end;
+
+ if (*start == '\0')
+ {
+ break;
+ }
+
+ /*
+ * Get the next mark if any, and if it is
+ * valid, add it to the linked list.
+ */
+ mark = get_mark(start, &end);
+ if (mark == NULL)
+ {
+ if (start != end)
+ {
+ fprintf(stderr, "error parsing mark, bailing out\n");
+ return(list);
+ }
+ }
+ else
+ {
+ mark->next = NULL;
+ current = AddObj(&list, current, mark, preformat);
+ }
+
+ start = (char *)(end + 1);
+
+ if ((mark != NULL)&&(mark->type == M_PLAIN_FILE)&&
+ (!mark->is_end))
+ {
+ /*
+ * A linefeed immediately after the <PLAINTEXT>
+ * mark is to be ignored.
+ */
+ if (*start == '\n')
+ {
+ start++;
+ }
+ }
+ else if ((mark != NULL)&&((mark->type == M_PLAIN_TEXT)||
+ (mark->type == M_LISTING_TEXT))&&
+ (!mark->is_end))
+ {
+ /*
+ * A linefeed immediately after the <XMP>
+ * or <LISTING> mark is to be ignored.
+ */
+ if (*start == '\n')
+ {
+ start++;
+ }
+ }
+ /*
+ * If we are parsing pre-formatted text we need to set a
+ * flag so we don't throw out needed linefeeds.
+ */
+ else if ((mark != NULL)&&(mark->type == M_PREFORMAT))
+ {
+ if (mark->is_end)
+ {
+ preformat = 0;
+ }
+ else
+ {
+ preformat = 1;
+ /*
+ * A linefeed immediately after the <PRE>
+ * mark is to be ignored.
+ */
+ if (*start == '\n')
+ {
+ start++;
+ }
+ }
+ }
+ }
+#ifdef TIMING
+gettimeofday(&Tv, &Tz);
+fprintf(stderr, "HTMLParse exit (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
+#endif
+ return(list);
+}
+
+
+/*
+ * Determine mark type from the identifying string passed
+ */
+int
+ParseMarkType(str)
+ char *str;
+{
+ int type;
+ char *tptr;
+ char tchar;
+
+ if (str == NULL)
+ {
+ return(M_NONE);
+ }
+
+ type = M_UNKNOWN;
+ tptr = str;
+ while (*tptr != '\0')
+ {
+ if (isspace((int)*tptr))
+ {
+ break;
+ }
+ tptr++;
+ }
+ tchar = *tptr;
+ *tptr = '\0';
+
+ if (caseless_equal(str, MT_ANCHOR))
+ {
+ type = M_ANCHOR;
+ }
+ else if (caseless_equal(str, MT_TITLE))
+ {
+ type = M_TITLE;
+ }
+ else if (caseless_equal(str, MT_FIXED))
+ {
+ type = M_FIXED;
+ }
+ else if (caseless_equal(str, MT_BOLD))
+ {
+ type = M_BOLD;
+ }
+ else if (caseless_equal(str, MT_ITALIC))
+ {
+ type = M_ITALIC;
+ }
+ else if (caseless_equal(str, MT_EMPHASIZED))
+ {
+ type = M_EMPHASIZED;
+ }
+ else if (caseless_equal(str, MT_STRONG))
+ {
+ type = M_STRONG;
+ }
+ else if (caseless_equal(str, MT_CODE))
+ {
+ type = M_CODE;
+ }
+ else if (caseless_equal(str, MT_SAMPLE))
+ {
+ type = M_SAMPLE;
+ }
+ else if (caseless_equal(str, MT_KEYBOARD))
+ {
+ type = M_KEYBOARD;
+ }
+ else if (caseless_equal(str, MT_VARIABLE))
+ {
+ type = M_VARIABLE;
+ }
+ else if (caseless_equal(str, MT_CITATION))
+ {
+ type = M_CITATION;
+ }
+ else if (caseless_equal(str, MT_STRIKEOUT))
+ {
+ type = M_STRIKEOUT;
+ }
+ else if (caseless_equal(str, MT_HEADER_1))
+ {
+ type = M_HEADER_1;
+ }
+ else if (caseless_equal(str, MT_HEADER_2))
+ {
+ type = M_HEADER_2;
+ }
+ else if (caseless_equal(str, MT_HEADER_3))
+ {
+ type = M_HEADER_3;
+ }
+ else if (caseless_equal(str, MT_HEADER_4))
+ {
+ type = M_HEADER_4;
+ }
+ else if (caseless_equal(str, MT_HEADER_5))
+ {
+ type = M_HEADER_5;
+ }
+ else if (caseless_equal(str, MT_HEADER_6))
+ {
+ type = M_HEADER_6;
+ }
+ else if (caseless_equal(str, MT_ADDRESS))
+ {
+ type = M_ADDRESS;
+ }
+ else if (caseless_equal(str, MT_PLAIN_TEXT))
+ {
+ type = M_PLAIN_TEXT;
+ }
+ else if (caseless_equal(str, MT_LISTING_TEXT))
+ {
+ type = M_LISTING_TEXT;
+ }
+ else if (caseless_equal(str, MT_PLAIN_FILE))
+ {
+ type = M_PLAIN_FILE;
+ }
+ else if (caseless_equal(str, MT_PARAGRAPH))
+ {
+ type = M_PARAGRAPH;
+ }
+ else if (caseless_equal(str, MT_UNUM_LIST))
+ {
+ type = M_UNUM_LIST;
+ }
+ else if (caseless_equal(str, MT_NUM_LIST))
+ {
+ type = M_NUM_LIST;
+ }
+ else if (caseless_equal(str, MT_MENU))
+ {
+ type = M_MENU;
+ }
+ else if (caseless_equal(str, MT_DIRECTORY))
+ {
+ type = M_DIRECTORY;
+ }
+ else if (caseless_equal(str, MT_LIST_ITEM))
+ {
+ type = M_LIST_ITEM;
+ }
+ else if (caseless_equal(str, MT_DESC_LIST))
+ {
+ type = M_DESC_LIST;
+ }
+ else if (caseless_equal(str, MT_DESC_TITLE))
+ {
+ type = M_DESC_TITLE;
+ }
+ else if (caseless_equal(str, MT_DESC_TEXT))
+ {
+ type = M_DESC_TEXT;
+ }
+ else if (caseless_equal(str, MT_PREFORMAT))
+ {
+ type = M_PREFORMAT;
+ }
+ else if (caseless_equal(str, MT_BLOCKQUOTE))
+ {
+ type = M_BLOCKQUOTE;
+ }
+ else if (caseless_equal(str, MT_INDEX))
+ {
+ type = M_INDEX;
+ }
+ else if (caseless_equal(str, MT_HRULE))
+ {
+ type = M_HRULE;
+ }
+ else if (caseless_equal(str, MT_BASE))
+ {
+ type = M_BASE;
+ }
+ else if (caseless_equal(str, MT_LINEBREAK))
+ {
+ type = M_LINEBREAK;
+ }
+ else if (caseless_equal(str, MT_IMAGE))
+ {
+ type = M_IMAGE;
+ }
+ else if (caseless_equal(str, MT_SELECT))
+ {
+ type = M_SELECT;
+ }
+ else if (caseless_equal(str, MT_OPTION))
+ {
+ type = M_OPTION;
+ }
+ else if (caseless_equal(str, MT_INPUT))
+ {
+ type = M_INPUT;
+ }
+ else if (caseless_equal(str, MT_TEXTAREA))
+ {
+ type = M_TEXTAREA;
+ }
+ else if (caseless_equal(str, MT_FORM))
+ {
+ type = M_FORM;
+ }
+ else
+ {
+#ifdef VERBOSE
+ fprintf(stderr, "warning: unknown mark (%s)\n", str);
+#endif
+ type = M_UNKNOWN;
+ }
+
+ *tptr = tchar;
+ return(type);
+}
+
+
+/*
+ * Parse a single anchor tag. ptrp is a pointer to a pointer to the
+ * string to be parsed. On return, the ptr should be changed to
+ * point to after the text we have parsed.
+ * On return start and end should point to the beginning, and just
+ * after the end of the tag's name in the original anchor string.
+ * Finally the function returns the tag value in a malloced buffer.
+ */
+char *
+AnchorTag(ptrp, startp, endp)
+ char **ptrp;
+ char **startp;
+ char **endp;
+{
+ char *tag_val;
+ char *ptr;
+ char *start;
+ char tchar;
+ int quoted;
+ int has_value;
+
+ quoted = 0;
+
+ /*
+ * remove leading spaces, and set start
+ */
+ ptr = *ptrp;
+ while (isspace((int)*ptr))
+ {
+ ptr++;
+ }
+ *startp = ptr;
+
+ /*
+ * Find and set the end of the tag
+ */
+ while ((!isspace((int)*ptr))&&(*ptr != '=')&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ *endp = ptr;
+
+ if (*ptr == '\0')
+ {
+ *ptrp = ptr;
+ return(NULL);
+ }
+
+ /*
+ * Move to the start of the tag value, if there is one.
+ * set the has_value flag.
+ */
+ has_value = 0;
+ while ((isspace((int)*ptr))||(*ptr == '='))
+ {
+ if (*ptr == '=')
+ {
+ has_value = 1;
+ }
+ ptr++;
+ }
+
+ /*
+ * For a tag with no value, this is a boolean flag.
+ * Return the string "1" so we know the tag is there.
+ */
+ if (!has_value)
+ {
+ *ptrp = *endp;
+ /*
+ * set a tag value of 1.
+ */
+ tag_val = (char *)malloc(strlen("1") + 1);
+ if (tag_val == NULL)
+ {
+ fprintf(stderr, "can't malloc space for tag value\n");
+ return(NULL);
+ }
+ strcpy(tag_val, "1");
+
+ return(tag_val);
+ }
+
+ if (*ptr == '\"')
+ {
+ quoted = 1;
+ ptr++;
+ }
+
+ start = ptr;
+ /*
+ * Get tag value. Either a quoted string or a single word
+ */
+ if (quoted)
+ {
+ while ((*ptr != '\"')&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ }
+ else
+ {
+ while ((!isspace((int)*ptr))&&(*ptr != '\0'))
+ {
+ ptr++;
+ }
+ }
+ if ((quoted)&&(*ptr == '\0'))
+ {
+ *ptrp = ptr;
+ return(NULL);
+ }
+
+ /*
+ * Copy the tag value out into a malloced string
+ */
+ tchar = *ptr;
+ *ptr = '\0';
+ tag_val = (char *)malloc(strlen(start) + 1);
+ if (tag_val == NULL)
+ {
+ fprintf(stderr, "can't malloc space for tag value\n");
+ *ptr = tchar;
+ *ptrp = ptr;
+ return(NULL);
+ }
+ strcpy(tag_val, start);
+ *ptr = tchar;
+ if (quoted)
+ {
+ ptr++;
+ }
+ *ptrp = ptr;
+
+ return(tag_val);
+}
+
+
+/*
+ * Parse mark text for the value associated with the
+ * passed mark tag.
+ * If the passed tag is not found, return NULL.
+ * If the passed tag is found but has no value, return "".
+ */
+char *
+ParseMarkTag(text, mtext, mtag)
+ char *text;
+ char *mtext;
+ char *mtag;
+{
+ char *ptr;
+ char *start;
+ char *end;
+ char *tag_val;
+ char tchar;
+
+ if ((text == NULL)||(mtext == NULL)||(mtag == NULL))
+ {
+ return(NULL);
+ }
+
+ ptr = (char *)(text + strlen(mtext));
+
+ while (*ptr != '\0')
+ {
+ tag_val = AnchorTag(&ptr, &start, &end);
+
+ tchar = *end;
+ *end = '\0';
+ if (caseless_equal(start, mtag))
+ {
+ *end = tchar;
+ if (tag_val == NULL)
+ {
+ tag_val = (char *)malloc(1);
+ *tag_val = '\0';
+ return(tag_val);
+ }
+ else
+ {
+ return(tag_val);
+ }
+ }
+ *end = tchar;
+ if (tag_val != NULL)
+ {
+ free(tag_val);
+ }
+ }
+ return(NULL);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/HTMLwidgets.c b/vendor/x11iraf/obm/ObmW/HTMLwidgets.c
new file mode 100644
index 00000000..a4195c45
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTMLwidgets.c
@@ -0,0 +1,4014 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef MOTIF
+#include <Xm/Xm.h>
+#include <Xm/Frame.h>
+#include <Xm/DrawingA.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/ToggleB.h>
+#include <Xm/PushB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/List.h>
+#else
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xaw/Toggle.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/List.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/SmeBSB.h>
+#endif /* MOTIF */
+#include "HTMLP.h"
+
+
+#ifdef MOTIF
+#define STRING XmString
+#else
+#define STRING String
+#endif /* MOTIF */
+
+#define X_NAME "x"
+#define Y_NAME "y"
+
+#define W_TEXTFIELD 0
+#define W_CHECKBOX 1
+#define W_RADIOBOX 2
+#define W_PUSHBUTTON 3
+#define W_PASSWORD 4
+#define W_OPTIONMENU 5
+#define W_TEXTAREA 6
+#define W_LIST 7
+#define W_JOT 8
+#define W_HIDDEN 9
+
+
+extern void NewJot();
+extern void ClearJot();
+extern void EVJotExpose();
+extern void EVJotPress();
+extern void EVJotMove();
+extern void EVJotRelease();
+extern char *EJB_JOTfromJot();
+extern char *ParseMarkTag();
+
+
+#ifdef MOTIF
+static Boolean ModifyIgnore = False;
+#endif /* MOTIF */
+
+
+char **ParseCommaList();
+void FreeCommaList();
+char *MapOptionReturn();
+
+
+#ifndef MOTIF
+#define FONTHEIGHT(font) (font->max_bounds.ascent + font->max_bounds.descent)
+
+void
+setTextSize(w, columns, lines)
+ Widget w;
+ int columns;
+ int lines;
+{
+ XFontStruct *font;
+ Position lm, rm, tm, bm;
+ int width, height;
+
+ XtVaGetValues(w, XtNfont, &font,
+ XtNleftMargin, &lm,
+ XtNrightMargin, &rm,
+ XtNtopMargin, &tm,
+ XtNbottomMargin, &bm,
+ NULL);
+ width = rm + lm + columns * XTextWidth(font, "0", 1);
+ height = tm + bm + lines * FONTHEIGHT(font);
+ XtVaSetValues(w,
+ XtNwidth, width,
+ XtNheight, height,
+ NULL);
+}
+
+void
+CBListDestroy(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ char **string_list, **p;
+ int item_count;
+
+ XtVaGetValues(w,
+ XtNlist, string_list,
+ XtNnumberStrings, item_count,
+ NULL);
+
+ p = string_list;
+ while(item_count > 0)
+ {
+ free(*p++);
+ item_count--;
+ }
+ free(string_list);
+}
+
+
+void
+CBTextDestroy(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ char *txt = (char *)client_data;
+ free(txt);
+}
+
+
+void
+CBoption(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ Widget menuButton = (Widget)client_data;
+ char *label;
+
+ XtVaGetValues(menuButton, XtNlabel, &label, NULL);
+ XtVaGetValues(w, XtNlabel, &label, NULL);
+ XtVaSetValues(menuButton, XtNlabel, label, NULL);
+}
+#endif /* not MOTIF */
+
+
+void
+AddNewForm(hw, fptr)
+ HTMLWidget hw;
+ FormInfo *fptr;
+{
+ FormInfo *ptr;
+
+ ptr = hw->html.form_list;
+ if (ptr == NULL)
+ {
+ hw->html.form_list = fptr;
+ fptr->next = NULL;
+ }
+ else
+ {
+ while (ptr->next != NULL)
+ {
+ ptr = ptr->next;
+ }
+ ptr->next = fptr;
+ fptr->next = NULL;
+ }
+}
+
+
+int
+CollectSubmitInfo(fptr, name_list, value_list)
+ FormInfo *fptr;
+ char ***name_list;
+ char ***value_list;
+{
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WbFormCallbackData cbdata;
+ WidgetInfo *wptr;
+ int cnt;
+#ifndef MOTIF
+ Boolean state;
+#endif
+
+ if (fptr->end == -1) /* unterminated FORM tag */
+ {
+ wptr = hw->html.widget_list;
+ cnt = 0;
+ while (wptr != NULL)
+ {
+ cnt++;
+ wptr = wptr->next;
+ }
+ cbdata.attribute_count = cnt;
+ }
+ else
+ {
+ cbdata.attribute_count = fptr->end - fptr->start;
+ }
+ cbdata.attribute_names = (char **)malloc(cbdata.attribute_count *
+ sizeof(char *));
+ cbdata.attribute_values = (char **)malloc(cbdata.attribute_count *
+ sizeof(char *));
+
+ if (fptr->start == 0)
+ {
+ wptr = hw->html.widget_list;
+ }
+ else
+ {
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->id == fptr->start)
+ {
+ wptr = wptr->next;
+ break;
+ }
+ wptr = wptr->next;
+ }
+ }
+
+ cnt = 0;
+
+ while ((wptr != NULL)&&(cnt < cbdata.attribute_count))
+ {
+ if ((wptr->name)&&(wptr->type != W_PUSHBUTTON))
+ {
+ Widget child;
+ STRING *str_list;
+ int list_cnt;
+ char *val;
+#ifdef MOTIF
+ STRING label;
+ Cardinal argcnt;
+ Arg arg[5];
+#else
+ XawListReturnStruct *currentSelection;
+#endif /* MOTIF */
+
+ cbdata.attribute_names[cnt] = wptr->name;
+ switch(wptr->type)
+ {
+ case W_TEXTFIELD:
+#ifdef MOTIF
+ cbdata.attribute_values[cnt] =
+ XmTextFieldGetString(wptr->w);
+#else
+ XtVaGetValues(wptr->w, XtNstring,
+ &(cbdata.attribute_values[cnt]),
+ NULL);
+#endif /* MOTIF */
+ if ((cbdata.attribute_values[cnt] != NULL)&&
+ (cbdata.attribute_values[cnt][0] == '\0'))
+ {
+ cbdata.attribute_values[cnt] = NULL;
+ }
+ break;
+ case W_TEXTAREA:
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNworkWindow, &child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+ cbdata.attribute_values[cnt] =
+ XmTextGetString(child);
+#else
+ XtVaGetValues(wptr->w, XtNstring,
+ &(cbdata.attribute_values[cnt]),
+ NULL);
+#endif /* MOTIF */
+ if ((cbdata.attribute_values[cnt] != NULL)&&
+ (cbdata.attribute_values[cnt][0] == '\0'))
+ {
+ cbdata.attribute_values[cnt] = NULL;
+ }
+ break;
+ case W_PASSWORD:
+ cbdata.attribute_values[cnt] = wptr->password;
+ if ((cbdata.attribute_values[cnt] != NULL)&&
+ (cbdata.attribute_values[cnt][0] == '\0'))
+ {
+ cbdata.attribute_values[cnt] = NULL;
+ }
+ break;
+ case W_LIST:
+ /*
+ * First get the Widget ID of the proper
+ * list element
+ */
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNworkWindow, &child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+#else
+ {
+ WidgetList wl;
+ XtVaGetValues(wptr->w, XtNchildren,
+ &wl, NULL);
+ child = *++wl;
+ }
+#endif /* MOTIF */
+
+ /*
+ * Now get the list of selected items.
+ */
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNselectedItemCount,
+ &list_cnt);
+ argcnt++;
+ XtSetArg(arg[argcnt], XmNselectedItems,
+ &str_list);
+ argcnt++;
+ XtGetValues(child, arg, argcnt);
+#else
+ currentSelection = XawListShowCurrent(child);
+ list_cnt =
+ currentSelection->list_index == XAW_LIST_NONE?
+ 0 : 1;
+ str_list = &(currentSelection->string);
+#endif /* MOTIF */
+
+ if (list_cnt == 0)
+ {
+ cnt--;
+ cbdata.attribute_count--;
+ }
+ else /* list_cnt >= 1 */
+ {
+ int j, new_cnt;
+ char **names;
+ char **values;
+
+ if (list_cnt > 1)
+ {
+ new_cnt = cbdata.attribute_count +
+ list_cnt - 1;
+ names = (char **)malloc(new_cnt *
+ sizeof(char *));
+ values = (char **)malloc(new_cnt *
+ sizeof(char *));
+ for (j=0; j<cnt; j++)
+ {
+ names[j] =
+ cbdata.attribute_names[j];
+ values[j] =
+ cbdata.attribute_values[j];
+ }
+ free((char *)
+ cbdata.attribute_names);
+ free((char *)
+ cbdata.attribute_values);
+ cbdata.attribute_names = names;
+ cbdata.attribute_values = values;
+ cbdata.attribute_count = new_cnt;
+ }
+
+ for (j=0; j<list_cnt; j++)
+ {
+ cbdata.attribute_names[cnt + j]
+ = wptr->name;
+#ifdef MOTIF
+ XmStringGetLtoR(str_list[j],
+ XmSTRING_DEFAULT_CHARSET,
+ &val);
+#else
+ val = str_list[j];
+#endif /* MOTIF */
+ if ((val != NULL)&&
+ (val[0] == '\0'))
+ {
+ val = NULL;
+ }
+ else if (val != NULL)
+ {
+ val = MapOptionReturn(
+ val,
+ wptr->mapping);
+ }
+ cbdata.attribute_values[cnt + j]
+ = val;
+ }
+ cnt = cnt + list_cnt - 1;
+ }
+ break;
+ /*
+ * For an option menu, first get the label gadget
+ * which holds the current value.
+ * Now get the text from that label as a character
+ * string.
+ */
+ case W_OPTIONMENU:
+#ifdef MOTIF
+ child = XmOptionButtonGadget(wptr->w);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNlabelString, &label);
+ argcnt++;
+ XtGetValues(child, arg, argcnt);
+ val = NULL;
+ XmStringGetLtoR(label, XmSTRING_DEFAULT_CHARSET,
+ &val);
+#else
+ XtVaGetValues(wptr->w, XtNlabel, &val, NULL);
+#endif /* MOTIF */
+ if ((val != NULL)&&(val[0] == '\0'))
+ {
+ val = NULL;
+ }
+ else if (val != NULL)
+ {
+ val = MapOptionReturn(val,
+ wptr->mapping);
+ }
+ cbdata.attribute_values[cnt] = val;
+ if ((cbdata.attribute_values[cnt] != NULL)&&
+ (cbdata.attribute_values[cnt][0] == '\0'))
+ {
+ cbdata.attribute_values[cnt] = NULL;
+ }
+ break;
+ case W_CHECKBOX:
+ case W_RADIOBOX:
+#ifdef MOTIF
+ if (XmToggleButtonGetState(wptr->w) == True)
+#else
+ XtVaGetValues(wptr->w, XtNstate, &state, NULL);
+ if (state)
+#endif /* MOTIF */
+ {
+ cbdata.attribute_values[cnt] = wptr->value;
+ }
+ else
+ {
+ cnt--;
+ cbdata.attribute_count--;
+ }
+ break;
+ case W_HIDDEN:
+ cbdata.attribute_values[cnt] = wptr->value;
+ break;
+#ifdef MOTIF
+ case W_JOT:
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNuserData,
+ (XtPointer *)&child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+ cbdata.attribute_values[cnt] =
+ EJB_JOTfromJot(child);
+ break;
+#endif /* MOTIF */
+ default:
+ cbdata.attribute_values[cnt] = NULL;
+ break;
+ }
+ cnt++;
+ }
+ else
+ {
+ cbdata.attribute_count--;
+ }
+ wptr = wptr->next;
+ }
+ cbdata.attribute_count = cnt;
+
+ *name_list = cbdata.attribute_names;
+ *value_list = cbdata.attribute_values;
+ return(cbdata.attribute_count);
+}
+
+
+void
+ImageSubmitForm(fptr, event, name, x, y)
+ FormInfo *fptr;
+ XEvent *event;
+ char *name;
+ int x, y;
+{
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WbFormCallbackData cbdata;
+ int i, cnt;
+ char **name_list;
+ char **value_list;
+ char valstr[100];
+
+ cbdata.event = event;
+ cbdata.href = fptr->action;
+ cbdata.method = fptr->method;
+ cbdata.enctype = fptr->enctype;
+ cbdata.enc_entity = fptr->enc_entity;
+
+ name_list = NULL;
+ value_list = NULL;
+ cnt = CollectSubmitInfo(fptr, &name_list, &value_list);
+
+ cbdata.attribute_count = cnt + 2;
+ cbdata.attribute_names = (char **)malloc(cbdata.attribute_count *
+ sizeof(char *));
+ cbdata.attribute_values = (char **)malloc(cbdata.attribute_count *
+ sizeof(char *));
+ for (i=0; i<cnt; i++)
+ {
+ cbdata.attribute_names[i] = name_list[i];
+ cbdata.attribute_values[i] = value_list[i];
+ }
+ if (name_list != NULL)
+ {
+ free((char *)name_list);
+ }
+ if (value_list != NULL)
+ {
+ free((char *)value_list);
+ }
+
+ if ((name != NULL)&&(name[0] != '\0'))
+ {
+ cbdata.attribute_names[cnt] = (char *)malloc(strlen(name) +
+ strlen(X_NAME) + 2);
+ strcpy(cbdata.attribute_names[cnt], name);
+ strcat(cbdata.attribute_names[cnt], ".");
+ strcat(cbdata.attribute_names[cnt], X_NAME);
+ }
+ else
+ {
+ cbdata.attribute_names[cnt] = (char *)malloc(strlen(X_NAME) +1);
+ strcpy(cbdata.attribute_names[cnt], X_NAME);
+ }
+ sprintf(valstr, "%d", x);
+ cbdata.attribute_values[cnt] = (char *)malloc(strlen(valstr) + 1);
+ strcpy(cbdata.attribute_values[cnt], valstr);
+
+ cnt++;
+ if ((name != NULL)&&(name[0] != '\0'))
+ {
+ cbdata.attribute_names[cnt] = (char *)malloc(strlen(name) +
+ strlen(Y_NAME) + 2);
+ strcpy(cbdata.attribute_names[cnt], name);
+ strcat(cbdata.attribute_names[cnt], ".");
+ strcat(cbdata.attribute_names[cnt], Y_NAME);
+ }
+ else
+ {
+ cbdata.attribute_names[cnt] = (char *)malloc(strlen(Y_NAME) +1);
+ strcpy(cbdata.attribute_names[cnt], Y_NAME);
+ }
+ sprintf(valstr, "%d", y);
+ cbdata.attribute_values[cnt] = (char *)malloc(strlen(valstr) + 1);
+ strcpy(cbdata.attribute_values[cnt], valstr);
+
+ XtCallCallbackList ((Widget)hw, hw->html.form_callback,
+ (XtPointer)&cbdata);
+}
+
+
+void
+CBSubmitForm(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ FormInfo *fptr = (FormInfo *)client_data;
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WbFormCallbackData cbdata;
+#ifdef MOTIF
+ XmPushButtonCallbackStruct *pb =
+ (XmPushButtonCallbackStruct *)call_data;
+#endif /* MOTIF */
+
+#ifdef MOTIF
+ cbdata.event = pb->event;
+#else
+ /******* WE HAVE NO EVENT in ATHENA *******/
+ cbdata.event = NULL;
+#endif /* MOTIF */
+ cbdata.href = fptr->action;
+ cbdata.method = fptr->method;
+ cbdata.enctype = fptr->enctype;
+ cbdata.enc_entity = fptr->enc_entity;
+
+ cbdata.attribute_count = CollectSubmitInfo(fptr,
+ &cbdata.attribute_names, &cbdata.attribute_values);
+
+ XtCallCallbackList ((Widget)hw, hw->html.form_callback,
+ (XtPointer)&cbdata);
+}
+
+
+/*
+ * A radio buttom was toggled on in a form.
+ * If there are other radios of the same name, turn them off.
+ */
+void
+CBChangeRadio(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ FormInfo *fptr = (FormInfo *)client_data;
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WidgetInfo *wptr;
+ WidgetInfo *wtmp;
+ char *name;
+ int cnt, count;
+#ifdef MOTIF
+ XmToggleButtonCallbackStruct *tb =
+ (XmToggleButtonCallbackStruct *)call_data;
+#else
+ Boolean state;
+#endif /* MOTIF */
+
+#ifdef MOTIF
+ /*
+ * Bad button
+ */
+ if (tb == NULL)
+ {
+ return;
+ }
+#endif /* MOTIF */
+
+ /*
+ * Only do stuff when the button is turned on.
+ * Don't let the button be turned off, by clicking on
+ * it, as that would leave all buttons off.
+ */
+#ifdef MOTIF
+ if ((tb == NULL)||(tb->set == False))
+ {
+ XmToggleButtonSetState(w, True, False);
+ return;
+ }
+#else
+ XtVaGetValues(w, XtNstate, &state, NULL);
+ if (!state)
+ {
+ XtVaSetValues(w, XtNstate, 1, NULL);
+ return;
+ }
+#endif /* MOTIF */
+
+ /*
+ * Terminate the form if it was never properly terminated.
+ */
+ if (fptr->end == -1) /* unterminated FORM tag */
+ {
+ wptr = hw->html.widget_list;
+ cnt = 0;
+ while (wptr != NULL)
+ {
+ cnt++;
+ wptr = wptr->next;
+ }
+ count = cnt;
+ }
+ else
+ {
+ count = fptr->end - fptr->start;
+ }
+
+ /*
+ * Locate the start of the form.
+ */
+ if (fptr->start == 0)
+ {
+ wptr = hw->html.widget_list;
+ }
+ else
+ {
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->id == fptr->start)
+ {
+ wptr = wptr->next;
+ break;
+ }
+ wptr = wptr->next;
+ }
+ }
+
+ /*
+ * Find the name of the toggle button just pressed.
+ */
+ name = NULL;
+ wtmp = wptr;
+ while (wtmp != NULL)
+ {
+ if (wtmp->w == w)
+ {
+ name = wtmp->name;
+ break;
+ }
+ wtmp = wtmp->next;
+ }
+
+ /*
+ * Check for other checked radioboxes of the same name.
+ */
+ cnt = 0;
+ while ((wptr != NULL)&&(cnt < count))
+ {
+#ifdef MOTIF
+ if ((wptr->type == W_RADIOBOX)&&
+ (wptr->w != w)&&
+ (XmToggleButtonGetState(wptr->w) == True)&&
+ (wptr->name != NULL)&&
+ (name != NULL)&&
+ (strcmp(wptr->name, name) == 0))
+ {
+ XmToggleButtonSetState(wptr->w, False, False);
+ }
+#else
+ if ((wptr->type == W_RADIOBOX)&&
+ (wptr->w != w)&&
+ (wptr->name != NULL)&&
+ (name != NULL)&&
+ (strcmp(wptr->name, name) == 0))
+ {
+ XtVaGetValues(wptr->w, XtNstate, &state, NULL);
+ if (state)
+ {
+ XtVaSetValues(wptr->w, XtNstate, 0, NULL);
+ }
+ }
+#endif /* MOTIF */
+ cnt++;
+ wptr = wptr->next;
+ }
+}
+
+
+#ifdef MOTIF
+/*
+ * Catch all attempted modifications to the textfield for password
+ * entry. This is so we can prevent the password from showing
+ * uponm the screen.
+ * I would prefer that for all insereted characters a random 1-3 '*'s
+ * were added, and any delete deleted the whole string, but due to
+ * bugs in somve version of Motif 1.1 this won't work.
+ */
+void
+CBPasswordModify(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ FormInfo *fptr = (FormInfo *)client_data;
+ XmTextVerifyCallbackStruct *tv =(XmTextVerifyCallbackStruct *)call_data;
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WidgetInfo *wptr;
+ int i, len;
+
+ /*
+ * by default accept nothing
+ tv->doit = False;
+ */
+
+ /*
+ * Ignore when ModifyIgnore is true
+ */
+ if (ModifyIgnore == True)
+ {
+ return;
+ }
+
+ /*
+ * only accept text modification of password fields
+ */
+ if (tv->reason != XmCR_MODIFYING_TEXT_VALUE)
+ {
+ return;
+ }
+
+ /*
+ * find the structure for this widget
+ */
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->w == w)
+ {
+ break;
+ }
+ wptr = wptr->next;
+ }
+ if (wptr == NULL)
+ {
+ return;
+ }
+
+ /*
+ * Deletion.
+ */
+ if (tv->text->ptr == NULL)
+ {
+ tv->doit = True;
+
+ /*
+ * Only can delete if we have stuff to delete.
+ */
+ if ((wptr->password != NULL)&&(wptr->password[0] != '\0'))
+ {
+ int start;
+ char *tptr;
+
+ len = strlen(wptr->password);
+ /*
+ * Find the start of the chunk of text to
+ * delete.
+ */
+ if (tv->startPos < len)
+ {
+ start = tv->startPos;
+ }
+ else
+ {
+ start = len - 1;
+ }
+
+ /*
+ * might be more stuff after the end that we
+ * want to move up
+ */
+ if (tv->endPos > len)
+ {
+ tptr = &(wptr->password[len]);
+ }
+ else
+ {
+ tptr = &(wptr->password[tv->endPos]);
+ }
+ wptr->password[start] = '\0';
+ strcat(wptr->password, tptr);
+ }
+ }
+ /*
+ * Else insert character.
+ */
+ else if (tv->text->length >= 1)
+ {
+ int maxlength, plen;
+ Cardinal argcnt;
+ Arg arg[5];
+
+ /*
+ * No insertion if it makes you exceed maxLength
+ */
+ if (wptr->password == NULL)
+ {
+ plen = 0;
+ }
+ else
+ {
+ plen = strlen(wptr->password);
+ }
+ maxlength = 1000000;
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNmaxLength, &maxlength); argcnt++;
+ XtGetValues(w, arg, argcnt);
+ if ((plen + tv->text->length) > maxlength)
+ {
+ return;
+ }
+
+ if (wptr->password == NULL)
+ {
+ wptr->password = (char *)malloc(tv->text->length + 1);
+ for (i=0; i < tv->text->length; i++)
+ {
+ wptr->password[i] = tv->text->ptr[i];
+ }
+ wptr->password[tv->text->length] = '\0';
+ }
+ /*
+ * else insert a char somewhere.
+ * Make a new buffer. Put everything from before the insert
+ * postion into it. Now insert the character.
+ * Finally append any remaining text.
+ */
+ else
+ {
+ char *buf;
+ char *tptr;
+ char tchar;
+ int start;
+
+ len = strlen(wptr->password);
+ if (tv->startPos < len)
+ {
+ start = tv->startPos;
+ }
+ else
+ {
+ start = len;
+ }
+ tptr = &(wptr->password[start]);
+ tchar = *tptr;
+ *tptr = '\0';
+ buf = (char *)malloc(len + tv->text->length + 1);
+ strcpy(buf, wptr->password);
+ for (i=0; i < tv->text->length; i++)
+ {
+ buf[start + i] = tv->text->ptr[i];
+ }
+ buf[start + tv->text->length] = '\0';
+ *tptr = tchar;
+ strcat(buf, tptr);
+ free(wptr->password);
+ wptr->password = buf;
+ }
+
+ tv->doit = True;
+ /*
+ * make a '*' show up instead of what they typed
+ */
+ for (i=0; i < tv->text->length; i++)
+ {
+ tv->text->ptr[i] = '*';
+ }
+ }
+}
+#endif /* MOTIF */
+
+
+
+/*
+ * RETURN was hit in a textfield in a form.
+ * If this is the only textfield in this form, submit the form.
+ */
+void
+CBActivateField(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ FormInfo *fptr = (FormInfo *)client_data;
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WidgetInfo *wptr;
+ int cnt, count;
+#ifdef MOTIF
+ XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *)call_data;
+#endif /* MOTIF */
+
+ /*
+ * Terminate the form if it was never properly terminated.
+ */
+ if (fptr->end == -1) /* unterminated FORM tag */
+ {
+ wptr = hw->html.widget_list;
+ cnt = 0;
+ while (wptr != NULL)
+ {
+ cnt++;
+ wptr = wptr->next;
+ }
+ count = cnt;
+ }
+ else
+ {
+ count = fptr->end - fptr->start;
+ }
+
+ /*
+ * Locate the start of the form.
+ */
+ if (fptr->start == 0)
+ {
+ wptr = hw->html.widget_list;
+ }
+ else
+ {
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->id == fptr->start)
+ {
+ wptr = wptr->next;
+ break;
+ }
+ wptr = wptr->next;
+ }
+ }
+
+ /*
+ * Count the textfields in this form.
+ */
+ cnt = 0;
+ while ((wptr != NULL)&&(cnt < count))
+ {
+ if ((wptr->type == W_TEXTFIELD)||(wptr->type == W_PASSWORD))
+ {
+ cnt++;
+ }
+ wptr = wptr->next;
+ }
+
+ /*
+ * If this is the only textfield in this form, submit the form.
+ */
+ if (cnt == 1)
+ {
+ CBSubmitForm(w, client_data, call_data);
+ }
+}
+
+
+void
+CBResetForm(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ FormInfo *fptr = (FormInfo *)client_data;
+ HTMLWidget hw = (HTMLWidget)(fptr->hw);
+ WidgetInfo *wptr;
+ int widget_count, cnt;
+#ifdef MOTIF
+ XmPushButtonCallbackStruct *pb =
+ (XmPushButtonCallbackStruct *)call_data;
+#endif /* MOTIF */
+
+ if (fptr->end == -1) /* unterminated FORM tag */
+ {
+ wptr = hw->html.widget_list;
+ cnt = 0;
+ while (wptr != NULL)
+ {
+ cnt++;
+ wptr = wptr->next;
+ }
+ widget_count = cnt;
+ }
+ else
+ {
+ widget_count = fptr->end - fptr->start;
+ }
+
+ if (fptr->start == 0)
+ {
+ wptr = hw->html.widget_list;
+ }
+ else
+ {
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->id == fptr->start)
+ {
+ wptr = wptr->next;
+ break;
+ }
+ wptr = wptr->next;
+ }
+ }
+
+ cnt = 0;
+ while ((wptr != NULL)&&(cnt < widget_count))
+ {
+ Widget child;
+ STRING label;
+#ifdef MOTIF
+ Cardinal argcnt;
+ Arg arg[5];
+#else
+ char *txt = NULL;
+ int length = 0;
+ Boolean stringInPlace;
+#endif /* MOTIF */
+
+ switch(wptr->type)
+ {
+ case W_TEXTFIELD:
+#ifdef MOTIF
+ if (wptr->value == NULL)
+ {
+ XmTextFieldSetString(wptr->w, "");
+ }
+ else
+ {
+ XmTextFieldSetString(wptr->w, wptr->value);
+ }
+#else
+ XtVaGetValues(wptr->w,
+ XtNuseStringInPlace, &stringInPlace,
+ XtNlength, &length,
+ NULL);
+ if (stringInPlace)
+ {
+ XtVaGetValues(wptr->w,
+ XtNstring, &txt,
+ NULL);
+ }
+ if (wptr->value == NULL)
+ {
+ if (stringInPlace)
+ {
+ if (txt) *txt = '\0';
+ XtVaSetValues(wptr->w,
+ XtNstring, txt, NULL);
+ }
+ else
+ {
+ XtVaSetValues(wptr->w,
+ XtNstring, "", NULL);
+ }
+ }
+ else
+ {
+ if (stringInPlace)
+ {
+ strncpy(txt,wptr->value,length);
+ XtVaSetValues(wptr->w,
+ XtNstring, txt, NULL);
+ }
+ else
+ {
+ XtVaSetValues(wptr->w,
+ XtNstring, wptr->value,
+ NULL);
+ }
+ }
+#endif /* MOTIF */
+ break;
+ case W_TEXTAREA:
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNworkWindow, &child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+ if (wptr->value == NULL)
+ {
+ XmTextSetString(child, "");
+ }
+ else
+ {
+ XmTextSetString(child, wptr->value);
+ }
+#else
+ XtVaSetValues(wptr->w, XtNstring,
+ wptr->value ? wptr->value : "",
+ NULL);
+#endif /* MOTIF */
+ break;
+ case W_PASSWORD:
+ if (wptr->value == NULL)
+ {
+#ifdef MOTIF
+ /*
+ * Due to errors in Motif1.1, I can't
+ * call XmTextFieldSetString() here.
+ * Because I have a modifyVerify callback
+ * registered for this widget.
+ * I don't know if this error exists
+ * in Motif1.2 or not.
+ */
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNvalue, "");
+ argcnt++;
+ XtSetValues(wptr->w, arg, argcnt);
+#else
+ XtVaSetValues(wptr->w,
+ XtNstring, "", NULL);
+#endif /* MOTIF */
+ if (wptr->password != NULL)
+ {
+ free(wptr->password);
+ wptr->password = NULL;
+ }
+ }
+ else
+ {
+ int i, len;
+
+ if (wptr->password != NULL)
+ {
+ free(wptr->password);
+ wptr->password = NULL;
+ }
+ len = strlen(wptr->value);
+ wptr->password = (char *)malloc(len + 1);
+ for (i=0; i<len; i++)
+ {
+ wptr->password[i] = '*';
+ }
+ wptr->password[len] = '\0';
+#ifdef MOTIF
+ XmTextFieldSetString(wptr->w,
+ wptr->password);
+#else
+ XtVaSetValues(wptr->w,
+ XtNstring, wptr->password,
+ NULL);
+#endif /* MOTIF */
+ strcpy(wptr->password, wptr->value);
+ }
+ break;
+ case W_LIST:
+ {
+ char **vlist;
+ int vlist_cnt;
+ STRING *val_list;
+ int i;
+
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNworkWindow, &child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+#else
+ WidgetList wl;
+ char **string_list;
+ int list_cnt;
+
+ XtVaGetValues(wptr->w, XtNchildren, &wl, NULL);
+ child = *++wl;
+ XtVaGetValues(child,
+ XtNlist, &string_list,
+ XtNnumberStrings, &list_cnt, NULL);
+#endif /* MOTIF */
+
+ if (wptr->value != NULL)
+ {
+ vlist = ParseCommaList(wptr->value,
+ &vlist_cnt);
+ val_list = (STRING *)malloc(vlist_cnt *
+ sizeof(STRING));
+#ifdef MOTIF
+ XmListDeselectAllItems(child);
+ for (i=0; i<vlist_cnt; i++)
+ {
+ val_list[i] =
+ XmStringCreateSimple(vlist[i]);
+ }
+#else
+ XawListUnhighlight(child);
+ for (i=0; i<vlist_cnt; i++)
+ {
+ val_list[i] =
+ XtNewString(vlist[i]);
+ }
+#endif /* MOTIF */
+ FreeCommaList(vlist, vlist_cnt);
+#ifdef MOTIF
+ if (vlist_cnt > 0)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNselectedItems,
+ val_list);
+ argcnt++;
+ XtSetArg(arg[argcnt],
+ XmNselectedItemCount,
+ vlist_cnt);
+ argcnt++;
+ XtSetValues(child, arg, argcnt);
+ }
+ for (i=0; i<vlist_cnt; i++)
+ {
+ XmStringFree(val_list[i]);
+ }
+#else
+ if (vlist_cnt > 0)
+ {
+ if (vlist_cnt > 1)
+ {
+ fprintf(stderr,
+ "HTML: only a single selection allowed!\n");
+ }
+
+ for (i=0; i<list_cnt; i++)
+ {
+ if (!strcmp(string_list[i],
+ val_list[0]))
+ {
+ XawListHighlight(child, i);
+ break;
+ }
+ }
+ }
+ for (i=0; i<vlist_cnt; i++)
+ {
+ free(val_list[i]);
+ }
+#endif /* MOTIF */
+ if (val_list != NULL)
+ {
+ free((char *)val_list);
+ }
+ }
+ else
+ {
+#ifdef MOTIF
+ XmListDeselectAllItems(child);
+#else
+ XawListUnhighlight(child);
+#endif /* MOTIF */
+ }
+ }
+ break;
+ /*
+ * gack, we saved the widget id of the starting default
+ * into the value character pointer, just so we could
+ * yank it out here, and restore the default.
+ */
+ case W_OPTIONMENU:
+ if (wptr->value != NULL)
+ {
+ Widget hist = (Widget)wptr->value;
+#ifdef MOTIF
+ Cardinal argcnt;
+ Arg arg[5];
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNmenuHistory,
+ hist);
+ argcnt++;
+ XtSetValues(wptr->w, arg, argcnt);
+#else
+ char *txt;
+
+ XtVaGetValues(hist, XtNlabel,&txt,NULL);
+ XtVaSetValues(wptr->w,XtNlabel,txt,NULL);
+#endif /* MOTIF */
+ }
+ break;
+ case W_CHECKBOX:
+ case W_RADIOBOX:
+#ifdef MOTIF
+ if (wptr->checked == True)
+ {
+ XmToggleButtonSetState(wptr->w, True, False);
+ }
+ else
+ {
+ XmToggleButtonSetState(wptr->w, False, False);
+ }
+#else
+ XtVaSetValues(wptr->w,
+ XtNstate, wptr->checked, NULL);
+#endif /* MOTIF */
+ break;
+ case W_HIDDEN:
+ break;
+#ifdef MOTIF
+ case W_JOT:
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNuserData,
+ (XtPointer *)&child);
+ argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+ ClearJot(hw, child, wptr->width, wptr->height);
+ break;
+#endif /* MOTIF */
+ default:
+ break;
+ }
+ cnt++;
+ wptr = wptr->next;
+ }
+}
+
+
+void
+PrepareFormEnd(hw, w, fptr)
+ HTMLWidget hw;
+ Widget w;
+ FormInfo *fptr;
+{
+#ifdef MOTIF
+ XtAddCallback(w, XmNactivateCallback,
+ (XtCallbackProc)CBSubmitForm, (caddr_t)fptr);
+#else
+ XtAddCallback(w, XtNcallback,
+ (XtCallbackProc)CBSubmitForm, (caddr_t)fptr);
+#endif /* MOTIF */
+}
+
+
+void
+PrepareFormReset(hw, w, fptr)
+ HTMLWidget hw;
+ Widget w;
+ FormInfo *fptr;
+{
+#ifdef MOTIF
+ XtAddCallback(w, XmNactivateCallback,
+ (XtCallbackProc)CBResetForm, (caddr_t)fptr);
+#else
+ XtAddCallback(w, XtNcallback,
+ (XtCallbackProc)CBResetForm, (caddr_t)fptr);
+#endif /* MOTIF */
+}
+
+
+void
+HideWidgets(hw)
+ HTMLWidget hw;
+{
+ WidgetInfo *wptr;
+ XEvent event;
+
+#ifdef MOTIF
+ /*
+ * Make sure all expose events have been dealt with first.
+ */
+ XmUpdateDisplay((Widget)hw);
+#endif /* MOTIF */
+
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if ((wptr->w != NULL)&&(wptr->mapped == True))
+ {
+ XtSetMappedWhenManaged(wptr->w, False);
+ wptr->mapped = False;
+ }
+ wptr = wptr->next;
+ }
+
+ /*
+ * Force the exposure events into the queue
+ */
+ XSync(XtDisplay(hw), False);
+
+ /*
+ * Remove all Expose events for the view window
+ */
+ while (XCheckWindowEvent(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), ExposureMask, &event) == True)
+ {
+ }
+}
+
+
+void
+MapWidgets(hw)
+ HTMLWidget hw;
+{
+ WidgetInfo *wptr;
+
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if ((wptr->w != NULL)&&(wptr->mapped == False))
+ {
+ wptr->mapped = True;
+ XtSetMappedWhenManaged(wptr->w, True);
+ }
+ wptr = wptr->next;
+ }
+}
+
+
+Boolean
+AlreadyChecked(hw, fptr, name)
+ HTMLWidget hw;
+ FormInfo *fptr;
+ char *name;
+{
+ WidgetInfo *wptr;
+ Boolean radio_checked;
+
+ radio_checked = False;
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if ((wptr->id >= fptr->start)&&
+ (wptr->type == W_RADIOBOX)&&
+ (wptr->checked == True)&&
+ (wptr->name != NULL)&&
+ (name != NULL)&&
+ (strcmp(wptr->name, name) == 0))
+ {
+ radio_checked = True;
+ break;
+ }
+ wptr = wptr->next;
+ }
+ return(radio_checked);
+}
+
+
+WidgetInfo *
+AddNewWidget(hw, fptr, w, type, id, x, y, width, height, name, value, mapping, checked)
+ HTMLWidget hw;
+ FormInfo *fptr;
+ Widget w;
+ int type;
+ int id;
+ int x, y;
+ int width, height;
+ char *name;
+ char *value;
+ char **mapping;
+ Boolean checked;
+{
+ WidgetInfo *wptr;
+
+ wptr = hw->html.widget_list;
+ if (wptr == NULL)
+ {
+ wptr = (WidgetInfo *)malloc(sizeof(WidgetInfo));
+ wptr->w = w;
+ wptr->type = type;
+ wptr->id = id;
+ wptr->x = x;
+ wptr->y = y;
+ wptr->width = width;
+ wptr->height = height;
+ wptr->name = name;
+ wptr->value = value;
+ wptr->password = NULL;
+ wptr->mapping = mapping;
+ wptr->checked = checked;
+ wptr->mapped = False;
+ wptr->next = NULL;
+ hw->html.widget_list = wptr;
+ }
+ else
+ {
+ while (wptr->next != NULL)
+ {
+ wptr = wptr->next;
+ }
+ wptr->next = (WidgetInfo *)malloc(sizeof(WidgetInfo));
+ wptr = wptr->next;
+ wptr->w = w;
+ wptr->type = type;
+ wptr->id = id;
+ wptr->x = x;
+ wptr->y = y;
+ wptr->width = width;
+ wptr->height = height;
+ wptr->name = name;
+ wptr->value = value;
+ wptr->password = NULL;
+ wptr->mapping = mapping;
+ wptr->checked = checked;
+ wptr->mapped = False;
+ wptr->next = NULL;
+ }
+
+ if ((wptr->type == W_PASSWORD)&&(wptr->value != NULL))
+ {
+ wptr->password = (char *)malloc(strlen(wptr->value) + 1);
+ strcpy(wptr->password, wptr->value);
+ }
+
+ return(wptr);
+}
+
+
+/*
+ * For the various widgets, return their fon structures so
+ * we can use the font's baseline to place them.
+ */
+XFontStruct *
+GetWidgetFont(hw, wptr)
+ HTMLWidget hw;
+ WidgetInfo *wptr;
+{
+ Widget child;
+ XFontStruct *font;
+#ifdef MOTIF
+ Boolean ret;
+ Cardinal argcnt;
+ Arg arg[5];
+ XmFontList font_list = (XmFontList)NULL;
+ XmFontContext font_context;
+ XmStringCharSet charset;
+#endif /* MOTIF */
+
+ /*
+ * For option menus we have to first get the child that has the
+ * font info.
+ */
+ if (wptr->type == W_OPTIONMENU)
+ {
+#ifdef MOTIF
+ child = XmOptionButtonGadget(wptr->w);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNfontList, &font_list); argcnt++;
+ XtGetValues(child, arg, argcnt);
+#else
+ XtVaGetValues(wptr->w, XtNfont, &font, NULL);
+#endif /* MOTIF */
+ }
+ else
+ {
+#ifdef MOTIF
+ if ((wptr->type == W_TEXTAREA)||(wptr->type == W_LIST))
+ {
+ child = NULL;
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNworkWindow, &child); argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNfontList,&font_list); argcnt++;
+ XtGetValues(child, arg, argcnt);
+ }
+#else
+ if (wptr->type == W_LIST)
+ {
+ WidgetList wl;
+ int nc;
+ XtVaGetValues(wptr->w,
+ XtNchildren, &wl, XtNnumChildren, &nc, NULL);
+ child = *++wl;
+ XtVaGetValues(child, XtNfont, &font, NULL);
+ }
+#endif /* MOTIF */
+ else
+ {
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNfontList,&font_list); argcnt++;
+ XtGetValues(wptr->w, arg, argcnt);
+#else
+ XtVaGetValues(wptr->w, XtNfont, &font, NULL);
+#endif /* MOTIF */
+ }
+ }
+
+#ifdef MOTIF
+ if (font_list == (XmFontList)NULL)
+ {
+ return((XFontStruct *)NULL);
+ }
+
+ ret = XmFontListInitFontContext(&font_context, font_list);
+ if (ret == False)
+ {
+ return((XFontStruct *)NULL);
+ }
+
+ ret = XmFontListGetNextFont(font_context, &charset, &font);
+ if (ret == False)
+ {
+ return((XFontStruct *)NULL);
+ }
+ else
+ {
+ XmFontListFreeFontContext(font_context);
+ free((char *)charset);
+ return(font);
+ }
+#else
+ return(font);
+#endif /* MOTIF */
+}
+
+
+/*
+ * Get the next value in a comma separated list.
+ * Also unescape the '\' escaping done in ComposeCommaList
+ * and convert the single ''' characters back to '"'
+ * characters
+ */
+char *
+NextComma(string)
+ char *string;
+{
+ char *tptr;
+
+ tptr = string;
+ while (*tptr != '\0')
+ {
+ if (*tptr == '\\')
+ {
+ *tptr = '\0';
+ strcat(string, (char *)(tptr + 1));
+ tptr++;
+ }
+ else if (*tptr == '\'')
+ {
+ *tptr = '\"';
+ tptr++;
+ }
+ else if (*tptr == ',')
+ {
+ return(tptr);
+ }
+ else
+ {
+ tptr++;
+ }
+ }
+ return(tptr);
+}
+
+
+char **
+ParseCommaList(str, count)
+ char *str;
+ int *count;
+{
+ char *str_copy;
+ char **list;
+ char **tlist;
+ char *tptr;
+ char *val;
+ int i, cnt;
+ int max_cnt;
+
+ *count = 0;
+ if ((str == NULL)||(*str == '\0'))
+ {
+ return((char **)NULL);
+ }
+ str_copy = (char *)malloc(strlen(str) + 1);
+ if (str_copy == NULL)
+ {
+ return((char **)NULL);
+ }
+ strcpy(str_copy, str);
+
+ list = (char **)malloc(50 * sizeof(char *));
+ if (list == NULL)
+ {
+ return((char **)NULL);
+ }
+ max_cnt = 50;
+
+ /*
+ * This loop counts the number of objects
+ * in this list.
+ * As a side effect, NextComma() unescapes in place so
+ * "\\" becomes '\' and "\," becomes ',' and "\"" becomes '"'
+ */
+ cnt = 0;
+ val = str_copy;
+ tptr = NextComma(val);
+ while (*tptr != '\0')
+ {
+ if ((cnt + 1) == max_cnt)
+ {
+ tlist = (char **)malloc((max_cnt +50) * sizeof(char *));
+ if (tlist == NULL)
+ {
+ return((char **)NULL);
+ }
+ for (i=0; i<cnt; i++)
+ {
+ tlist[i] = list[i];
+ }
+ free((char *)list);
+ list = tlist;
+ max_cnt += 50;
+ }
+ *tptr = '\0';
+ list[cnt] = (char *)malloc(strlen(val) + 1);
+ if (list[cnt] == NULL)
+ {
+ return((char **)NULL);
+ }
+ strcpy(list[cnt], val);
+ cnt++;
+
+ val = (char *)(tptr + 1);
+ tptr = NextComma(val);
+ }
+ list[cnt] = (char *)malloc(strlen(val) + 1);
+ if (list[cnt] == NULL)
+ {
+ return((char **)NULL);
+ }
+ strcpy(list[cnt], val);
+ cnt++;
+
+ free(str_copy);
+ tlist = (char **)malloc(cnt * sizeof(char *));
+ if (tlist == NULL)
+ {
+ return((char **)NULL);
+ }
+ for (i=0; i<cnt; i++)
+ {
+ tlist[i] = list[i];
+ }
+ free((char *)list);
+ list = tlist;
+
+ *count = cnt;
+ return(list);
+}
+
+
+/*
+ * Compose a single string comma separated list from
+ * an array of strings. Any '\', or ',' in the
+ * list are escaped with a prepending '\'.
+ * So they become '\\' and '\,'
+ * Also we want to allow '"' characters in the list, but
+ * they would get eaten by the later parsing code, so we will
+ * turn '"' into ''', and turn ''' into '\''
+ */
+char *
+ComposeCommaList(list, cnt)
+ char **list;
+ int cnt;
+{
+ int i;
+ char *fail;
+ char *buf;
+ char *tbuf;
+ int len, max_len;
+
+ fail = (char *)malloc(1);
+ *fail = '\0';
+
+ if (cnt == 0)
+ {
+ return(fail);
+ }
+
+ buf = (char *)malloc(1024);
+ if (buf == NULL)
+ {
+ return(fail);
+ }
+ max_len = 1024;
+ len = 0;
+ buf[0] = '\0';
+
+ for (i=0; i<cnt; i++)
+ {
+ char *option;
+ char *tptr;
+ int olen;
+
+ option = list[i];
+ if (option == NULL)
+ {
+ olen = 0;
+ }
+ else
+ {
+ olen = strlen(option);
+ }
+ if ((len + (olen * 2)) >= max_len)
+ {
+ tbuf = (char *)malloc(max_len + olen + 1024);
+ if (tbuf == NULL)
+ {
+ return(fail);
+ }
+ strcpy(tbuf, buf);
+ free(buf);
+ buf = tbuf;
+ max_len = max_len + olen + 1024;
+ }
+ tptr = (char *)(buf + len);
+ while ((option != NULL)&&(*option != '\0'))
+ {
+ if ((*option == '\\')||(*option == ',')||
+ (*option == '\''))
+ {
+ *tptr++ = '\\';
+ *tptr++ = *option++;
+ len += 2;
+ }
+ else if (*option == '\"')
+ {
+ *tptr++ = '\'';
+ option++;
+ len++;
+ }
+ else
+ {
+ *tptr++ = *option++;
+ len++;
+ }
+ }
+ if (i != (cnt - 1))
+ {
+ *tptr++ = ',';
+ len++;
+ }
+ *tptr = '\0';
+ }
+
+ tbuf = (char *)malloc(len + 1);
+ if (tbuf == NULL)
+ {
+ return(fail);
+ }
+ strcpy(tbuf, buf);
+ free(buf);
+ buf = tbuf;
+ free(fail);
+ return(buf);
+}
+
+
+void
+FreeCommaList(list, cnt)
+ char **list;
+ int cnt;
+{
+ int i;
+
+ for (i=0; i<cnt; i++)
+ {
+ if (list[i] != NULL)
+ {
+ free(list[i]);
+ }
+ }
+ if (list != NULL)
+ {
+ free((char *)list);
+ }
+}
+
+
+/*
+ * Clean up the mucked value field for a TEXTAREA.
+ * Unescape the things with '\' in front of them, and transform
+ * lone ' back to "
+ */
+void
+UnMuckTextAreaValue(value)
+ char *value;
+{
+ char *tptr;
+
+ if ((value == NULL)||(value[0] == '\0'))
+ {
+ return;
+ }
+
+ tptr = value;
+ while (*tptr != '\0')
+ {
+ if (*tptr == '\\')
+ {
+ *tptr = '\0';
+ strcat(value, (char *)(tptr + 1));
+ tptr++;
+ }
+ else if (*tptr == '\'')
+ {
+ *tptr = '\"';
+ tptr++;
+ }
+ else
+ {
+ tptr++;
+ }
+ }
+}
+
+
+char *
+MapOptionReturn(val, mapping)
+ char *val;
+ char **mapping;
+{
+ int cnt;
+
+ if (mapping == NULL)
+ {
+ return(val);
+ }
+
+ cnt = 0;
+ while (mapping[cnt] != NULL)
+ {
+ if (strcmp(mapping[cnt], val) == 0)
+ {
+ return(mapping[cnt + 1]);
+ }
+ cnt += 2;
+ }
+ return(val);
+}
+
+
+char **
+MakeOptionMappings(list1, list2, list_cnt)
+ char **list1;
+ char **list2;
+ int list_cnt;
+{
+ int i, cnt;
+ char **list;
+
+ /*
+ * pass through to see how many mappings we have.
+ */
+ cnt = 0;
+ for (i=0; i<list_cnt; i++)
+ {
+ if ((list2[i] != NULL)&&(*list2[i] != '\0'))
+ {
+ cnt++;
+ }
+ }
+
+ if (cnt == 0)
+ {
+ return(NULL);
+ }
+
+ list = (char **)malloc(((2 * cnt) + 1) * sizeof(char *));
+ if (list == NULL)
+ {
+ return(NULL);
+ }
+
+ cnt = 0;
+ for (i=0; i<list_cnt; i++)
+ {
+ if ((list2[i] != NULL)&&(*list2[i] != '\0'))
+ {
+ list[cnt] = (char *)malloc(strlen(list1[i]) + 1);
+ list[cnt + 1] = (char *)malloc(strlen(list2[i]) + 1);
+ if ((list[cnt] == NULL)||(list[cnt + 1] == NULL))
+ {
+ return(NULL);
+ }
+ strcpy(list[cnt], list1[i]);
+ strcpy(list[cnt + 1], list2[i]);
+ cnt += 2;
+ }
+ }
+ list[cnt] = NULL;
+
+ return(list);
+}
+
+
+#ifdef MOTIF
+/********** MOTIF VERSION *************/
+/*
+ * Make the appropriate widget for this tag, and fill in an
+ * WidgetInfo structure and return it.
+ */
+WidgetInfo *
+MakeWidget(hw, text, x, y, id, fptr)
+ HTMLWidget hw;
+ char *text;
+ int x, y;
+ int id;
+ FormInfo *fptr;
+{
+ Arg arg[30];
+ Cardinal argcnt;
+ Widget w;
+ WidgetInfo *wlist;
+ WidgetInfo *wptr;
+ Dimension width, height;
+
+ wlist = hw->html.widget_list;
+ while (wlist != NULL)
+ {
+ if (wlist->id == id)
+ {
+ break;
+ }
+ wlist = wlist->next;
+ }
+
+ /*
+ * If this widget is not on the list, we have never
+ * used it before. Create it now.
+ */
+ if (wlist == NULL)
+ {
+ char widget_name[100];
+ char **mapping;
+ char *tptr;
+ char *value;
+ char *name;
+ char *type_str;
+ int type;
+ short size;
+ int maxlength;
+ Boolean checked;
+
+ mapping = NULL;
+
+ checked = False;
+ name = ParseMarkTag(text, MT_INPUT, "NAME");
+
+ /*
+ * We may need to shorten the name for the widgets,
+ * which can't handle long names.
+ */
+ if (name == NULL)
+ {
+ widget_name[0] = '\0';
+ }
+ else if (strlen(name) > 99)
+ {
+ strncpy(widget_name, name, 99);
+ widget_name[99] = '\0';
+ }
+ else
+ {
+ strcpy(widget_name, name);
+ }
+
+ type_str = ParseMarkTag(text, MT_INPUT, "TYPE");
+ if ((type_str != NULL)&&(strcmp(type_str, "checkbox") == 0))
+ {
+ XmString label;
+
+ type = W_CHECKBOX;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(strlen("on") + 1);
+ strcpy(value, "on");
+ }
+
+ tptr = ParseMarkTag(text, MT_INPUT, "CHECKED");
+
+ /* We want no text on our toggles */
+ label = XmStringCreateSimple("");
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNlabelString, label); argcnt++;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (tptr != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNset, True); argcnt++;
+ checked = True;
+ free(tptr);
+ }
+ w = XmCreateToggleButton(hw->html.view, widget_name,
+ arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+
+ XmStringFree(label);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "hidden") == 0))
+ {
+ type = W_HIDDEN;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(1);
+ value[0] = '\0';
+ }
+
+ w = NULL;
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "radio") == 0))
+ {
+ XmString label;
+
+ type = W_RADIOBOX;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(strlen("on") + 1);
+ strcpy(value, "on");
+ }
+
+ /*
+ * Only one checked radio button with the
+ * same name per form
+ */
+ tptr = ParseMarkTag(text, MT_INPUT, "CHECKED");
+ if ((tptr != NULL)&&
+ (AlreadyChecked(hw, fptr, name) == True))
+ {
+ free(tptr);
+ tptr = NULL;
+ }
+
+ /* We want no text on our toggles */
+ label = XmStringCreateSimple("");
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNlabelString, label); argcnt++;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XmNindicatorType, XmONE_OF_MANY);
+ argcnt++;
+ if (tptr != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNset, True); argcnt++;
+ checked = True;
+ free(tptr);
+ }
+ w = XmCreateToggleButton(hw->html.view, widget_name,
+ arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ XtAddCallback(w, XmNvalueChangedCallback,
+ (XtCallbackProc)CBChangeRadio, (caddr_t)fptr);
+
+ XmStringFree(label);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "submit") == 0))
+ {
+ XmString label;
+
+ type = W_PUSHBUTTON;
+ label = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if ((value == NULL)||(*value == '\0'))
+ {
+ value = (char *)malloc(strlen("Submit Query") +
+ 1);
+ strcpy(value, "Submit Query");
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (value != NULL)
+ {
+ label = XmStringCreateSimple(value);
+ XtSetArg(arg[argcnt], XmNlabelString, label);
+ argcnt++;
+ }
+ w = XmCreatePushButton(hw->html.view, widget_name,
+ arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ if (label != NULL)
+ {
+ XmStringFree(label);
+ }
+ PrepareFormEnd(hw, w, fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "reset") == 0))
+ {
+ XmString label;
+
+ type = W_PUSHBUTTON;
+ label = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if ((value == NULL)||(*value == '\0'))
+ {
+ value = (char *)malloc(strlen("Reset") + 1);
+ strcpy(value, "Reset");
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (value != NULL)
+ {
+ label = XmStringCreateSimple(value);
+ XtSetArg(arg[argcnt], XmNlabelString, label);
+ argcnt++;
+ }
+ w = XmCreatePushButton(hw->html.view, widget_name,
+ arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ if (label != NULL)
+ {
+ XmStringFree(label);
+ }
+ PrepareFormReset(hw, w, fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "button") == 0))
+ {
+ XmString label;
+
+ type = W_PUSHBUTTON;
+ label = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (value != NULL)
+ {
+ label = XmStringCreateSimple(value);
+ XtSetArg(arg[argcnt], XmNlabelString, label);
+ argcnt++;
+ }
+ w = XmCreatePushButton(hw->html.view, widget_name,
+ arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ if (label != NULL)
+ {
+ XmStringFree(label);
+ }
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "jot") == 0))
+ {
+ XmString label;
+ Dimension width, height;
+ Widget frame;
+ char **list;
+ int list_cnt;
+
+ type = W_JOT;
+ label = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ /*
+ * SIZE is WIDTH,HEIGHT
+ */
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ list = ParseCommaList(tptr, &list_cnt);
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ width = 200;
+ height = 50;
+ if (list_cnt == 1)
+ {
+ width = atoi(list[0]);
+ }
+ else if (list_cnt > 1)
+ {
+ width = atoi(list[0]);
+ height = atoi(list[1]);
+ }
+ FreeCommaList(list, list_cnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XmNshadowType, XmSHADOW_IN);
+ argcnt++;
+ frame = XmCreateFrame(hw->html.view, "Frame",
+ arg, argcnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNwidth, width); argcnt++;
+ XtSetArg(arg[argcnt], XmNheight, height); argcnt++;
+ w = XmCreateDrawingArea(frame, widget_name,
+ arg, argcnt);
+ XtManageChild(w);
+
+ NewJot(w, width, height);
+ XtAddEventHandler(w, ExposureMask, 0,
+ EVJotExpose, (XtPointer)hw);
+ XtAddEventHandler(w, ButtonPressMask, 0,
+ EVJotPress, (XtPointer)hw);
+ XtAddEventHandler(w, ButtonMotionMask, 0,
+ EVJotMove, (XtPointer)hw);
+ XtAddEventHandler(w, ButtonReleaseMask, 0,
+ EVJotRelease, (XtPointer)hw);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNuserData, (XtPointer)w);
+ argcnt++;
+ XtSetValues(frame, arg, argcnt);
+
+ w = frame;
+
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ if (label != NULL)
+ {
+ XmStringFree(label);
+ }
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "select") == 0))
+ {
+ XmString label;
+ Widget scroll;
+ Widget pulldown, button, hist;
+ char *options;
+ char *returns;
+ char **list;
+ int list_cnt;
+ char **ret_list;
+ int return_cnt;
+ char **vlist;
+ int vlist_cnt;
+ int i, mult, size;
+
+ type = -1;
+ tptr = ParseMarkTag(text, MT_INPUT, "HINT");
+ if ((tptr != NULL)&&(strcmp(tptr, "list") == 0))
+ {
+ type = W_LIST;
+ }
+ else if ((tptr != NULL)&&(strcmp(tptr, "menu") == 0))
+ {
+ type = W_OPTIONMENU;
+ }
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ size = 5;
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr != NULL)
+ {
+ size = atoi(tptr);
+ if ((size > 1)&&(type == -1))
+ {
+ type = W_LIST;
+ }
+ free(tptr);
+ }
+
+ mult = 0;
+ tptr = ParseMarkTag(text, MT_INPUT, "MULTIPLE");
+ if (tptr != NULL)
+ {
+ if (type == -1)
+ {
+ type = W_LIST;
+ }
+ mult = 1;
+ free(tptr);
+ }
+
+ if (type == -1)
+ {
+ type = W_OPTIONMENU;
+ }
+
+ label = NULL;
+ hist = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ options = ParseMarkTag(text, MT_INPUT, "OPTIONS");
+ returns = ParseMarkTag(text, MT_INPUT, "RETURNS");
+ list = ParseCommaList(options, &list_cnt);
+ if (options != NULL)
+ {
+ free(options);
+ }
+
+ ret_list = ParseCommaList(returns, &return_cnt);
+ if (returns != NULL)
+ {
+ free(returns);
+ }
+
+ /*
+ * If return_cnt is less than list_cnt, the user made
+ * a serious error. Try to recover by padding out
+ * ret_list with NULLs
+ */
+ if (list_cnt > return_cnt)
+ {
+ int rcnt;
+ char **rlist;
+
+ rlist = (char **)malloc(list_cnt *
+ sizeof(char *));
+ for (rcnt = 0; rcnt < return_cnt; rcnt++)
+ {
+ rlist[rcnt] = ret_list[rcnt];
+ }
+ for (rcnt = return_cnt; rcnt < list_cnt; rcnt++)
+ {
+ rlist[rcnt] = NULL;
+ }
+ if (ret_list != NULL)
+ {
+ free((char *)ret_list);
+ }
+ ret_list = rlist;
+ }
+
+ vlist = ParseCommaList(value, &vlist_cnt);
+
+ if (size > list_cnt)
+ {
+ size = list_cnt;
+ }
+ if (size < 1)
+ {
+ size = 1;
+ }
+
+ mapping = MakeOptionMappings(list, ret_list, list_cnt);
+
+ if (type == W_OPTIONMENU)
+ {
+ Widget child;
+ XmString xmstr;
+ argcnt = 0;
+ pulldown = XmCreatePulldownMenu(hw->html.view,
+ widget_name, arg, argcnt);
+
+ for (i=0; i<list_cnt; i++)
+ {
+ char bname[30];
+
+ sprintf(bname, "Button%d", (i + 1));
+ label = XmStringCreateSimple(list[i]);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNlabelString,
+ label);
+ argcnt++;
+ button = XmCreatePushButton(pulldown,
+ bname, arg, argcnt);
+ XtManageChild(button);
+ XmStringFree(label);
+
+ if ((vlist_cnt > 0)&&
+ (vlist[0] != NULL)&&
+ (strcmp(vlist[0], list[i]) ==0))
+ {
+ hist = button;
+ }
+
+ /*
+ * Start hist out as the first button
+ * so that if the user didn't set a
+ * default we always default to the
+ * first element.
+ */
+ if ((i == 0)&&(hist == NULL))
+ {
+ hist = button;
+ }
+ }
+
+ FreeCommaList(list, list_cnt);
+ FreeCommaList(ret_list, list_cnt);
+ FreeCommaList(vlist, vlist_cnt);
+ if (value != NULL)
+ {
+ free(value);
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XmNsubMenuId, pulldown);
+ argcnt++;
+ if (hist != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNmenuHistory,
+ hist);
+ argcnt++;
+ /*
+ * A gaggage. Value is used to later
+ * restore defaults. For option menu
+ * this means we need to save a child
+ * widget id as opposed to the
+ * character string everyone else uses.
+ */
+ value = (char *)hist;
+ }
+ w = XmCreateOptionMenu(hw->html.view,
+ widget_name, arg, argcnt);
+ argcnt = 0;
+ xmstr = XmStringCreateSimple ("");
+ XtSetArg(arg[argcnt], XmNlabelString,
+ (XtArgVal)xmstr);
+ argcnt++;
+ child = XmOptionLabelGadget (w);
+ XtSetValues (child, arg, argcnt);
+ XmStringFree (xmstr);
+ }
+ else /* type == W_LIST */
+ {
+ XmString *string_list;
+ XmString *val_list;
+
+ if ((!mult)&&(vlist_cnt > 1))
+ {
+ free(value);
+ value = (char *)malloc(
+ strlen(vlist[0]) + 1);
+ strcpy(value, vlist[0]);
+ }
+
+ string_list = (XmString *)malloc(list_cnt *
+ sizeof(XmString));
+ val_list = (XmString *)malloc(vlist_cnt *
+ sizeof(XmString));
+
+ for (i=0; i<list_cnt; i++)
+ {
+ string_list[i] =
+ XmStringCreateSimple(list[i]);
+ }
+ for (i=0; i<vlist_cnt; i++)
+ {
+ val_list[i] =
+ XmStringCreateSimple(vlist[i]);
+ }
+
+ FreeCommaList(list, list_cnt);
+ FreeCommaList(ret_list, list_cnt);
+ FreeCommaList(vlist, vlist_cnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ scroll = XmCreateScrolledWindow(hw->html.view,
+ "Scroll", arg, argcnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNitems, string_list);
+ argcnt++;
+ XtSetArg(arg[argcnt], XmNitemCount, list_cnt);
+ argcnt++;
+ XtSetArg(arg[argcnt], XmNvisibleItemCount,size);
+ argcnt++;
+ if (mult)
+ {
+ XtSetArg(arg[argcnt],XmNselectionPolicy,
+ XmEXTENDED_SELECT);
+ argcnt++;
+ }
+ else
+ {
+ XtSetArg(arg[argcnt],XmNselectionPolicy,
+ XmBROWSE_SELECT);
+ argcnt++;
+ }
+ if ((vlist_cnt > 0)&&(mult))
+ {
+ XtSetArg(arg[argcnt], XmNselectedItems,
+ val_list);
+ argcnt++;
+ XtSetArg(arg[argcnt],
+ XmNselectedItemCount,
+ vlist_cnt);
+ argcnt++;
+ }
+ else if ((vlist_cnt > 0)&&(!mult))
+ {
+ XtSetArg(arg[argcnt], XmNselectedItems,
+ &val_list[0]);
+ argcnt++;
+ XtSetArg(arg[argcnt],
+ XmNselectedItemCount, 1);
+ argcnt++;
+ }
+ w = XmCreateList(scroll, widget_name,
+ arg, argcnt);
+ XtManageChild(w);
+ w = scroll;
+
+ for (i=0; i<list_cnt; i++)
+ {
+ XmStringFree(string_list[i]);
+ }
+ if (string_list != NULL)
+ {
+ free((char *)string_list);
+ }
+ for (i=0; i<vlist_cnt; i++)
+ {
+ XmStringFree(val_list[i]);
+ }
+ if (val_list != NULL)
+ {
+ free((char *)val_list);
+ }
+ }
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "password") ==0))
+ {
+ type = W_PASSWORD;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ size = -1;
+ maxlength = -1;
+
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr != NULL)
+ {
+ size = atoi(tptr);
+ free(tptr);
+ }
+
+ tptr = ParseMarkTag(text, MT_INPUT, "MAXLENGTH");
+ if (tptr != NULL)
+ {
+ maxlength = atoi(tptr);
+ free(tptr);
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (size > 0)
+ {
+ XtSetArg(arg[argcnt], XmNcolumns, size);
+ argcnt++;
+ }
+ if (maxlength > 0)
+ {
+ XtSetArg(arg[argcnt], XmNmaxLength, maxlength);
+ argcnt++;
+ }
+ if (value != NULL)
+ {
+ int i, len;
+ char *bval;
+
+ len = strlen(value);
+ bval = (char *)malloc(len + 1);
+ for (i=0; i<len; i++)
+ {
+ bval[i] = '*';
+ }
+ bval[len] = '\0';
+ XtSetArg(arg[argcnt], XmNvalue, bval);
+ argcnt++;
+ }
+ w = XmCreateTextField(hw->html.view, widget_name,
+ arg, argcnt);
+/*
+ * The proper order here is XtSetMappedWhenManaged, XtManageChild. But a bug
+ * in some versions of Motif1.1 makes us do it the other way. All versions
+ * of 1.2 should have this fixed
+ */
+#ifdef MOTIF1_2
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+#else
+ XtManageChild(w);
+ XtSetMappedWhenManaged(w, False);
+#endif /* MOTIF1_2 */
+ XtAddCallback(w, XmNactivateCallback,
+ (XtCallbackProc)CBActivateField, (caddr_t)fptr);
+ XtAddCallback(w, XmNmodifyVerifyCallback,
+ (XtCallbackProc)CBPasswordModify, (caddr_t)fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "textarea") ==0))
+ {
+ char **list;
+ int list_cnt;
+ int rows, cols;
+ Widget scroll;
+
+ type = W_TEXTAREA;
+
+ /*
+ * If there is no SIZE, look for ROWS and COLS
+ * directly.
+ * SIZE is COLUMNS,ROWS parse the list
+ */
+ rows = -1;
+ cols = -1;
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr == NULL)
+ {
+ tptr = ParseMarkTag(text, MT_INPUT, "ROWS");
+ if (tptr != NULL)
+ {
+ rows = atoi(tptr);
+ free(tptr);
+ }
+ tptr = ParseMarkTag(text, MT_INPUT, "COLS");
+ if (tptr != NULL)
+ {
+ cols = atoi(tptr);
+ free(tptr);
+ }
+ }
+ else
+ {
+ list = ParseCommaList(tptr, &list_cnt);
+ free(tptr);
+
+ if (list_cnt == 1)
+ {
+ cols = atoi(list[0]);
+ }
+ else if (list_cnt > 1)
+ {
+ cols = atoi(list[0]);
+ rows = atoi(list[1]);
+ }
+ FreeCommaList(list, list_cnt);
+ }
+
+ /*
+ * Grab the starting value of the text here.
+ * NULL if none.
+ */
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ UnMuckTextAreaValue(value);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ scroll = XmCreateScrolledWindow(hw->html.view,
+ "Scroll", arg, argcnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNeditMode, XmMULTI_LINE_EDIT);
+ argcnt++;
+ if (cols > 0)
+ {
+ XtSetArg(arg[argcnt], XmNcolumns, cols);
+ argcnt++;
+ }
+ if (rows > 0)
+ {
+ XtSetArg(arg[argcnt], XmNrows, rows);
+ argcnt++;
+ }
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNvalue, value);
+ argcnt++;
+ }
+ w = XmCreateText(scroll, widget_name, arg, argcnt);
+ XtManageChild(w);
+ w = scroll;
+
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else /* if no type, assume type=text */
+ {
+ char **list;
+ int list_cnt;
+ int rows, cols;
+ Widget scroll;
+
+ /*
+ * SIZE can be either COLUMNS or COLUMNS,ROWS
+ * we assume COLUMNS,ROWS and parse the list
+ */
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ list = ParseCommaList(tptr, &list_cnt);
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ /*
+ * If only COLUMNS specified, or SIZE not specified
+ * assume a TEXTFIELD
+ * Otherwise a TEXTAREA.
+ */
+ if (list_cnt <= 1)
+ {
+ type = W_TEXTFIELD;
+ if (list_cnt == 1)
+ {
+ cols = atoi(list[0]);
+ }
+ else
+ {
+ cols = -1;
+ }
+ }
+ else
+ {
+ type = W_TEXTAREA;
+ cols = atoi(list[0]);
+ rows = atoi(list[1]);
+ }
+ /*
+ * Now that we have cols, and maybe rows, free the list
+ */
+ FreeCommaList(list, list_cnt);
+
+ /*
+ * Grab the starting value of the text here.
+ * NULL if none.
+ */
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ /*
+ * For textfileds parse maxlength and
+ * set up the widget.
+ */
+ if (type == W_TEXTFIELD)
+ {
+ maxlength = -1;
+ tptr = ParseMarkTag(text, MT_INPUT,"MAXLENGTH");
+ if (tptr != NULL)
+ {
+ maxlength = atoi(tptr);
+ free(tptr);
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ if (cols > 0)
+ {
+ XtSetArg(arg[argcnt], XmNcolumns, cols);
+ argcnt++;
+ }
+ if (maxlength > 0)
+ {
+ XtSetArg(arg[argcnt], XmNmaxLength,
+ maxlength);
+ argcnt++;
+ }
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNvalue, value);
+ argcnt++;
+ }
+ w = XmCreateTextField(hw->html.view,
+ widget_name, arg, argcnt);
+ }
+ /*
+ * Else this is a TEXTAREA. Maxlength is ignored,
+ * and we set up the scrolled window
+ */
+ else
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ scroll = XmCreateScrolledWindow(hw->html.view,
+ "Scroll", arg, argcnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNeditMode,
+ XmMULTI_LINE_EDIT);
+ argcnt++;
+ if (cols > 0)
+ {
+ XtSetArg(arg[argcnt], XmNcolumns, cols);
+ argcnt++;
+ }
+ if (rows > 0)
+ {
+ XtSetArg(arg[argcnt], XmNrows, rows);
+ argcnt++;
+ }
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XmNvalue, value);
+ argcnt++;
+ }
+ w = XmCreateText(scroll, widget_name,
+ arg, argcnt);
+ XtManageChild(w);
+ w = scroll;
+ }
+
+/*
+ * The proper order here is XtSetMappedWhenManaged, XtManageChild. But a bug
+ * in some versions of Motif1.1 makes us do it the other way. All versions
+ * of 1.2 should have this fixed
+ */
+#ifdef MOTIF1_2
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+#else
+ XtManageChild(w);
+ XtSetMappedWhenManaged(w, False);
+#endif /* MOTIF1_2 */
+
+ /*
+ * For textfields, a CR might be an activate
+ */
+ if (type == W_TEXTFIELD)
+ {
+ XtAddCallback(w, XmNactivateCallback,
+ (XtCallbackProc)CBActivateField, (caddr_t)fptr);
+ }
+ }
+ if (type_str != NULL)
+ {
+ free(type_str);
+ }
+
+ /*
+ * Don't want to do GetValues if this is HIDDEN input
+ * tag with no widget.
+ */
+ if (w != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNwidth, &width); argcnt++;
+ XtSetArg(arg[argcnt], XmNheight, &height); argcnt++;
+ XtGetValues(w, arg, argcnt);
+ }
+ else
+ {
+ width = 0;
+ height = 0;
+ }
+
+ wptr = AddNewWidget(hw, fptr, w, type, id, x, y, width, height,
+ name, value, mapping, checked);
+ }
+ else
+ /*
+ * We found this widget on the list of already created widgets.
+ * Put it in place for reuse.
+ */
+ {
+ wlist->x = x;
+ wlist->y = y;
+
+ /*
+ * Don't want to SetValues if type HIDDEN which
+ * has no widget.
+ */
+ if (wlist->w != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XmNy, y); argcnt++;
+ XtSetValues(wlist->w, arg, argcnt);
+ }
+
+ wptr = wlist;
+ }
+
+ return(wptr);
+}
+#else
+/********** ATHENA VERSION *************/
+/*
+ * Make the appropriate widget for this tag, and fill in an
+ * WidgetInfo structure and return it.
+ */
+WidgetInfo *
+MakeWidget(hw, text, x, y, id, fptr)
+ HTMLWidget hw;
+ char *text;
+ int x, y;
+ int id;
+ FormInfo *fptr;
+{
+ Arg arg[30];
+ Cardinal argcnt;
+ Widget w;
+ WidgetInfo *wlist;
+ WidgetInfo *wptr;
+ Dimension width, height;
+
+ wlist = hw->html.widget_list;
+ while (wlist != NULL)
+ {
+ if (wlist->id == id)
+ {
+ break;
+ }
+ wlist = wlist->next;
+ }
+
+ /*
+ * If this widget is not on the list, we have never
+ * used it before. Create it now.
+ */
+ if (wlist == NULL)
+ {
+ char *tptr;
+ char *value;
+ char *name;
+ char *type_str;
+ int type;
+ short size;
+ int maxlength;
+ Boolean checked;
+
+ checked = False;
+ name = ParseMarkTag(text, MT_INPUT, "NAME");
+
+ type_str = ParseMarkTag(text, MT_INPUT, "TYPE");
+ if ((type_str != NULL)&&(strcmp(type_str, "checkbox") == 0))
+ {
+ type = W_CHECKBOX;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(strlen("on") + 1);
+ strcpy(value, "on");
+ }
+
+ tptr = ParseMarkTag(text, MT_INPUT, "CHECKED");
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ if (tptr != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNstate, True); argcnt++;
+ checked = True;
+ free(tptr);
+ }
+ XtSetArg(arg[argcnt], XtNlabel, ""); argcnt++;
+ w = XtCreateWidget(name, toggleWidgetClass,
+ hw->html.view, arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "hidden") == 0))
+ {
+ type = W_HIDDEN;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(1);
+ value[0] = '\0';
+ }
+
+ w = NULL;
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "radio") == 0))
+ {
+ type = W_RADIOBOX;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if (value == NULL)
+ {
+ value = (char *)malloc(strlen("on") + 1);
+ strcpy(value, "on");
+ }
+
+ /*
+ * Only one checked radio button with the
+ * same name per form
+ */
+ tptr = ParseMarkTag(text, MT_INPUT, "CHECKED");
+ if ((tptr != NULL)&&
+ (AlreadyChecked(hw, fptr, name) == True))
+ {
+ free(tptr);
+ tptr = NULL;
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ if (tptr != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNstate, True); argcnt++;
+ checked = True;
+ free(tptr);
+ }
+ XtSetArg(arg[argcnt], XtNlabel, ""); argcnt++;
+ w = XtCreateWidget(name, toggleWidgetClass,
+ hw->html.view, arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ XtAddCallback(w, XtNcallback,
+ (XtCallbackProc)CBChangeRadio, (caddr_t)fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "submit") == 0))
+ {
+ type = W_PUSHBUTTON;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if ((value == NULL)||(*value == '\0'))
+ {
+ value = (char *)malloc(strlen("Submit Query") +
+ 1);
+ strcpy(value, "Submit Query");
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNlabel, value);
+ argcnt++;
+ }
+ w = XtCreateWidget(name, commandWidgetClass,
+ hw->html.view, arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ PrepareFormEnd(hw, w, fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "reset") == 0))
+ {
+ type = W_PUSHBUTTON;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ if ((value == NULL)||(*value == '\0'))
+ {
+ value = (char *)malloc(strlen("Reset") + 1);
+ strcpy(value, "Reset");
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNlabel, value);
+ argcnt++;
+ }
+ w = XtCreateWidget(name, commandWidgetClass,
+ hw->html.view, arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ PrepareFormReset(hw, w, fptr);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "button") == 0))
+ {
+ type = W_PUSHBUTTON;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNlabel, value);
+ argcnt++;
+ }
+ w = XtCreateWidget(name, commandWidgetClass,
+ hw->html.view, arg, argcnt);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "select") == 0))
+ {
+ STRING label;
+ Widget scroll;
+ Widget pulldown, button, hist;
+ char *options;
+ char **list;
+ int list_cnt;
+ char **vlist;
+ int vlist_cnt;
+ int i, mult, size;
+
+ type = -1;
+ tptr = ParseMarkTag(text, MT_INPUT, "HINT");
+ if ((tptr != NULL)&&(strcmp(tptr, "list") == 0))
+ {
+ type = W_LIST;
+ }
+ else if ((tptr != NULL)&&(strcmp(tptr, "menu") == 0))
+ {
+ type = W_OPTIONMENU;
+ }
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ size = 5;
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr != NULL)
+ {
+ size = atoi(tptr);
+ if ((size > 1)&&(type == -1))
+ {
+ type = W_LIST;
+ }
+ free(tptr);
+ }
+
+ mult = 0;
+ tptr = ParseMarkTag(text, MT_INPUT, "MULTIPLE");
+ if (tptr != NULL)
+ {
+ if (type == -1)
+ {
+ type = W_LIST;
+ }
+ mult = 1;
+ free(tptr);
+ }
+
+ if (type == -1)
+ {
+ type = W_OPTIONMENU;
+ }
+
+ label = NULL;
+ hist = NULL;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ options = ParseMarkTag(text, MT_INPUT, "OPTIONS");
+ list = ParseCommaList(options, &list_cnt);
+ if (options != NULL)
+ {
+ free(options);
+ }
+
+ vlist = ParseCommaList(value, &vlist_cnt);
+
+ if (size > list_cnt)
+ {
+ size = list_cnt;
+ }
+ if (size < 1)
+ {
+ size = 1;
+ }
+
+ if (type == W_OPTIONMENU)
+ {
+ XFontStruct *font;
+ Dimension maxWidth = 0, width, iW;
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ w = XtCreateWidget(name,
+ menuButtonWidgetClass,
+ hw->html.view, arg, argcnt);
+ argcnt = 0;
+ pulldown = XtCreatePopupShell("menu",
+ simpleMenuWidgetClass, w,
+ arg, argcnt);
+
+ for (i=0; i<list_cnt; i++)
+ {
+ char bname[30];
+
+ sprintf(bname, "Button%d", (i + 1));
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNlabel,
+ list[i]);
+ argcnt++;
+ button = XtCreateWidget(bname,
+ smeBSBObjectClass,
+ pulldown, arg, argcnt);
+ XtManageChild(button);
+
+ XtAddCallback(button, XtNcallback,
+ CBoption, (XtPointer)w);
+
+ if (i==0)
+ {
+ XtVaGetValues(w,
+ XtNfont, &font,
+ XtNinternalWidth, &iW,
+ NULL);
+ }
+
+ width = XTextWidth(font, list[i],
+ strlen(list[i]));
+
+ if (width > maxWidth) maxWidth = width;
+
+ if ((vlist_cnt > 0)&&
+ (vlist[0] != NULL)&&
+ (strcmp(vlist[0], list[i]) ==0))
+ {
+ hist = button;
+ XtVaSetValues(w,
+ XtNlabel,
+ XtNewString(list[i]),
+ NULL);
+ }
+
+ /*
+ * Start hist out as the first button
+ * so that if the user didn't set a
+ * default we always default to the
+ * first element.
+ */
+ if ((i == 0)&&(hist == NULL))
+ {
+ hist = button;
+ }
+ }
+
+ XtVaSetValues(w, XtNwidth, maxWidth + (4 * iW),
+ NULL);
+
+ FreeCommaList(vlist, vlist_cnt);
+ if (value != NULL)
+ {
+ free(value);
+ }
+
+ if (hist != NULL)
+ {
+ /*
+ * A gaggage. Value is used to later
+ * restore defaults. For option menu
+ * this means we need to save a child
+ * widget id as opposed to the
+ * character string everyone else uses.
+ */
+ value = (char *)hist;
+ }
+ }
+ else /* type == W_LIST */
+ {
+ STRING *string_list;
+ STRING *val_list;
+
+ if ((!mult)&&(vlist_cnt > 1))
+ {
+ free(value);
+ value = (char *)malloc(
+ strlen(vlist[0]) + 1);
+ strcpy(value, vlist[0]);
+ }
+
+ string_list = (STRING *)malloc(list_cnt *
+ sizeof(STRING));
+ val_list = (STRING *)malloc(vlist_cnt *
+ sizeof(STRING));
+
+ for (i=0; i<list_cnt; i++)
+ {
+ string_list[i] =
+ XtNewString(list[i]);
+ }
+ for (i=0; i<vlist_cnt; i++)
+ {
+ val_list[i] =
+ XtNewString(vlist[i]);
+ }
+
+ FreeCommaList(list, list_cnt);
+ FreeCommaList(vlist, vlist_cnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XtNallowVert, True);
+ argcnt++;
+ scroll = XtCreateWidget("Scroll",
+ viewportWidgetClass,
+ hw->html.view, arg, argcnt);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNdefaultColumns, 1);
+ argcnt++;
+ w = XtCreateWidget(name,
+ listWidgetClass,
+ scroll, arg, argcnt);
+ XtManageChild(w);
+
+ XtAddCallback(w, XtNdestroyCallback,
+ CBListDestroy, NULL);
+
+ XawListChange(w, string_list, list_cnt,
+ 0, True);
+
+ if (vlist_cnt > 0)
+ {
+ if (vlist_cnt > 1)
+ {
+ fprintf(stderr,
+ "HTML: only a single selection allowed!\n");
+ }
+
+ for (i=0; i<list_cnt; i++)
+ {
+ if (!strcmp(string_list[i],val_list[0]))
+ {
+ XawListHighlight(w, i);
+ break;
+ }
+ }
+ }
+
+ if (size>list_cnt) size=list_cnt;
+ if (size>1)
+ {
+ XFontStruct *font;
+ Dimension h,width, s;
+
+ XtVaGetValues(w, XtNfont, &font,
+ XtNinternalHeight, &h,
+ XtNwidth, &width,
+ XtNrowSpacing, &s,
+ NULL);
+ XtVaSetValues(scroll,
+ XtNheight,
+ h + size*(s+FONTHEIGHT(font)),
+ XtNwidth, width + 20,
+ NULL);
+ }
+
+ w = scroll;
+
+ for (i=0; i<vlist_cnt; i++)
+ {
+ free(val_list[i]);
+ }
+ if (val_list != NULL)
+ {
+ free((char *)val_list);
+ }
+ }
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "password") ==0))
+ {
+ char *txt;
+
+ type = W_PASSWORD;
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ size = -1;
+ maxlength = -1;
+
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr != NULL)
+ {
+ size = atoi(tptr);
+ free(tptr);
+ }
+
+ tptr = ParseMarkTag(text, MT_INPUT, "MAXLENGTH");
+ if (tptr != NULL)
+ {
+ maxlength = atoi(tptr);
+ free(tptr);
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XtNeditType, XawtextEdit);
+ argcnt++;
+
+ if (maxlength > 0)
+ {
+ if (value)
+ {
+ txt = XtNewString(value);
+ txt = (char*)realloc(txt,
+ sizeof(char)*(maxlength+1));
+ }
+ else
+ {
+ txt = (char *)malloc(sizeof(char)*
+ (maxlength+1));
+ *txt = '\0';
+ }
+ XtSetArg(arg[argcnt], XtNuseStringInPlace, 1);
+ argcnt++;
+ XtSetArg(arg[argcnt], XtNlength, maxlength);
+ argcnt++;
+ }
+ else
+ {
+ XtSetArg(arg[argcnt], XtNuseStringInPlace, 0);
+ argcnt++;
+ }
+
+
+ if (value != NULL)
+ {
+ int i, len;
+ char *bval;
+
+ len = strlen(value);
+ if (maxlength > 0)
+ {
+ bval = txt;
+ if (maxlength<len) len = maxlength+1;
+ }
+ else
+ {
+ bval = (char *)malloc(len + 1);
+ }
+ for (i=0; i<len; i++)
+ {
+ bval[i] = '*';
+ }
+ bval[len] = '\0';
+ XtSetArg(arg[argcnt], XtNstring, bval);
+ argcnt++;
+ }
+ else /* value == NULL */
+ {
+ if (maxlength>0) /* stringInPlace */
+ {
+ XtSetArg(arg[argcnt], XtNstring, txt);
+ argcnt++;
+ }
+ }
+
+ w = XtCreateWidget(name, asciiTextWidgetClass,
+ hw->html.view, arg, argcnt);
+
+ if (maxlength > 0)
+ {
+ XtAddCallback(w, XtNdestroyCallback,
+ (XtCallbackProc)CBTextDestroy,
+ (caddr_t)txt);
+ }
+
+ XtOverrideTranslations(w,
+ XtParseTranslationTable("<Key>: HTMLpwdInput()"));
+ XtOverrideTranslations(w,
+ XtParseTranslationTable("<Key>Return: no-op(RingBell)"));
+
+ setTextSize(w,size<1?20:size,1);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else if ((type_str != NULL)&&(strcmp(type_str, "textarea") ==0))
+ {
+ char **list;
+ int list_cnt;
+ int rows, cols;
+
+ type = W_TEXTAREA;
+
+ /*
+ * If there is no SIZE, look for ROWS and COLS
+ * directly.
+ * SIZE is COLUMNS,ROWS parse the list
+ */
+ rows = -1;
+ cols = -1;
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ if (tptr == NULL)
+ {
+ tptr = ParseMarkTag(text, MT_INPUT, "ROWS");
+ if (tptr != NULL)
+ {
+ rows = atoi(tptr);
+ free(tptr);
+ }
+ tptr = ParseMarkTag(text, MT_INPUT, "COLS");
+ if (tptr != NULL)
+ {
+ cols = atoi(tptr);
+ free(tptr);
+ }
+ }
+ else
+ {
+ list = ParseCommaList(tptr, &list_cnt);
+ free(tptr);
+
+ if (list_cnt == 1)
+ {
+ cols = atoi(list[0]);
+ }
+ else if (list_cnt > 1)
+ {
+ cols = atoi(list[0]);
+ rows = atoi(list[1]);
+ }
+ FreeCommaList(list, list_cnt);
+ }
+
+ /*
+ * Grab the starting value of the text here.
+ * NULL if none.
+ */
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+ UnMuckTextAreaValue(value);
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XtNeditType, XawtextEdit);
+ argcnt++;
+
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNstring, value);
+ argcnt++;
+ }
+ w = XtCreateWidget(name, asciiTextWidgetClass,
+ hw->html.view, arg, argcnt);
+
+ setTextSize(w,cols>0?cols:20,rows>0?rows:1);
+
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ else /* if no type, assume type=text */
+ {
+ char **list;
+ int list_cnt;
+ int rows, cols;
+
+ /*
+ * SIZE can be either COLUMNS or COLUMNS,ROWS
+ * we assume COLUMNS,ROWS and parse the list
+ */
+ tptr = ParseMarkTag(text, MT_INPUT, "SIZE");
+ list = ParseCommaList(tptr, &list_cnt);
+ if (tptr != NULL)
+ {
+ free(tptr);
+ }
+
+ /*
+ * If only COLUMNS specified, or SIZE not specified
+ * assume a TEXTFIELD
+ * Otherwise a TEXTAREA.
+ */
+ if (list_cnt <= 1)
+ {
+ type = W_TEXTFIELD;
+ if (list_cnt == 1)
+ {
+ cols = atoi(list[0]);
+ }
+ else
+ {
+ cols = -1;
+ }
+ }
+ else
+ {
+ type = W_TEXTAREA;
+ cols = atoi(list[0]);
+ rows = atoi(list[1]);
+ }
+ /*
+ * Now that we have cols, and maybe rows, free the list
+ */
+ FreeCommaList(list, list_cnt);
+
+ /*
+ * Grab the starting value of the text here.
+ * NULL if none.
+ */
+ value = ParseMarkTag(text, MT_INPUT, "VALUE");
+
+ /*
+ * For textfileds parse maxlength and
+ * set up the widget.
+ */
+ if (type == W_TEXTFIELD)
+ {
+ char *txt;
+
+ maxlength = -1;
+ tptr = ParseMarkTag(text, MT_INPUT,"MAXLENGTH");
+ if (tptr != NULL)
+ {
+ maxlength = atoi(tptr);
+ free(tptr);
+ }
+
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+
+ if (maxlength > 0)
+ {
+ if (value)
+ {
+ txt = XtNewString(value);
+ txt = (char *)realloc(txt,
+ maxlength);
+ }
+ else
+ {
+ txt = (char *)malloc(maxlength);
+ *txt = '\0';
+ }
+ XtSetArg(arg[argcnt],
+ XtNuseStringInPlace,1);
+ argcnt++;
+ XtSetArg(arg[argcnt],
+ XtNlength, maxlength);
+ argcnt++;
+ XtSetArg(arg[argcnt], XtNstring, txt);
+ argcnt++;
+ }
+ else
+ {
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt],
+ XtNuseStringInPlace,0);
+ argcnt++;
+ txt = value;
+ XtSetArg(arg[argcnt],
+ XtNstring, txt);
+ argcnt++;
+ }
+ }
+
+ XtSetArg(arg[argcnt], XtNeditType, XawtextEdit);
+ argcnt++;
+ w = XtCreateWidget(name,
+ asciiTextWidgetClass,
+ hw->html.view, arg, argcnt);
+
+ if (maxlength > 0)
+ {
+ XtAddCallback(w, XtNdestroyCallback,
+ CBTextDestroy, (caddr_t)txt);
+ }
+
+ XtOverrideTranslations(w,
+ XtParseTranslationTable(
+ "<Key>Return: no-op(RingBell)"));
+ setTextSize(w,cols>0?cols:20,1);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ /*
+ * Else this is a TEXTAREA. Maxlength is ignored,
+ * and we set up the scrolled window
+ */
+ else
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ XtSetArg(arg[argcnt], XtNeditType, XawtextEdit);
+ argcnt++;
+
+ if (value != NULL)
+ {
+ XtSetArg(arg[argcnt], XtNstring, value);
+ argcnt++;
+ }
+ w = XtCreateWidget(name,
+ asciiTextWidgetClass,
+ hw->html.view, arg, argcnt);
+ setTextSize(w,cols>0?cols:20,rows>0?rows:1);
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+
+ XtSetMappedWhenManaged(w, False);
+ XtManageChild(w);
+ }
+ if (type_str != NULL)
+ {
+ free(type_str);
+ }
+
+ /*
+ * Don't want to do GetValues if this is HIDDEN input
+ * tag with no widget.
+ */
+ if (w != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNwidth, &width); argcnt++;
+ XtSetArg(arg[argcnt], XtNheight, &height); argcnt++;
+ XtGetValues(w, arg, argcnt);
+ }
+ else
+ {
+ width = 0;
+ height = 0;
+ }
+
+ wptr = AddNewWidget(hw, fptr, w, type, id, x, y, width, height,
+ name, value, checked);
+ }
+ else
+ /*
+ * We found this widget on the list of already created widgets.
+ * Put it in place for reuse.
+ */
+ {
+ wlist->x = x;
+ wlist->y = y;
+
+ /*
+ * Don't want to SetValues if type HIDDEN which
+ * has no widget.
+ */
+ if (wlist->w != NULL)
+ {
+ XtUnmanageChild(wlist->w);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNx, x); argcnt++;
+ XtSetArg(arg[argcnt], XtNy, y); argcnt++;
+ XtSetValues(wlist->w, arg, argcnt);
+ XtManageChild(wlist->w);
+ }
+
+ wptr = wlist;
+ }
+
+ return(wptr);
+}
+#endif /* MOTIF */
+
+
+void
+WidgetRefresh(hw, eptr)
+ HTMLWidget hw;
+ struct ele_rec *eptr;
+{
+ if ((eptr->widget_data != NULL)&&(eptr->widget_data->mapped == False)&&
+ (eptr->widget_data->w != NULL))
+ {
+ eptr->widget_data->mapped = True;
+ XtSetMappedWhenManaged(eptr->widget_data->w, True);
+ }
+
+#if 0
+ if (eptr->pic_data != NULL)
+ {
+ int x, y, extra;
+
+ x = eptr->x;
+ y = eptr->y + eptr->y_offset;
+
+ if ((hw->html.border_images == True)||
+ (eptr->anchorHRef != NULL))
+ {
+ extra = IMAGE_BORDER;
+ }
+ else
+ {
+ extra = 0;
+ }
+
+ x = x - hw->html.scroll_x;
+ y = y - hw->html.scroll_y;
+ XSetForeground(XtDisplay(hw), hw->html.drawGC, eptr->fg);
+ XSetBackground(XtDisplay(hw), hw->html.drawGC, eptr->bg);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, y,
+ (eptr->pic_data->width + (2 * extra)),
+ extra);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x,
+ (y + eptr->pic_data->height + extra),
+ (eptr->pic_data->width + (2 * extra)),
+ extra);
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ x, y,
+ extra,
+ (eptr->pic_data->height + (2 * extra)));
+ XFillRectangle(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view), hw->html.drawGC,
+ (x + eptr->pic_data->width + extra),
+ y,
+ extra,
+ (eptr->pic_data->height + (2 * extra)));
+
+ if (eptr->pic_data->image == (Pixmap)NULL)
+ {
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->image = InfoToImage(hw,
+ eptr->pic_data);
+ }
+ else
+ {
+ eptr->pic_data->image = NoImage(hw);
+ }
+ }
+
+ if (eptr->pic_data->image != (Pixmap)NULL)
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ eptr->pic_data->image,
+ XtWindow(hw->html.view), hw->html.drawGC, 0, 0,
+ eptr->pic_data->width, eptr->pic_data->height,
+ (x + extra),
+ (y + extra));
+ }
+ }
+#endif
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/Icon.c b/vendor/x11iraf/obm/ObmW/Icon.c
new file mode 100644
index 00000000..b4696665
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Icon.c
@@ -0,0 +1,224 @@
+/* Generated by wbuild from "Icon.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/extensions/shape.h>
+#include <stdio.h>
+#include "IconP.h"
+static void activate(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"activate", activate},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Down>,<Btn1Up>: activate() \n\
+<Key>Return: activate() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void realize(
+#if NeedFunctionPrototypes
+Widget,XtValueMask *,XSetWindowAttributes *
+#endif
+);
+static void create_image_gc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void create_image_gc(self)Widget self;
+{
+ Dimension wd, ht;
+ Position x, y;
+ XtGCMask mask = GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
+ XGCValues values;
+
+ if (((XfwfIconWidget)self)->xfwfIcon.image_gc != NULL) XtReleaseGC(self, ((XfwfIconWidget)self)->xfwfIcon.image_gc);
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &wd, &ht);
+ if (((XfwfIconWidget)self)->xfwfIcon.image && ((XfwfIconWidget)self)->xfwfIcon.image->pixmap != None) {
+ values.tile = ((XfwfIconWidget)self)->xfwfIcon.image->pixmap;
+ mask |= GCTile;
+ }
+ values.fill_style = FillTiled;
+ values.ts_x_origin = x;
+ values.ts_y_origin = y;
+ ((XfwfIconWidget)self)->xfwfIcon.image_gc = XtGetGC(self, mask, &values);
+}
+
+static XtResource resources[] = {
+{XtNimage,XtCImage,XtRIcon,sizeof(((XfwfIconRec*)NULL)->xfwfIcon.image),XtOffsetOf(XfwfIconRec,xfwfIcon.image),XtRImmediate,(XtPointer)NULL },
+{XtNactivate,XtCActivate,XtRCallback,sizeof(((XfwfIconRec*)NULL)->xfwfIcon.activate),XtOffsetOf(XfwfIconRec,xfwfIcon.activate),XtRImmediate,(XtPointer)NULL },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfIconRec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfIconRec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)0 },
+};
+
+XfwfIconClassRec xfwfIconClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfBoardClassRec,
+"Icon",
+sizeof(XfwfIconRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+realize,
+actionsList,
+1,
+resources,
+3,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfIcon_class part */
+0
+},
+};
+WidgetClass xfwfIconWidgetClass = (WidgetClass) &xfwfIconClassRec;
+/*ARGSUSED*/
+static void activate(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XtCallCallbackList(self, ((XfwfIconWidget)self)->xfwfIcon.activate, event);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfIconWidgetClass c = (XfwfIconWidgetClass) class;
+ XfwfIconWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfIconWidgetClass) return;
+ super = (XfwfIconWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Dimension dummy1, dummy2;
+ Position x, y;
+
+ ((XfwfIconWidget)self)->xfwfIcon.image_gc = NULL;
+ create_image_gc(self);
+ if (((XfwfIconWidget)self)->xfwfIcon.image && (((XfwfIconWidget)self)->xfwfIcon.image->attributes.valuemask & XpmSize) != 0) {
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &dummy1, &dummy2);
+ XtVaSetValues(self, XtNwidth, ((XfwfIconWidget)self)->xfwfIcon.image->attributes.width + 2*x,
+ XtNheight, ((XfwfIconWidget)self)->xfwfIcon.image->attributes.height + 2*y, NULL);
+ }
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Dimension wd, ht;
+ Position x, y;
+
+ if (! XtIsRealized(self)) return;
+ if (((XfwfIconWidget)self)->xfwfIcon.image && ((XfwfIconWidget)self)->xfwfIcon.image->pixmap != None) {
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &wd, &ht);
+ XFillRectangle(XtDisplay(self), XtWindow(self), ((XfwfIconWidget)self)->xfwfIcon.image_gc, x, y, wd, ht);
+ }
+ xfwfBoardClassRec.core_class.expose(self, event, region);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Dimension dummy1, dummy2;
+ Position x, y;
+ Boolean need_redraw = False;
+
+ if (((XfwfIconWidget)old)->xfwfFrame.frameWidth != ((XfwfIconWidget)self)->xfwfFrame.frameWidth
+ || ((XfwfIconWidget)old)->xfwfFrame.outerOffset != ((XfwfIconWidget)self)->xfwfFrame.outerOffset
+ || ((XfwfIconWidget)old)->xfwfIcon.image != ((XfwfIconWidget)self)->xfwfIcon.image) {
+ create_image_gc(self);
+ need_redraw = True;
+ }
+ if (((XfwfIconWidget)old)->xfwfIcon.image != ((XfwfIconWidget)self)->xfwfIcon.image && ((XfwfIconWidget)self)->xfwfIcon.image) {
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &dummy1, &dummy2);
+ if ((((XfwfIconWidget)self)->xfwfIcon.image->attributes.valuemask & XpmSize) != 0)
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfBoard_class.set_abs_location(self, CWWidth | CWHeight, 0, 0,
+ ((XfwfIconWidget)self)->xfwfIcon.image->attributes.width + 2*x,
+ ((XfwfIconWidget)self)->xfwfIcon.image->attributes.height + 2*y);
+ if (((XfwfIconWidget)self)->xfwfIcon.image->mask != None && XtIsRealized(self))
+ XShapeCombineMask(XtDisplay(self), XtWindow(self), ShapeBounding,
+ x, y, ((XfwfIconWidget)self)->xfwfIcon.image->mask, ShapeSet);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+/*ARGSUSED*/static void realize(self,mask,attributes)Widget self;XtValueMask * mask;XSetWindowAttributes * attributes;
+{
+ Dimension wd, ht;
+ Position x, y;
+
+ xfwfBoardClassRec.core_class.realize(self, mask, attributes);
+ ((XfwfIconWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &wd, &ht);
+ if (((XfwfIconWidget)self)->xfwfIcon.image && ((XfwfIconWidget)self)->xfwfIcon.image->mask != None)
+ XShapeCombineMask(XtDisplay(self), XtWindow(self), ShapeBounding,
+ x, y, ((XfwfIconWidget)self)->xfwfIcon.image->mask, ShapeSet);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Icon.h b/vendor/x11iraf/obm/ObmW/Icon.h
new file mode 100644
index 00000000..966ee3e5
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Icon.h
@@ -0,0 +1,31 @@
+/* Generated by wbuild from "Icon.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfIcon_H_
+#define _XfwfIcon_H_
+#include "Board.h"
+#include "Converters.h"
+#ifndef XtNimage
+#define XtNimage "image"
+#endif
+#ifndef XtCImage
+#define XtCImage "Image"
+#endif
+#ifndef XtRIcon
+#define XtRIcon "Icon"
+#endif
+
+#ifndef XtNactivate
+#define XtNactivate "activate"
+#endif
+#ifndef XtCActivate
+#define XtCActivate "Activate"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+typedef struct _XfwfIconClassRec *XfwfIconWidgetClass;
+typedef struct _XfwfIconRec *XfwfIconWidget;
+externalref WidgetClass xfwfIconWidgetClass;
+#endif /*_XfwfIcon_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Icon.man b/vendor/x11iraf/obm/ObmW/Icon.man
new file mode 100644
index 00000000..0a77db34
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Icon.man
@@ -0,0 +1,392 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfIcon
+.SH DESCRIPTION
+The XfwfIcon widget displays an image. The preferred width and
+height of the widget will be set to the width and height of the loaded
+image, plus space for the frame. The widget has a callback
+\fIactivateCallback\fP, that is by default bound to a click of the left
+mouse button.
+
+The image is a \fIPixmap\fP, optionally accompanied by a mask, to make
+parts of the image transparent. When the image has a mask, the frame
+around the widget will not be shown.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfIcon
+Name Class Type Default
+XtNimage XtCImage Icon * NULL
+XtNactivate XtCActivate Callback NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNimage"
+The image must be in \fIPixmap\fP format. The width and height of the
+image will be used to set the width and height of the widget. There
+is a converter for strings (defined in the Common widget), which will
+try to interpret a string as a file name and load the file. The file
+must be in XPM format. The converter also knows about some built-in
+images, called \fI"FATAL"\fP, \fI"ERROR"\fP, \fI"WARNING"\fP, \fI"QUESTION"\fP,
+\fI"INFO"\fP and \fI"NONE"\fP.
+
+
+
+.hi
+
+.nf
+Icon * image = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNactivate"
+The callback is called by the \fIactivate\fP action, which is by default
+bound to a click of mouse button 1.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList activate = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+By default, icons do not have a frame.
+
+
+
+.hi
+
+.nf
+ frameWidth = 0
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The type \fIIcon\fP is defined in \fIConverters.h\fP
+
+.nf
+
+.B incl
+ <Xfwf/Converters.h>
+.fi
+
+.SS "Translations"
+
+By default, the \fIactivate\fP action is bound to a mouse click and to
+the Return key.
+
+
+
+.nf
+<Btn1Down>,<Btn1Up>: activate()
+.fi
+
+.nf
+<Key>Return: activate()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "activate
+
+The \fIactivate\fP action just calls the \fIactivate\fP callback functions,
+passing the \fIXEvent\fP pointer in the \fIcall_data\fP argument.
+
+.hi
+
+.nf
+void activate($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XtCallCallbackList($, $activate, event);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <X11/extensions/shape.h>
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The GC for drawing the image.
+
+
+
+.nf
+GC image_gc
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The \fIinitialize\fP sets the (desired and actual) size of the widget to
+the size of the image. The GC is initialized.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Dimension dummy1, dummy2;
+ Position x, y;
+
+ $image_gc = NULL;
+ create_image_gc($);
+ if ($image ($image->attributes.valuemask XpmSize) != 0) {
+ $compute_inside($, x, y, dummy1, dummy2);
+ XtVaSetValues($, XtNwidth, $image->attributes.width + 2*x,
+ XtNheight, $image->attributes.height + 2*y, NULL);
+ }
+}
+.fi
+
+The \fIexpose\fP method simply draws the image (if any) against the top
+left corner of the widget. The window is first masked with the image's
+mask. After that the images is drawn with a call to \fIXFillRectangle\fP.
+The GC is queried first, to see if the origin needs changing.
+Unfortunately, this involves a round trip to the server. Finally,
+\fIexpose\fP calls the superclass's \fIexpose\fP method to draw the frame.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Dimension wd, ht;
+ Position x, y;
+
+ if (! XtIsRealized($)) return;
+ if ($image $image->pixmap != None) {
+ $compute_inside($, x, y, wd, ht);
+ XFillRectangle(XtDisplay($), XtWindow($), $image_gc, x, y, wd, ht);
+ }
+ #expose($, event, region);
+}
+.fi
+
+A change of image also causes a change in size.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Dimension dummy1, dummy2;
+ Position x, y;
+ Boolean need_redraw = False;
+
+ if ($old$frameWidth != $frameWidth
+ || $old$outerOffset != $outerOffset
+ || $old$image != $image) {
+ create_image_gc($);
+ need_redraw = True;
+ }
+ if ($old$image != $image $image) {
+ $compute_inside($, x, y, dummy1, dummy2);
+ if (($image->attributes.valuemask XpmSize) != 0)
+ $set_abs_location($, CWWidth | CWHeight, 0, 0,
+ $image->attributes.width + 2*x,
+ $image->attributes.height + 2*y);
+ if ($image->mask != None XtIsRealized($))
+ XShapeCombineMask(XtDisplay($), XtWindow($), ShapeBounding,
+ x, y, $image->mask, ShapeSet);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+.fi
+
+When the Widget is realized, the window is immediately combined with
+the icon's mask.
+
+.nf
+realize($, XtValueMask * mask, XSetWindowAttributes * attributes)
+{
+ Dimension wd, ht;
+ Position x, y;
+
+ #realize($, mask, attributes);
+ $compute_inside($, x, y, wd, ht);
+ if ($image $image->mask != None)
+ XShapeCombineMask(XtDisplay($), XtWindow($), ShapeBounding,
+ x, y, $image->mask, ShapeSet);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The GC is created by a utility function. It sets the fill style to
+\fIFillTiled\fP and the origin to the coordinates just inside the widget's
+frame
+
+.nf
+create_image_gc($)
+{
+ Dimension wd, ht;
+ Position x, y;
+ XtGCMask mask = GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin;
+ XGCValues values;
+
+ if ($image_gc != NULL) XtReleaseGC($, $image_gc);
+ $compute_inside($, x, y, wd, ht);
+ if ($image $image->pixmap != None) {
+ values.tile = $image->pixmap;
+ mask |= GCTile;
+ }
+ values.fill_style = FillTiled;
+ values.ts_x_origin = x;
+ values.ts_y_origin = y;
+ $image_gc = XtGetGC($, mask, values);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/IconP.h b/vendor/x11iraf/obm/ObmW/IconP.h
new file mode 100644
index 00000000..1089db47
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/IconP.h
@@ -0,0 +1,41 @@
+/* Generated by wbuild from "Icon.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfIconP_H_
+#define _XfwfIconP_H_
+#include "BoardP.h"
+#include "Icon.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfIconClassPart;
+typedef struct _XfwfIconClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfIconClassPart xfwfIcon_class;
+} XfwfIconClassRec;
+
+typedef struct {
+/* resources */
+Icon * image;
+XtCallbackList activate;
+/* private state */
+GC image_gc;
+} XfwfIconPart;
+
+typedef struct _XfwfIconRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfIconPart xfwfIcon;
+} XfwfIconRec;
+
+externalref XfwfIconClassRec xfwfIconClassRec;
+
+#endif /* _XfwfIconP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Imakefile b/vendor/x11iraf/obm/ObmW/Imakefile
new file mode 100644
index 00000000..7bb51686
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Imakefile
@@ -0,0 +1,241 @@
+XCOMM Imakefile for the Object Manager special widget library.
+XCOMM 05-Sep-93, Doug Tody NOAO/IRAF.
+
+X11IRAFDIR = ../../
+#include <../../X11IRAF.tmpl>
+
+ EXTRA_INCLUDES = -I../../include
+ EXTRA_DEFINES = -D_NO_PROTO
+
+# Hack to compile under SunPRO V4 on Solaris
+#if defined (SunArchitecture) && HasSunC && OSMajorVersion >= 5
+#if OSMinorVersion <= 5
+#if !defined (i386Architecture)
+ CCOPTIONS = -Xs
+ EXTRA_LDOPTIONS = -xildoff
+#endif
+#endif
+#endif
+
+#if defined (PpcDarwinArchitecture) || defined (TenonServer)
+ CCOPTIONS = -traditional-cpp
+#endif
+
+#if ((GccMajorVersion == 3) && (GccMinorVersion >= 1))
+ CCOPTIONS = -DUSE_STDARG
+#else
+ CCOPTIONS =
+#endif
+
+
+
+HEADERS = \
+ Arrow.h ArrowP.h Board.h BoardP.h Button.h ButtonP.h \
+ Common.h CommonP.h Converters.h DrawingArea.h DrawingAreaP.h \
+ Frame.h FrameP.h Group.h GroupP.h Gterm.h GtermP.h HTML.h HTMLP.h \
+ HTMLamp.h Icon.h IconP.h Label.h LabelP.h Layout.h LayoutP.h \
+ MenuBar.h MenuBarP.h MultiList.h MultiListP.h RadioGrp.h RadioGrpP.h \
+ RowCol.h RowColP.h Scrollbar.h ScrollbarP.h Slider2.h Slider2P.h \
+ TabString.h Toggle.h ToggleP.h done.h inkstore.h laygram.h scroll.h \
+ Tabs.h TabsP.h Gcs.h ListTree.h ListTreeP.h
+
+XRAW_HEADERS = \
+ 3d.h AllWidgets.h Arrow.h ArrowP.h AsciiSink.h AsciiSinkP.h \
+ AsciiSrc.h AsciiSrcP.h AsciiText.h AsciiTextP.h Box.h BoxP.h \
+ Cardinals.h Clock.h ClockP.h Command.h CommandP.h Container.h \
+ ContainerP.h Dialog.h DialogP.h Form.h FormP.h Frame.h FrameP.h \
+ Grip.h GripP.h Label.h LabelP.h List.h ListP.h Logo.h LogoP.h \
+ Mailbox.h MailboxP.h MenuButtoP.h MenuButton.h Object.h Paned.h \
+ PanedP.h Panner.h PannerP.h Porthole.h PortholeP.h Repeater.h \
+ RepeaterP.h Reports.h Scrollbar.h ScrollbarP.h ScrolledTable.h \
+ ScrolledTableP.h Separator.h SeparatorP.h Simple.h SimpleMenP.h \
+ SimpleMenu.h SimpleP.h Sme.h SmeBSB.h SmeBSBP.h SmeLine.h SmeLineP.h \
+ SmeP.h StripCharP.h StripChart.h Table.h Table3d.h TableP.h \
+ TableUtil.h Template.h TemplateP.h Text.h TextP.h TextSink.h \
+ TextSinkP.h TextSrc.h TextSrcP.h Toggle.h ToggleP.h Tree.h TreeP.h \
+ Viewport.h ViewportP.h XawAll.h XawInit.h Xosdefs.h XrawInit.h \
+ color.h xraw_table.h
+
+SRCS = \
+ Arrow.c Board.c Button.c Common.c DrawIString.c DrawString.c \
+ DrawingArea.c Frame.c Group.c Gterm.c HTML-PSformat.c HTML.c \
+ HTMLformat.c HTMLimages.c HTMLjot.c HTMLlists.c HTMLparse.c \
+ HTMLwidgets.c Icon.c Label.c Layout.c MenuBar.c MultiList.c \
+ RadioGrp.c RowCol.c Scrollbar.c Slider2.c Tablist2Tabs.c TextWidth.c \
+ Toggle.c cvtLong.c iconutil.c laygram.c laylex.c scroll.c strnchr.c \
+ Tabs.c Gcs.c ListTree.c Separator.c Table.c Table3d.c TableUtil.c \
+ Container.c color.c
+
+OBJS = \
+ Arrow.o Board.o Button.o Common.o DrawIString.o DrawString.o \
+ DrawingArea.o Frame.o Group.o Gterm.o HTML-PSformat.o HTML.o \
+ HTMLformat.o HTMLimages.o HTMLjot.o HTMLlists.o HTMLparse.o \
+ HTMLwidgets.o Icon.o Label.o Layout.o MenuBar.o MultiList.o \
+ RadioGrp.o RowCol.o Scrollbar.o Slider2.o Tablist2Tabs.o TextWidth.o \
+ Toggle.o cvtLong.o iconutil.o laygram.o laylex.o scroll.o strnchr.o \
+ Tabs.o Gcs.o ListTree.o Separator.o Table.o Table3d.o TableUtil.o \
+ Container.o color.o
+
+#ifdef LexCmd
+LEX=LexCmd
+#endif
+#ifdef YaccCmd
+YACC=YaccCmd
+#endif
+
+
+depend:: laygram.c laylex.c
+all:: laygram.c laylex.c
+
+SubdirLibraryRule($(OBJS))
+NormalLintTarget($(SRCS))
+LintLibraryTarget(ar,$(SRCS))
+
+# Turn off compiler warnings for the HTML and FWF widgets.
+ FWFCFLAGS = $(CFLAGS) -c -w
+
+HTML.o: HTML.c
+ $(CC) $(FWFCFLAGS) HTML.c
+HTML-PSformat.o: HTML-PSformat.c
+ $(CC) $(FWFCFLAGS) HTML-PSformat.c
+HTMLformat.o: HTMLformat.c
+ $(CC) $(FWFCFLAGS) HTMLformat.c
+HTMLimages.o: HTMLimages.c
+ $(CC) $(FWFCFLAGS) HTMLimages.c
+HTMLjot.o: HTMLjot.c
+ $(CC) $(FWFCFLAGS) HTMLjot.c
+HTMLlists.o: HTMLlists.c
+ $(CC) $(FWFCFLAGS) HTMLlists.c
+HTMLparse.o: HTMLparse.c
+ $(CC) $(FWFCFLAGS) HTMLparse.c
+HTMLwidgets.o: HTMLwidgets.c
+ $(CC) $(FWFCFLAGS) HTMLwidgets.c
+
+
+Arrow.o:
+ $(CC) $(FWFCFLAGS) Arrow.c
+Board.o:
+ $(CC) $(FWFCFLAGS) Board.c
+Button.o:
+ $(CC) $(FWFCFLAGS) Button.c
+Common.o:
+ $(CC) $(FWFCFLAGS) Common.c
+DrawIString.o:
+ $(CC) $(FWFCFLAGS) DrawIString.c
+DrawString.o:
+ $(CC) $(FWFCFLAGS) DrawString.c
+Frame.o:
+ $(CC) $(FWFCFLAGS) Frame.c
+Group.o:
+ $(CC) $(FWFCFLAGS) Group.c
+Icon.o:
+ $(CC) $(FWFCFLAGS) Icon.c
+Label.o:
+ $(CC) $(FWFCFLAGS) Label.c
+MenuBar.o:
+ $(CC) $(FWFCFLAGS) MenuBar.c
+MultiList.o:
+ $(CC) $(FWFCFLAGS) MultiList.c
+RadioGrp.o:
+ $(CC) $(FWFCFLAGS) RadioGrp.c
+RowCol.o:
+ $(CC) $(FWFCFLAGS) RowCol.c
+Scrollbar.o:
+ $(CC) $(FWFCFLAGS) Scrollbar.c
+Slider2.o:
+ $(CC) $(FWFCFLAGS) Slider2.c
+Tablist2Tabs.o:
+ $(CC) $(FWFCFLAGS) Tablist2Tabs.c
+TextWidth.o:
+ $(CC) $(FWFCFLAGS) TextWidth.c
+Toggle.o:
+ $(CC) $(FWFCFLAGS) Toggle.c
+cvtLong.o:
+ $(CC) $(FWFCFLAGS) cvtLong.c
+iconutil.o:
+ $(CC) $(FWFCFLAGS) iconutil.c
+laylex.o:
+ $(CC) $(FWFCFLAGS) laylex.c
+
+laygram.c laygram.h : laygram.y
+ yacc -d laygram.y
+ sed 's/yy/LayYY/g' y.tab.c > laygram.c
+ sed 's/yy/LayYY/g' y.tab.h > laygram.h
+ rm y.tab.c y.tab.h
+
+# Hack to compile under systems which don't have strict ANSI compilers.
+#if defined (SunArchitecture) && HasSunC && OSMajorVersion >= 5
+#if !defined (i386Architecture)
+Tabs.o:
+ $(CC) -Xc $(EXTRA_INCLUDES) -c Tabs.c
+ListTree.o:
+ $(CC) -Xc $(EXTRA_INCLUDES) -c ListTree.c
+#endif
+#else
+#if defined (SunArchitecture) && OSMajorVersion == 4
+Tabs.o:
+ acc -w $(EXTRA_INCLUDES) -DSUNOS -c Tabs.c
+Gcs.o:
+ acc -w $(EXTRA_INCLUDES) -c Gcs.c
+ListTree.o:
+ acc -w $(EXTRA_INCLUDES) -c ListTree.c
+#else
+#if defined (HPArchitecture)
+Tabs.o:
+ c89 -w $(CFLAGS) $(EXTRA_INCLUDES) -c Tabs.c
+Gcs.o:
+ c89 -w $(CFLAGS) $(EXTRA_INCLUDES) -c Gcs.c
+ListTree.o:
+ c89 -w $(CFLAGS) $(EXTRA_INCLUDES) -c ListTree.c
+#else
+#if defined (AlphaArchitecture) && OSMajorVersion >= 4
+Tabs.o:
+ $(CC) -std $(CFLAGS) $(EXTRA_INCLUDES) -c Tabs.c
+ListTree.o:
+ $(CC) -std $(CFLAGS) $(EXTRA_INCLUDES) -c ListTree.c
+#endif
+#endif
+#endif
+#endif
+
+
+# Hack to compile under SunPRO V4 on Solaris
+#if defined (SunArchitecture) && HasSunC && OSMajorVersion >= 5
+laygram.o:
+ $(CC) $(EXTRA_INCLUDES) -c laygram.c
+#endif
+
+clean::
+ -rm -f laygram.c laygram.h
+
+laylex.c: laylex.l
+ $(LEX) laylex.l
+ sed 's/yy/LayYY/g' lex.yy.c > laylex.c
+ rm lex.yy.c
+
+clean::
+ -rm -f laylex.c
+
+includes:: laygram.h
+ MakeDir(X11irafIncDir/ObmW)
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/ObmW/$$i; \
+ $(CP) -p $$i X11irafIncDir/ObmW/$$i; \
+ done)
+ MakeDir(X11irafIncDir/X11/Xraw)
+ @(set -x; for i in $(XRAW_HEADERS); do \
+ $(RM) X11irafIncDir/X11/Xraw/$$i; \
+ $(CP) -p Xraw/$$i X11irafIncDir/X11/Xraw/$$i; \
+ done)
+
+#if InstallIncludes
+install::
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/ObmW/$$i; \
+ done)
+ for i in $(HEADERS); do \
+ (set -x; $(CP) -p $$i X11irafIncDir/ObmW); \
+ done
+#endif
+
+DependTarget()
diff --git a/vendor/x11iraf/obm/ObmW/Label.c b/vendor/x11iraf/obm/ObmW/Label.c
new file mode 100644
index 00000000..116ee13e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Label.c
@@ -0,0 +1,345 @@
+/* Generated by wbuild from "Label.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "stip4.bm"
+#include <stdio.h>
+#include "TabString.h"
+#include "LabelP.h"
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void set_label(
+#if NeedFunctionPrototypes
+Widget,String
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void make_gc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void make_graygc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void count_lines(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void make_gc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.gc != NULL) XtReleaseGC(self, ((XfwfLabelWidget)self)->xfwfLabel.gc);
+ values.background = ((XfwfLabelWidget)self)->core.background_pixel;
+ values.foreground = ((XfwfLabelWidget)self)->xfwfLabel.foreground;
+ values.font = ((XfwfLabelWidget)self)->xfwfLabel.font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ ((XfwfLabelWidget)self)->xfwfLabel.gc = XtGetGC(self, mask, &values);
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.rv_gc != NULL) XtReleaseGC(self, ((XfwfLabelWidget)self)->xfwfLabel.rv_gc);
+ values.foreground = ((XfwfLabelWidget)self)->core.background_pixel;
+ values.background = ((XfwfLabelWidget)self)->xfwfLabel.foreground;
+ values.font = ((XfwfLabelWidget)self)->xfwfLabel.font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ ((XfwfLabelWidget)self)->xfwfLabel.rv_gc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void make_graygc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.graygc != NULL) XtReleaseGC(self, ((XfwfLabelWidget)self)->xfwfLabel.graygc);
+ values.foreground = ((XfwfLabelWidget)self)->core.background_pixel;
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ values.fill_style = FillStippled;
+ mask = GCForeground | GCStipple | GCFillStyle;
+ ((XfwfLabelWidget)self)->xfwfLabel.graygc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void count_lines(self)Widget self;
+{
+ String p, s;
+ int w;
+
+ ((XfwfLabelWidget)self)->xfwfLabel.nlines = 0;
+ ((XfwfLabelWidget)self)->xfwfLabel.label_width = 0;
+ if (((XfwfLabelWidget)self)->xfwfLabel.label) {
+ for (p = ((XfwfLabelWidget)self)->xfwfLabel.label, ((XfwfLabelWidget)self)->xfwfLabel.nlines = 1, s = ((XfwfLabelWidget)self)->xfwfLabel.label; *s; s++) {
+ if (*s == '\n') {
+ ((XfwfLabelWidget)self)->xfwfLabel.nlines++;
+ w = XfwfTextWidth(((XfwfLabelWidget)self)->xfwfLabel.font, p, s - p, ((XfwfLabelWidget)self)->xfwfLabel.tabs);
+ p = s + 1;
+ if (w > ((XfwfLabelWidget)self)->xfwfLabel.label_width) ((XfwfLabelWidget)self)->xfwfLabel.label_width = w;
+ }
+ }
+ w = XfwfTextWidth(((XfwfLabelWidget)self)->xfwfLabel.font, p, s - p, ((XfwfLabelWidget)self)->xfwfLabel.tabs);
+ if (w > ((XfwfLabelWidget)self)->xfwfLabel.label_width) ((XfwfLabelWidget)self)->xfwfLabel.label_width = w;
+ }
+ ((XfwfLabelWidget)self)->xfwfLabel.label_height = ((XfwfLabelWidget)self)->xfwfLabel.nlines * (((XfwfLabelWidget)self)->xfwfLabel.font->ascent + ((XfwfLabelWidget)self)->xfwfLabel.font->descent);
+ ((XfwfLabelWidget)self)->xfwfLabel.label_width += ((XfwfLabelWidget)self)->xfwfLabel.leftMargin + ((XfwfLabelWidget)self)->xfwfLabel.rightMargin;
+ ((XfwfLabelWidget)self)->xfwfLabel.label_height += ((XfwfLabelWidget)self)->xfwfLabel.topMargin + ((XfwfLabelWidget)self)->xfwfLabel.bottomMargin;
+}
+
+static XtResource resources[] = {
+{XtNlabel,XtCLabel,XtRString,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.label),XtOffsetOf(XfwfLabelRec,xfwfLabel.label),XtRImmediate,(XtPointer)NULL },
+{XtNtablist,XtCTablist,XtRString,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.tablist),XtOffsetOf(XfwfLabelRec,xfwfLabel.tablist),XtRImmediate,(XtPointer)NULL },
+{XtNfont,XtCFont,XtRFontStruct,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.font),XtOffsetOf(XfwfLabelRec,xfwfLabel.font),XtRString,(XtPointer)XtDefaultFont },
+{XtNforeground,XtCForeground,XtRPixel,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.foreground),XtOffsetOf(XfwfLabelRec,xfwfLabel.foreground),XtRString,(XtPointer)XtDefaultForeground },
+{XtNalignment,XtCAlignment,XtRAlignment,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.alignment),XtOffsetOf(XfwfLabelRec,xfwfLabel.alignment),XtRImmediate,(XtPointer)0 },
+{XtNtopMargin,XtCTopMargin,XtRDimension,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.topMargin),XtOffsetOf(XfwfLabelRec,xfwfLabel.topMargin),XtRImmediate,(XtPointer)2 },
+{XtNbottomMargin,XtCBottomMargin,XtRDimension,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.bottomMargin),XtOffsetOf(XfwfLabelRec,xfwfLabel.bottomMargin),XtRImmediate,(XtPointer)2 },
+{XtNleftMargin,XtCLeftMargin,XtRDimension,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.leftMargin),XtOffsetOf(XfwfLabelRec,xfwfLabel.leftMargin),XtRImmediate,(XtPointer)2 },
+{XtNrightMargin,XtCRightMargin,XtRDimension,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.rightMargin),XtOffsetOf(XfwfLabelRec,xfwfLabel.rightMargin),XtRImmediate,(XtPointer)2 },
+{XtNshrinkToFit,XtCShrinkToFit,XtRBoolean,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.shrinkToFit),XtOffsetOf(XfwfLabelRec,xfwfLabel.shrinkToFit),XtRImmediate,(XtPointer)False },
+{XtNrvStart,XtCRvStart,XtRInt,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.rvStart),XtOffsetOf(XfwfLabelRec,xfwfLabel.rvStart),XtRImmediate,(XtPointer)0 },
+{XtNrvLength,XtCRvLength,XtRInt,sizeof(((XfwfLabelRec*)NULL)->xfwfLabel.rvLength),XtOffsetOf(XfwfLabelRec,xfwfLabel.rvLength),XtRImmediate,(XtPointer)0 },
+{XtNtraversalOn,XtCTraversalOn,XtRBoolean,sizeof(((XfwfLabelRec*)NULL)->xfwfCommon.traversalOn),XtOffsetOf(XfwfLabelRec,xfwfCommon.traversalOn),XtRImmediate,(XtPointer)False },
+};
+
+XfwfLabelClassRec xfwfLabelClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfBoardClassRec,
+"TextBox",
+sizeof(XfwfLabelRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+NULL,
+0,
+resources,
+13,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfLabel_class part */
+set_label,
+},
+};
+WidgetClass xfwfLabelWidgetClass = (WidgetClass) &xfwfLabelClassRec;
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfLabelWidgetClass c = (XfwfLabelWidgetClass) class;
+ XfwfLabelWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfLabelWidgetClass) return;
+ super = (XfwfLabelWidgetClass)class->core_class.superclass;
+ if (c->xfwfLabel_class.set_label == XtInherit_set_label)
+ c->xfwfLabel_class.set_label = super->xfwfLabel_class.set_label;
+}
+/*ARGSUSED*/static void set_label(self,newlabel)Widget self;String newlabel;
+{
+ Position x, y;
+ Dimension w, h;
+
+ XtFree(((XfwfLabelWidget)self)->xfwfLabel.label);
+ ((XfwfLabelWidget)self)->xfwfLabel.label = XtNewString(newlabel);
+ count_lines(self);
+ if (XtIsRealized(self)) {
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ XClearArea(XtDisplay(self), XtWindow(self), x, y, w, h, True);
+ /* $expose($, NULL, NULL); */
+ }
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redisplay = False, need_count = False;
+ Position x, y;
+ Dimension w, h, wd, ht;
+
+ if (((XfwfLabelWidget)self)->core.background_pixel != ((XfwfLabelWidget)old)->core.background_pixel)
+ make_graygc(self);
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.tablist != ((XfwfLabelWidget)old)->xfwfLabel.tablist) {
+ XtFree((String) ((XfwfLabelWidget)old)->xfwfLabel.tabs);
+ ((XfwfLabelWidget)self)->xfwfLabel.tabs = XfwfTablist2Tabs(((XfwfLabelWidget)self)->xfwfLabel.tablist);
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) need_count = True;
+ }
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.font != ((XfwfLabelWidget)old)->xfwfLabel.font) {
+ make_gc(self);
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) need_count = True;
+ }
+ if (((XfwfLabelWidget)self)->xfwfLabel.foreground != ((XfwfLabelWidget)old)->xfwfLabel.foreground
+ || ((XfwfLabelWidget)self)->core.background_pixel != ((XfwfLabelWidget)old)->core.background_pixel) {
+ make_gc(self);
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) need_redisplay = True;
+ }
+ if (((XfwfLabelWidget)self)->xfwfLabel.topMargin != ((XfwfLabelWidget)old)->xfwfLabel.topMargin
+ || ((XfwfLabelWidget)self)->xfwfLabel.bottomMargin != ((XfwfLabelWidget)old)->xfwfLabel.bottomMargin
+ || ((XfwfLabelWidget)self)->xfwfLabel.leftMargin != ((XfwfLabelWidget)old)->xfwfLabel.leftMargin
+ || ((XfwfLabelWidget)self)->xfwfLabel.rightMargin != ((XfwfLabelWidget)old)->xfwfLabel.rightMargin)
+ need_count = True;
+
+ if (((XfwfLabelWidget)self)->core.sensitive != ((XfwfLabelWidget)old)->core.sensitive)
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) need_redisplay = True;
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.rvStart != ((XfwfLabelWidget)old)->xfwfLabel.rvStart || ((XfwfLabelWidget)self)->xfwfLabel.rvLength != ((XfwfLabelWidget)old)->xfwfLabel.rvLength)
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) need_redisplay = True;
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != ((XfwfLabelWidget)old)->xfwfLabel.label) {
+ XtFree(((XfwfLabelWidget)old)->xfwfLabel.label);
+ ((XfwfLabelWidget)self)->xfwfLabel.label = XtNewString(((XfwfLabelWidget)self)->xfwfLabel.label);
+ need_count = True;
+ }
+ if (need_count) {
+ count_lines(self);
+ need_redisplay = True;
+ }
+ if (need_count && ((XfwfLabelWidget)self)->xfwfLabel.shrinkToFit) {
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ wd = ((XfwfLabelWidget)self)->xfwfLabel.label_width + ((XfwfLabelWidget)self)->core.width - w;
+ ht = ((XfwfLabelWidget)self)->xfwfLabel.label_height + ((XfwfLabelWidget)self)->core.height - h;
+ if (wd != ((XfwfLabelWidget)self)->core.width || ht != ((XfwfLabelWidget)self)->core.height) {
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfBoard_class.set_abs_location(self, CWWidth | CWHeight, 0, 0, wd, ht);
+ need_redisplay = False;
+ }
+ }
+ return need_redisplay;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ char *s;
+ Position x, y;
+ Dimension w, h, wd, ht;
+
+ if (((XfwfLabelWidget)self)->xfwfLabel.label) ((XfwfLabelWidget)self)->xfwfLabel.label = XtNewString(((XfwfLabelWidget)self)->xfwfLabel.label);
+ count_lines(self);
+ ((XfwfLabelWidget)self)->xfwfLabel.gc = NULL;
+ ((XfwfLabelWidget)self)->xfwfLabel.rv_gc = NULL;
+ ((XfwfLabelWidget)self)->xfwfLabel.graygc = NULL;
+ make_gc(self);
+ make_graygc(self);
+ ((XfwfLabelWidget)self)->xfwfLabel.tabs = XfwfTablist2Tabs(((XfwfLabelWidget)self)->xfwfLabel.tablist);
+ if (((XfwfLabelWidget)self)->xfwfLabel.shrinkToFit) {
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ wd = ((XfwfLabelWidget)self)->xfwfLabel.label_width + ((XfwfLabelWidget)self)->core.width - w;
+ ht = ((XfwfLabelWidget)self)->xfwfLabel.label_height + ((XfwfLabelWidget)self)->core.height - h;
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfBoard_class.set_abs_location(self, CWWidth | CWHeight, 0, 0, wd, ht);
+ }
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Region reg;
+ XRectangle rect;
+ int baseline;
+ int w1, w2, w3;
+ char *s, *t;
+ int x, y, i, j, rstart, rend;
+
+ if (! XtIsRealized(self)) return;
+ xfwfBoardClassRec.core_class.expose(self, event, region);
+ if (((XfwfLabelWidget)self)->xfwfLabel.label != NULL) {
+ baseline = ((XfwfLabelWidget)self)->xfwfLabel.font->ascent + ((XfwfLabelWidget)self)->xfwfLabel.font->descent;
+ ((XfwfLabelWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &rect.x, &rect.y, &rect.width, &rect.height);
+ rect.x += ((XfwfLabelWidget)self)->xfwfLabel.leftMargin; rect.width -= ((XfwfLabelWidget)self)->xfwfLabel.leftMargin + ((XfwfLabelWidget)self)->xfwfLabel.rightMargin;
+ rect.y += ((XfwfLabelWidget)self)->xfwfLabel.topMargin; rect.height -= ((XfwfLabelWidget)self)->xfwfLabel.topMargin + ((XfwfLabelWidget)self)->xfwfLabel.bottomMargin;
+ reg = XCreateRegion();
+ XUnionRectWithRegion(&rect, reg, reg);
+ if (region != NULL) XIntersectRegion(region, reg, reg);
+ XSetRegion(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.gc, reg);
+ XSetRegion(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.rv_gc, reg);
+ if (((XfwfLabelWidget)self)->xfwfLabel.alignment & XfwfTop)
+ y = rect.y + ((XfwfLabelWidget)self)->xfwfLabel.font->ascent;
+ else if (((XfwfLabelWidget)self)->xfwfLabel.alignment & XfwfBottom)
+ y = rect.y + rect.height - ((XfwfLabelWidget)self)->xfwfLabel.nlines * baseline + ((XfwfLabelWidget)self)->xfwfLabel.font->ascent;
+ else
+ y = rect.y + (rect.height - ((XfwfLabelWidget)self)->xfwfLabel.nlines * baseline)/2 + ((XfwfLabelWidget)self)->xfwfLabel.font->ascent;
+ for (i = 0, j = 0; ((XfwfLabelWidget)self)->xfwfLabel.label[i]; i++) {
+ if (((XfwfLabelWidget)self)->xfwfLabel.label[i] == '\n') {
+ draw_line(XtDisplay(self), XtWindow(self), j, i);
+ j = i + 1;
+ y += baseline;
+ }
+ }
+ draw_line(XtDisplay(self), XtWindow(self), j, i);
+
+ /* Gray out if not sensitive */
+ if (! ((XfwfLabelWidget)self)->core.sensitive) {
+ XSetRegion(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.graygc, reg);
+ XFillRectangle(XtDisplay(self), XtWindow(self), ((XfwfLabelWidget)self)->xfwfLabel.graygc, rect.x,
+ rect.y, rect.width, rect.height);
+ XSetClipMask(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.graygc, None);
+ }
+ XSetClipMask(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.gc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfLabelWidget)self)->xfwfLabel.rv_gc, None);
+
+ XDestroyRegion (reg); /* MF038 */
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Label.h b/vendor/x11iraf/obm/ObmW/Label.h
new file mode 100644
index 00000000..b23fc0a1
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Label.h
@@ -0,0 +1,130 @@
+/* Generated by wbuild from "Label.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfLabel_H_
+#define _XfwfLabel_H_
+#include "Board.h"
+#ifndef XtNlabel
+#define XtNlabel "label"
+#endif
+#ifndef XtCLabel
+#define XtCLabel "Label"
+#endif
+#ifndef XtRString
+#define XtRString "String"
+#endif
+
+#ifndef XtNtablist
+#define XtNtablist "tablist"
+#endif
+#ifndef XtCTablist
+#define XtCTablist "Tablist"
+#endif
+#ifndef XtRString
+#define XtRString "String"
+#endif
+
+#ifndef XtNfont
+#define XtNfont "font"
+#endif
+#ifndef XtCFont
+#define XtCFont "Font"
+#endif
+#ifndef XtRFontStruct
+#define XtRFontStruct "FontStruct"
+#endif
+
+#ifndef XtNforeground
+#define XtNforeground "foreground"
+#endif
+#ifndef XtCForeground
+#define XtCForeground "Foreground"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNalignment
+#define XtNalignment "alignment"
+#endif
+#ifndef XtCAlignment
+#define XtCAlignment "Alignment"
+#endif
+#ifndef XtRAlignment
+#define XtRAlignment "Alignment"
+#endif
+
+#ifndef XtNtopMargin
+#define XtNtopMargin "topMargin"
+#endif
+#ifndef XtCTopMargin
+#define XtCTopMargin "TopMargin"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNbottomMargin
+#define XtNbottomMargin "bottomMargin"
+#endif
+#ifndef XtCBottomMargin
+#define XtCBottomMargin "BottomMargin"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNleftMargin
+#define XtNleftMargin "leftMargin"
+#endif
+#ifndef XtCLeftMargin
+#define XtCLeftMargin "LeftMargin"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNrightMargin
+#define XtNrightMargin "rightMargin"
+#endif
+#ifndef XtCRightMargin
+#define XtCRightMargin "RightMargin"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNshrinkToFit
+#define XtNshrinkToFit "shrinkToFit"
+#endif
+#ifndef XtCShrinkToFit
+#define XtCShrinkToFit "ShrinkToFit"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+#ifndef XtNrvStart
+#define XtNrvStart "rvStart"
+#endif
+#ifndef XtCRvStart
+#define XtCRvStart "RvStart"
+#endif
+#ifndef XtRInt
+#define XtRInt "Int"
+#endif
+
+#ifndef XtNrvLength
+#define XtNrvLength "rvLength"
+#endif
+#ifndef XtCRvLength
+#define XtCRvLength "RvLength"
+#endif
+#ifndef XtRInt
+#define XtRInt "Int"
+#endif
+
+typedef struct _XfwfLabelClassRec *XfwfLabelWidgetClass;
+typedef struct _XfwfLabelRec *XfwfLabelWidget;
+externalref WidgetClass xfwfLabelWidgetClass;
+#endif /*_XfwfLabel_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Label.man b/vendor/x11iraf/obm/ObmW/Label.man
new file mode 100644
index 00000000..bd1e223c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Label.man
@@ -0,0 +1,732 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfLabel
+.SH DESCRIPTION
+The Label class has the capability to display one or more lines of
+text in a single font. Otherwise it is the same as the Board class.
+The text can be left, right or center justified and it can be centered
+vertically or put against the top or the bottom of the widget. There
+is also a resource to set tab stops.
+
+The text is `grayed out' when the widget becomes insensitive
+(resource: \fIsensitive\fP), even though a Label widget has no actions of
+its own.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfLabel
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNtablist XtCTablist String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNalignment XtCAlignment Alignment 0
+XtNtopMargin XtCTopMargin Dimension 2
+XtNbottomMargin XtCBottomMargin Dimension 2
+XtNleftMargin XtCLeftMargin Dimension 2
+XtNrightMargin XtCRightMargin Dimension 2
+XtNshrinkToFit XtCShrinkToFit Boolean False
+XtNrvStart XtCRvStart Int 0
+XtNrvLength XtCRvLength Int 0
+
+.TE
+.ps
+
+.TP
+.I "XtNlabel"
+The text is a single string, which may contain embedded newlines.
+There is no provision for changing fonts in the middle of a text.
+
+
+
+.hi
+
+.nf
+String label = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNtablist"
+A tablist can be provided for tabbing to particular columns
+within the label.
+
+
+
+.hi
+
+.nf
+String tablist = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNfont"
+The text is drawn in the font which is give as the \fIfont\fP resource.
+
+
+
+.hi
+
+.nf
+<FontStruct> XFontStruct * font = <String>XtDefaultFont
+.fi
+
+.eh
+
+.TP
+.I "XtNforeground"
+The foreground color is the color used to draw the text.
+
+
+
+.hi
+
+.nf
+Pixel foreground = <String>XtDefaultForeground
+.fi
+
+.eh
+
+.TP
+.I "XtNalignment"
+The text can be aligned in the widget in nine ways: left, right or
+center, combined with top, center or bottom. Symbolic constants
+\fIXfwfTop\fP, \fIXfwfBottom\fP, \fIXfwfLeft\fP and \fIXfwfRight\fP can be added together to
+get the desired alignment. The alignment is actually a four-bit
+number made up of two parts of 2 bits added together: 1 is left, 2 is
+right, 0 is center, 4 is top, 8 is bottom, 0 is vertical center. Thus
+5 (= 1 + 4) means top left and 2 (= 2 + 0) means center right. For
+easier specification, there is also a converter from strings, that
+accepts string like `top left' or `center right'.
+
+
+
+.hi
+
+.nf
+Alignment alignment = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNtopMargin"
+The \fItopmargin\fP is only used when the text is not centered. It gives
+the number of pixels between the frame and the top of the text.
+
+
+
+.hi
+
+.nf
+Dimension topMargin = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNbottomMargin"
+The \fIbottomMargin\fP is only used to compute the preferred size of the
+button in case \fIshrinkToFit = True\fP.
+
+
+
+.hi
+
+.nf
+Dimension bottomMargin = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNleftMargin"
+The \fIleftMargin\fP is only used when the text is not centered. It
+gives the number of pixels between the frame and the left edge of the
+text, and if possible also between the frame and the right edge of the
+text.
+
+
+
+.hi
+
+.nf
+Dimension leftMargin = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNrightMargin"
+The \fIrightMargin\fP is only used to compute the preferred size of the
+button in case \fIshrinkToFit = True\fP.
+
+
+
+.hi
+
+.nf
+Dimension rightMargin = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNshrinkToFit"
+Buttons will normally not occupy the full area of their parents.
+Most likely they will be a fixed size or a size depending on the
+label. By setting the \fIshrinkToFit\fP resource to True, the width and
+height are recomputed with every new label.
+
+
+
+.hi
+
+.nf
+Boolean shrinkToFit = False
+.fi
+
+.eh
+
+.TP
+.I "XtNrvStart"
+It is possible to set a part of the label apart by drawing it in
+reverse. The \fIrvStart\fP resource gives the index of the first
+character to draw in reverse video.
+
+
+
+.hi
+
+.nf
+int rvStart = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNrvLength"
+The \fIrvLength\fP resource contains the number of characters to
+draw in reverse video.
+
+
+
+.hi
+
+.nf
+int rvLength = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNtraversalOn"
+A label normally needs no keyboard interface, therefore traversal is
+turned off.
+
+
+
+.hi
+
+.nf
+ traversalOn = False
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ "stip4.bm"
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <Xfwf/TabString.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+For faster drawing, the number of lines in the text is stored in a
+private variable by the \fIset_values\fP and \fIinitialize\fP methods.
+
+
+
+.nf
+int nlines
+.fi
+
+The tablist is converted from string format to a list of int's for speed.
+
+
+
+.nf
+int * tabs
+.fi
+
+For drawing the text, this GC is used.
+
+
+
+.nf
+GC gc
+.fi
+
+This GC is for the text that is drawn in reverse video.
+
+
+
+.nf
+GC rv_gc
+.fi
+
+For graying out the text, another GC is used.
+
+
+
+.nf
+GC graygc
+.fi
+
+When the \fIshrinkToFit\fP resource is set, we need the minimum area
+necessary for the complete label to be visible. \fIlabel_width\fP and
+\fIlabel_height\fP include the size of \fImargin\fP.
+
+
+
+.nf
+Dimension label_width
+.fi
+
+.nf
+Dimension label_height
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The new method \fIset_label\fP makes a copy of the string that is passed
+in, counts the number of lines and also draws the new label. This
+could have been done in \fIset_values\fP, but it is expected that
+subclasses will redraw the label frequently, so a more efficient way
+is provided.
+
+Note that this method does not resize the widget in case \fIshrinkToFit\fP
+is set.
+
+.nf
+set_label($, String newlabel)
+{
+ Position x, y;
+ Dimension w, h;
+
+ XtFree($label);
+ $label = XtNewString(newlabel);
+ count_lines($);
+ if (XtIsRealized($)) {
+ $compute_inside($, x, y, w, h);
+ XClearArea(XtDisplay($), XtWindow($), x, y, w, h, True);
+ /* $expose($, NULL, NULL); */
+ }
+}
+.fi
+
+The \fIset_values\fP method checks the \fIbackground\fP resource, because is
+is used in the GC \fIgraygc\fP. When the text or the font change, the
+private variables \fInlines\fP, \fIlabel_height\fP and \fIlabel_width\fP are
+updated.
+
+\fIneed_count\fP is set to \fITrue\fP if the size of the label changes.
+\fIneed_count\fP implies \fIneed_redisplay\fP.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redisplay = False, need_count = False;
+ Position x, y;
+ Dimension w, h, wd, ht;
+
+ if ($background_pixel != $old$background_pixel)
+ make_graygc($);
+
+ if ($tablist != $old$tablist) {
+ XtFree((String) $old$tabs);
+ $tabs = XfwfTablist2Tabs($tablist);
+ if ($label != NULL) need_count = True;
+ }
+
+ if ($font != $old$font) {
+ make_gc($);
+ if ($label != NULL) need_count = True;
+ }
+ if ($foreground != $old$foreground
+ || $background_pixel != $old$background_pixel) {
+ make_gc($);
+ if ($label != NULL) need_redisplay = True;
+ }
+ if ($topMargin != $old$topMargin
+ || $bottomMargin != $old$bottomMargin
+ || $leftMargin != $old$leftMargin
+ || $rightMargin != $old$rightMargin)
+ need_count = True;
+
+ if ($sensitive != $old$sensitive)
+ if ($label != NULL) need_redisplay = True;
+
+ if ($rvStart != $old$rvStart || $rvLength != $old$rvLength)
+ if ($label != NULL) need_redisplay = True;
+
+ if ($label != $old$label) {
+ XtFree($old$label);
+ $label = XtNewString($label);
+ need_count = True;
+ }
+ if (need_count) {
+ count_lines($);
+ need_redisplay = True;
+ }
+ if (need_count $shrinkToFit) {
+ $compute_inside($, x, y, w, h);
+ wd = $label_width + $width - w;
+ ht = $label_height + $height - h;
+ if (wd != $width || ht != $height) {
+ $set_abs_location($, CWWidth | CWHeight, 0, 0, wd, ht);
+ need_redisplay = False;
+ }
+ }
+ return need_redisplay;
+}
+.fi
+
+The \fIinitialize\fP methods creates the first GC's and initializes the
+private variables. It sets the GC's to \fINULL\fP and calls two utility
+routines to actually create them.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ char *s;
+ Position x, y;
+ Dimension w, h, wd, ht;
+
+ if ($label) $label = XtNewString($label);
+ count_lines($);
+ $gc = NULL;
+ $rv_gc = NULL;
+ $graygc = NULL;
+ make_gc($);
+ make_graygc($);
+ $tabs = XfwfTablist2Tabs($tablist);
+ if ($shrinkToFit) {
+ $compute_inside($, x, y, w, h);
+ wd = $label_width + $width - w;
+ ht = $label_height + $height - h;
+ $set_abs_location($, CWWidth | CWHeight, 0, 0, wd, ht);
+ }
+}
+.fi
+
+The \fIexpose\fP method is responsible for drawing the text. The text is
+put in the position given in \fIalignment\fP. The text is always kept
+within the frame. If necessary, the text is clipped. The routine ends
+by calling the \fIexpose\fP method from the superclass, which is
+responsible for drawing the frame.
+
+The part of the text that is to appear in reverse video is drawn with
+the \fIrv_gc\fP GC.
+
+\fBdef\fP draw_line(dpy, win, from, to) =
+do {
+ if ($rvStart >= to) rstart = to;
+ else rstart = max($rvStart, from);
+ if ($rvStart + $rvLength <= from) rend = rstart;
+ else rend = min($rvStart + $rvLength, to);
+ w1 = XfwfTextWidth($font, $label + from, rstart - from, $tabs);
+ w2 = XfwfTextWidth($font, $label + rstart, rend - rstart, $tabs);
+ w3 = XfwfTextWidth($font, $label + rend, to - rend, $tabs);
+ if ($alignment XfwfLeft)
+ x = rect.x;
+ else if ($alignment XfwfRight)
+ x = rect.x + rect.width - w1 - w2 - w3;
+ else
+ x = rect.x + (rect.width - w1 - w2 - w3)/2;
+ if (w1)
+ XfwfDrawImageString(dpy, win, $gc, x, y, $label + from,
+ rstart - from, $tabs);
+ if (w2)
+ XfwfDrawImageString(dpy, win, $rv_gc, x + w1, y, $label
+ + rstart, rend - rstart, $tabs);
+ if (w3)
+ XfwfDrawImageString(dpy, win, $gc, x + w1 + w2, y, $label +
+ rend, to - rend, $tabs);
+ }while (0 )
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Region reg;
+ XRectangle rect;
+ int baseline;
+ int w1, w2, w3;
+ char *s, *t;
+ int x, y, i, j, rstart, rend;
+
+ if (! XtIsRealized($)) return;
+ #expose($, event, region);
+ if ($label != NULL) {
+ baseline = $font->ascent + $font->descent;
+ $compute_inside($, rect.x, rect.y, rect.width, rect.height);
+ rect.x += $leftMargin; rect.width -= $leftMargin + $rightMargin;
+ rect.y += $topMargin; rect.height -= $topMargin + $bottomMargin;
+ reg = XCreateRegion();
+ XUnionRectWithRegion(rect, reg, reg);
+ if (region != NULL) XIntersectRegion(region, reg, reg);
+ XSetRegion(XtDisplay($), $gc, reg);
+ XSetRegion(XtDisplay($), $rv_gc, reg);
+ if ($alignment XfwfTop)
+ y = rect.y + $font->ascent;
+ else if ($alignment XfwfBottom)
+ y = rect.y + rect.height - $nlines * baseline + $font->ascent;
+ else
+ y = rect.y + (rect.height - $nlines * baseline)/2 + $font->ascent;
+ for (i = 0, j = 0; $label[i]; i++) {
+ if ($label[i] == '\\n') {
+ draw_line(XtDisplay($), XtWindow($), j, i);
+ j = i + 1;
+ y += baseline;
+ }
+ }
+ draw_line(XtDisplay($), XtWindow($), j, i);
+
+ /* Gray out if not sensitive */
+ if (! $sensitive) {
+ XSetRegion(XtDisplay($), $graygc, reg);
+ XFillRectangle(XtDisplay($), XtWindow($), $graygc, rect.x,
+ rect.y, rect.width, rect.height);
+ XSetClipMask(XtDisplay($), $graygc, None);
+ }
+ XSetClipMask(XtDisplay($), $gc, None);
+ XSetClipMask(XtDisplay($), $rv_gc, None);
+ }
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The \fImake_gc\fP routine creates the GC for the text.
+
+.nf
+make_gc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($gc != NULL) XtReleaseGC($, $gc);
+ values.background = $background_pixel;
+ values.foreground = $foreground;
+ values.font = $font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ $gc = XtGetGC($, mask, values);
+
+ if ($rv_gc != NULL) XtReleaseGC($, $rv_gc);
+ values.foreground = $background_pixel;
+ values.background = $foreground;
+ values.font = $font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ $rv_gc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fImake_graygc\fP routine creates a GC for graying out the text. It
+contains a stipple in the background color, that will be applied over
+the text.
+
+.nf
+make_graygc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($graygc != NULL) XtReleaseGC($, $graygc);
+ values.foreground = $background_pixel;
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ values.fill_style = FillStippled;
+ mask = GCForeground | GCStipple | GCFillStyle;
+ $graygc = XtGetGC($, mask, values);
+}
+.fi
+
+The funtion \fIcount_lines\fP computes the correct values for the
+private variables \fInlines\fP, \fIlabel_width\fP and \fIlabel_height\fP.
+
+.nf
+count_lines($)
+{
+ String p, s;
+ int w;
+
+ $nlines = 0;
+ $label_width = 0;
+ if ($label) {
+ for (p = $label, $nlines = 1, s = $label; *s; s++) {
+ if (*s == '\\n') {
+ $nlines++;
+ w = XfwfTextWidth($font, p, s - p, $tabs);
+ p = s + 1;
+ if (w > $label_width) $label_width = w;
+ }
+ }
+ w = XfwfTextWidth($font, p, s - p, $tabs);
+ if (w > $label_width) $label_width = w;
+ }
+ $label_height = $nlines * ($font->ascent + $font->descent);
+ $label_width += $leftMargin + $rightMargin;
+ $label_height += $topMargin + $bottomMargin;
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/LabelP.h b/vendor/x11iraf/obm/ObmW/LabelP.h
new file mode 100644
index 00000000..962b20ee
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/LabelP.h
@@ -0,0 +1,89 @@
+/* Generated by wbuild from "Label.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfLabelP_H_
+#define _XfwfLabelP_H_
+#include "BoardP.h"
+#include "Label.h"
+typedef void (*set_label_Proc)(
+#if NeedFunctionPrototypes
+Widget,String
+#endif
+);
+#define XtInherit_set_label ((set_label_Proc) _XtInherit)
+typedef struct {
+/* methods */
+set_label_Proc set_label;
+#define draw_line(dpy, win, from, to) do {\
+ if (((XfwfLabelWidget)self)->xfwfLabel.rvStart >= to) rstart = to;\
+ else rstart = max(((XfwfLabelWidget)self)->xfwfLabel.rvStart, from);\
+ if (((XfwfLabelWidget)self)->xfwfLabel.rvStart + ((XfwfLabelWidget)self)->xfwfLabel.rvLength <= from) rend = rstart;\
+ else rend = min(((XfwfLabelWidget)self)->xfwfLabel.rvStart + ((XfwfLabelWidget)self)->xfwfLabel.rvLength, to);\
+ w1 = XfwfTextWidth(((XfwfLabelWidget)self)->xfwfLabel.font, ((XfwfLabelWidget)self)->xfwfLabel.label + from, rstart - from, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ w2 = XfwfTextWidth(((XfwfLabelWidget)self)->xfwfLabel.font, ((XfwfLabelWidget)self)->xfwfLabel.label + rstart, rend - rstart, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ w3 = XfwfTextWidth(((XfwfLabelWidget)self)->xfwfLabel.font, ((XfwfLabelWidget)self)->xfwfLabel.label + rend, to - rend, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ if (((XfwfLabelWidget)self)->xfwfLabel.alignment & XfwfLeft)\
+ x = rect.x;\
+ else if (((XfwfLabelWidget)self)->xfwfLabel.alignment & XfwfRight)\
+ x = rect.x + rect.width - w1 - w2 - w3;\
+ else\
+ x = rect.x + (rect.width - w1 - w2 - w3)/2;\
+ if (w1)\
+ XfwfDrawImageString(dpy, win, ((XfwfLabelWidget)self)->xfwfLabel.gc, x, y, ((XfwfLabelWidget)self)->xfwfLabel.label + from,\
+ rstart - from, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ if (w2)\
+ XfwfDrawImageString(dpy, win, ((XfwfLabelWidget)self)->xfwfLabel.rv_gc, x + w1, y, ((XfwfLabelWidget)self)->xfwfLabel.label\
+ + rstart, rend - rstart, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ if (w3)\
+ XfwfDrawImageString(dpy, win, ((XfwfLabelWidget)self)->xfwfLabel.gc, x + w1 + w2, y, ((XfwfLabelWidget)self)->xfwfLabel.label +\
+ rend, to - rend, ((XfwfLabelWidget)self)->xfwfLabel.tabs);\
+ }while (0 )
+
+
+/* class variables */
+} XfwfLabelClassPart;
+typedef struct _XfwfLabelClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfLabelClassPart xfwfLabel_class;
+} XfwfLabelClassRec;
+
+typedef struct {
+/* resources */
+String label;
+String tablist;
+XFontStruct * font;
+Pixel foreground;
+Alignment alignment;
+Dimension topMargin;
+Dimension bottomMargin;
+Dimension leftMargin;
+Dimension rightMargin;
+Boolean shrinkToFit;
+int rvStart;
+int rvLength;
+/* private state */
+int nlines;
+int * tabs;
+GC gc;
+GC rv_gc;
+GC graygc;
+Dimension label_width;
+Dimension label_height;
+} XfwfLabelPart;
+
+typedef struct _XfwfLabelRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfLabelPart xfwfLabel;
+} XfwfLabelRec;
+
+externalref XfwfLabelClassRec xfwfLabelClassRec;
+
+#endif /* _XfwfLabelP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Layout.c b/vendor/x11iraf/obm/ObmW/Layout.c
new file mode 100644
index 00000000..e623320e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Layout.c
@@ -0,0 +1,965 @@
+/*
+ * $XConsortium: Layout.c,v 1.1 91/09/13 18:51:44 keith Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Misc.h>
+#include <X11/Xmu/Converters.h>
+
+#include "LayoutP.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+/*****************************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************************/
+
+#define offset(field) XtOffsetOf(LayoutRec, layout.field)
+
+static XtResource resources[] = {
+ {XtNlayout, XtCLayout, XtRLayout, sizeof (BoxPtr),
+ offset(layout), XtRLayout, NULL },
+ {XtNdebug, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(debug), XtRImmediate, (XtPointer) FALSE},
+};
+
+#undef offset
+
+static void ClassInitialize(), Initialize();
+static void Resize();
+static Boolean SetValues();
+static XtGeometryResult GeometryManager();
+static void ChangeManaged();
+static void InsertChild();
+static XtGeometryResult QueryGeometry ();
+static void GetDesiredSize ();
+
+static void LayoutLayout ();
+static void LayoutGetNaturalSize ();
+static void LayoutFreeLayout ();
+
+extern void LayYYsetsource(), LayYYsetdest();
+extern int LayYYparse();
+
+#define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
+
+LayoutClassRec layoutClassRec = {
+ {
+/* core class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class name */ "Layout",
+ /* size */ sizeof(LayoutRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part init */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ FALSE,
+ /* compress_exposure */ 0,
+ /* compress_enterleave*/ FALSE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+ /* expose */ NULL,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }, {
+/* composite class fields */
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ InsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ }, {
+/* constraint class fields */
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ sizeof(LayoutConstraintsRec),
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec;
+
+#define ForAllChildren(pw, childP) \
+ for ( (childP) = (pw)->composite.children ; \
+ (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
+ (childP)++ ) if (!XtIsManaged(*childP)) ; else
+
+/************************************************************
+ *
+ * Semi-public routines.
+ *
+ ************************************************************/
+
+/* Function Name: ClassInitialize
+ * Description: The Layout widgets class initialization proc.
+ * Arguments: none.
+ * Returns: none.
+ */
+
+/*ARGSUSED*/
+static Boolean
+CvtStringToLayout (dpy, args, num_args, from, to, converter_data)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *num_args;
+ XrmValue *from, *to;
+ XtPointer *converter_data;
+{
+ static BoxPtr tmp;
+ LayYYsetsource ((char *) from->addr);
+ if (!to->addr) to->addr = (XtPointer)&tmp;
+ LayYYsetdest ((BoxPtr *) to->addr);
+ to->size = sizeof (BoxPtr *);
+ if (LayYYparse () == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*ARGSUSED*/
+static void
+DisposeLayout (app, to, data, args, num_args)
+ XtAppContext app;
+ XrmValue *to;
+ XtPointer data;
+ XrmValuePtr args;
+ Cardinal *num_args;
+{
+ LayoutFreeLayout (* (LayoutPtr *) to->addr);
+}
+
+static void
+ClassInitialize()
+{
+ XtSetTypeConverter ( XtRString, XtRLayout, CvtStringToLayout,
+ (XtConvertArgList)NULL, (Cardinal)0, XtCacheNone,
+ DisposeLayout );
+}
+
+/*ARGSUSED*/
+static XtGeometryResult GeometryManager(child, request, reply)
+ Widget child;
+ XtWidgetGeometry *request, *reply;
+{
+ LayoutWidget w = (LayoutWidget) XtParent(child);
+ SubInfoPtr p = SubInfo(child);
+ int bw;
+ Bool changed, bwChanged;
+
+ bw = p->naturalBw;
+ changed = FALSE;
+ bwChanged = FALSE;
+ if (request->request_mode & CWBorderWidth &&
+ request->border_width != child->core.border_width)
+ {
+ p->naturalBw = bw;
+ bw = request->border_width;
+ changed = TRUE;
+ bwChanged = TRUE;
+ }
+ if (bwChanged || ((request->request_mode & CWWidth) &&
+ request->width != child->core.width))
+ {
+ p->naturalSize[LayoutHorizontal] = request->width + bw * 2;
+ changed = TRUE;
+ }
+ if (bwChanged || ((request->request_mode & CWHeight) &&
+ request->height != child->core.height))
+ {
+ p->naturalSize[LayoutVertical] = request->height + bw * 2;
+ changed = TRUE;
+ }
+ if (changed)
+ LayoutLayout (w, TRUE);
+ return XtGeometryDone;
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+Widget request, new;
+ArgList args;
+Cardinal *num_args;
+{
+/* LayoutWidget w = (LayoutWidget)new; */
+}
+
+static void ChangeManaged(gw)
+ Widget gw;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ Widget *children;
+
+ ForAllChildren (w, children)
+ GetDesiredSize (*children);
+ LayoutLayout ((LayoutWidget) w, TRUE);
+}
+
+static void
+GetDesiredSize (child)
+ Widget child;
+{
+ XtWidgetGeometry desired;
+ SubInfoPtr p;
+
+ XtQueryGeometry (child, (XtWidgetGeometry *) NULL, &desired);
+ p = SubInfo (child);
+ p->naturalBw = desired.border_width;
+ p->naturalSize[LayoutHorizontal] = desired.width + desired.border_width * 2;
+ p->naturalSize[LayoutVertical] = desired.height + desired.border_width * 2;
+}
+
+static void InsertChild (child)
+ Widget child;
+{
+ (*SuperClass->composite_class.insert_child) (child);
+ GetDesiredSize (child);
+}
+
+static void
+Resize(gw)
+ Widget gw;
+{
+ LayoutLayout ((LayoutWidget) gw, FALSE);
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues(gold, greq, gnew, args, num_args)
+ Widget gold, greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ LayoutWidget old = (LayoutWidget) gold,
+ new = (LayoutWidget) gnew;
+
+ if (old->layout.layout != new->layout.layout)
+ LayoutLayout (new, TRUE);
+ return FALSE;
+} /* SetValues */
+
+static XtGeometryResult
+QueryGeometry (gw, request, prefered_return)
+ Widget gw;
+ XtWidgetGeometry *request, *prefered_return;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ XtGeometryResult result;
+ XtWidgetGeometry prefered_size;
+
+ if (request && !(request->request_mode & (CWWidth|CWHeight)))
+ return XtGeometryYes;
+ LayoutGetNaturalSize (w, &prefered_size.width, &prefered_size.height);
+ prefered_return->request_mode = 0;
+ result = XtGeometryYes;
+ if (!request) {
+ prefered_return->width = prefered_size.width;
+ prefered_return->height= prefered_size.height;
+ if (prefered_size.width != w->core.width) {
+ prefered_return->request_mode |= CWWidth;
+ result = XtGeometryAlmost;
+ }
+ if (prefered_size.height != w->core.height) {
+ prefered_return->request_mode |= CWHeight;
+ result = XtGeometryAlmost;
+ }
+ } else {
+ if (request->request_mode & CWWidth) {
+ if (prefered_size.width > request->width)
+ {
+ if (prefered_size.width == w->core.width)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWWidth;
+ prefered_return->width = prefered_size.width;
+ }
+ }
+ }
+ if (request->request_mode & CWHeight) {
+ if (prefered_size.height > request->height)
+ {
+ if (prefered_size.height == w->core.height)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWHeight;
+ prefered_return->height = prefered_size.height;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * Layout section. Exports LayoutGetNaturalSize and
+ * LayoutLayout to above section
+ */
+
+static void
+PrintGlue (g)
+ GlueRec g;
+{
+ if (g.order == 0 || g.value != 1.0)
+ (void) printf ("%g", g.value);
+ if (g.order > 0)
+ {
+ (void) printf ("%s", " inf");
+ if (g.order > 1)
+ (void) printf (" %d", g.order);
+ }
+}
+
+static void
+PrintDirection (dir)
+ LayoutDirection dir;
+{
+ switch (dir) {
+ case LayoutHorizontal:
+ (void) printf ("%s", "horizontal");
+ break;
+ case LayoutVertical:
+ (void) printf ("%s", "vertical");
+ break;
+ default:
+ (void) printf ("Unknown layout direction %d\n", dir);
+ break;
+
+ }
+}
+
+static void
+TabTo(level)
+ int level;
+{
+ while (level--)
+ (void) printf ("%s", " ");
+}
+
+static void
+PrintBox (box, level)
+ BoxPtr box;
+ int level;
+{
+ BoxPtr child;
+
+ TabTo (level);
+ (void) printf ("%s", "< ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutHorizontal]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutHorizontal]);
+ (void) printf ("%s", " * ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutVertical]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutVertical]);
+ (void) printf ("%s", " >");
+ (void) printf (" size: %d x %d", box->size[0], box->size[1]);
+ (void) printf (" natural: %d x %d ", box->natural[0], box->natural[1]);
+ switch (box->type) {
+ case BoxBox:
+ PrintDirection (box->u.box.dir);
+ (void) printf ("%s\n", "");
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ PrintBox (child, level+1);
+ break;
+ case WidgetBox:
+ (void) printf (" %s\n", XrmQuarkToString (box->u.widget.quark));
+ break;
+ case GlueBox:
+ (void) printf ("%s\n", " glue");
+ break;
+ case VariableBox:
+ (void) printf (" variable %s\n", XrmQuarkToString (box->u.variable.quark));
+ break;
+ }
+}
+
+static ExprPtr
+LookupVariable (child, quark)
+ BoxPtr child;
+ XrmQuark quark;
+{
+ BoxPtr parent, box;
+
+ while ((parent = child->parent))
+ {
+ for (box = parent->u.box.firstChild;
+ box != child;
+ box = box->nextSibling)
+ {
+ if (box->type == VariableBox && box->u.variable.quark == quark)
+ return box->u.variable.expr;
+ }
+ child = parent;
+ }
+ return 0;
+}
+
+static double
+Evaluate (l, box, expr, natural)
+ LayoutWidget l;
+ BoxPtr box;
+ ExprPtr expr;
+ double natural;
+{
+ double left, right, down;
+ Widget widget;
+ SubInfoPtr info;
+
+ switch (expr->type) {
+ case Constant:
+ return expr->u.constant;
+ case Binary:
+ left = Evaluate (l, box, expr->u.binary.left, natural);
+ right = Evaluate (l, box, expr->u.binary.right, natural);
+ switch (expr->u.binary.op) {
+ case Plus:
+ return left + right;
+ case Minus:
+ return left - right;
+ case Times:
+ return left * right;
+ case Divide:
+ return left / right;
+ case Percent:
+ return right * left / 100.0;
+ }
+ case Unary:
+ down = Evaluate (l, box, expr->u.unary.down, natural);
+ switch (expr->u.unary.op) {
+ case Percent:
+ return natural * down / 100.0;
+ case Minus:
+ return -down;
+ case Plus:
+ case Times:
+ case Divide:
+ break;
+ }
+ case Width:
+ widget = QuarkToWidget (l, expr->u.width);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutHorizontal];
+ case Height:
+ widget = QuarkToWidget (l, expr->u.height);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutVertical];
+ case Variable:
+ expr = LookupVariable (box, expr->u.variable);
+ if (!expr)
+ {
+ char buf[256];
+ (void) sprintf (buf, "Layout: undefined variable %s\n",
+ XrmQuarkToString (expr->u.variable));
+ XtError (buf);
+ return 0.0;
+ }
+ return Evaluate (l, box, expr, natural);
+ }
+ return 0.0;
+}
+
+static void
+DisposeExpr (expr)
+ ExprPtr expr;
+{
+ if (!expr)
+ return;
+ switch (expr->type) {
+ case Constant:
+ break;
+ case Binary:
+ DisposeExpr (expr->u.binary.left);
+ DisposeExpr (expr->u.binary.right);
+ break;
+ case Unary:
+ DisposeExpr (expr->u.unary.down);
+ break;
+ case Width:
+ case Height:
+ case Variable:
+ break;
+ }
+ Dispose (expr);
+}
+
+#define CheckGlue(l, box, glue, n) { \
+ if (glue.expr) \
+ glue.value = Evaluate (l, box, glue.expr, n); \
+ if (glue.order == 0 && glue.value == 0) \
+ glue.order = -1; \
+ else if (glue.order == -1 && glue.value != 0) \
+ glue.order = 0; \
+}
+
+#define DoStretch(l, box, dir) \
+ CheckGlue (l, box, box->params.stretch[dir], (double) box->natural[dir]);
+
+#define DoShrink(l, box, dir) \
+ CheckGlue (l, box, box->params.shrink[dir], (double) box->natural[dir])
+
+/* compute the natural sizes of a box */
+static void
+ComputeNaturalSizes (l, box, dir)
+ LayoutWidget l;
+ BoxPtr box;
+ LayoutDirection dir;
+{
+ BoxPtr child;
+ Widget w;
+ SubInfoPtr info;
+ int minStretchOrder, minShrinkOrder;
+ LayoutDirection thisDir;
+
+ switch (box->type) {
+ case WidgetBox:
+ w = box->u.widget.widget = QuarkToWidget (l, box->u.widget.quark);
+ if (!w)
+ {
+ box->natural[LayoutHorizontal] = 0;
+ box->natural[LayoutVertical] = 0;
+ }
+ else
+ {
+ info = SubInfo (w);
+ box->natural[LayoutHorizontal] = info->naturalSize[LayoutHorizontal];
+ box->natural[LayoutVertical] = info->naturalSize[LayoutVertical];
+ }
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ DoStretch (l, box, !dir);
+ DoShrink (l, box, !dir);
+ break;
+ case GlueBox:
+ box->natural[dir] = Evaluate (l, box, box->u.glue.expr, 0.0);
+ box->natural[!dir] = 0;
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ break;
+ case BoxBox:
+ thisDir = box->u.box.dir;
+ box->natural[0] = 0;
+ box->natural[1] = 0;
+ minStretchOrder = 100000;
+ minShrinkOrder = 100000;
+ ZeroGlue (box->params.shrink[thisDir]);
+ ZeroGlue (box->params.stretch[thisDir]);
+ box->params.shrink[!thisDir].order = 100000;
+ box->params.stretch[!thisDir].order = 100000;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+
+ ComputeNaturalSizes (l, child, thisDir);
+ /*
+ * along box axis:
+ * normal size += child normal size
+ * shrink += child shrink
+ * stretch += child stretch
+ */
+ box->natural[thisDir] += child->natural[thisDir];
+ AddGlue (box->params.shrink[thisDir],
+ box->params.shrink[thisDir],
+ child->params.shrink[thisDir]);
+ AddGlue (box->params.stretch[thisDir],
+ box->params.stretch[thisDir],
+ child->params.stretch[thisDir]);
+ /*
+ * normal to box axis:
+ * normal size = maximum child normal size of minimum shrink order
+ * shrink = difference between normal size and minimum shrink
+ * stretch = minimum child stretch
+ */
+ if (box->natural[!thisDir] >= child->natural[!thisDir])
+ {
+ if (child->params.stretch[!thisDir].order < minShrinkOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ if (child->params.shrink[!thisDir].order < minShrinkOrder)
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ }
+ }
+ else
+ {
+ if (child->params.shrink[!thisDir].order <= minStretchOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ if (child->params.stretch[!thisDir].order < minStretchOrder)
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ }
+ }
+ MinGlue (box->params.stretch[!thisDir],
+ box->params.stretch[!thisDir],
+ child->params.stretch[!thisDir]);
+ MinGlue (box->params.shrink[!thisDir],
+ box->params.shrink[!thisDir],
+ child->params.shrink[!thisDir]);
+ }
+ if (box->params.shrink[!thisDir].order <= 0)
+ {
+ int minSize;
+ int largestMinSize;
+
+ largestMinSize = 0;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+
+ if (child->params.shrink[!thisDir].order <= 0)
+ {
+ minSize = child->natural[!thisDir] -
+ child->params.shrink[!thisDir].value;
+ if (minSize > largestMinSize)
+ largestMinSize = minSize;
+ }
+ }
+ box->params.shrink[!thisDir].value = box->natural[!thisDir] -
+ largestMinSize;
+ if (box->params.shrink[!thisDir].value == 0)
+ box->params.shrink[!thisDir].order = -1;
+ else
+ box->params.shrink[!thisDir].order = 0;
+ }
+ /* 24Jan97 MJF - VariableBox is excluded above.
+ break;
+ case VariableBox:
+ break;
+ */
+ }
+}
+
+/* given the boxs geometry, set the geometry of the pieces */
+
+#define GluePart(a,b,dist) ((a) ? ((int) (((a) * (dist)) / (b) + \
+ ((dist >= 0) ? 0.5 : -0.5))) : 0)
+
+static Bool
+ComputeSizes (box)
+ BoxPtr box;
+{
+ LayoutDirection dir;
+ BoxPtr child;
+ GlueRec stretch;
+ GlueRec shrink;
+ GlueRec totalGlue[2];
+ double remainingGlue;
+ GluePtr glue;
+ int size;
+ int totalSizes;
+ int totalChange[2];
+ int change;
+ int remainingChange;
+ Bool shrinking;
+ Bool happy;
+ int i;
+ int maxGlue;
+
+ dir = box->u.box.dir;
+ size = box->size[dir];
+
+ stretch = box->params.stretch[dir];
+ shrink = box->params.shrink[dir];
+
+ /* pick the correct adjustment parameters based on the change direction */
+
+ totalChange[0] = size - box->natural[dir];
+
+ shrinking = totalChange[0] < 0;
+
+ totalChange[1] = 0;
+ totalGlue[1].order = 100000;
+ totalGlue[1].value = 0;
+ maxGlue = 1;
+ if (shrinking)
+ {
+ totalGlue[0] = shrink;
+ /* for first-order infinites, shrink it to zero and then
+ * shrink the zero-orders
+ */
+ if (shrink.order == 1) {
+ totalSizes = 0;
+ remainingGlue = 0;
+ for (child = box->u.box.firstChild;
+ child;
+ child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+
+ switch (child->params.shrink[dir].order) {
+ case 0:
+ remainingGlue += child->params.shrink[dir].value;
+ break;
+ case 1:
+ totalSizes += child->natural[dir];
+ break;
+ }
+ }
+ if (totalSizes < -totalChange[0])
+ {
+ totalGlue[1] = shrink;
+ totalGlue[0].order = 0;
+ totalGlue[0].value = remainingGlue;
+ totalChange[1] = -totalSizes;
+ totalChange[0] = totalChange[0] - totalChange[1];
+ maxGlue = 2;
+ }
+ }
+ if (totalGlue[0].order <= 0 &&
+ totalChange[0] > totalGlue[0].value)
+ {
+ totalChange[0] = totalGlue[0].value;
+ }
+ }
+ else
+ totalGlue[0] = stretch;
+
+ /* adjust each box */
+ totalSizes = 0;
+ remainingGlue = totalGlue[0].value + totalGlue[1].value;
+ remainingChange = totalChange[0] + totalChange[1];
+ happy = True;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* never add glue or stretch to a VariableBox! */
+ if (child->type == VariableBox) continue;
+
+ if (shrinking)
+ glue = &child->params.shrink[dir];
+ else
+ glue = &child->params.stretch[dir];
+
+ child->size[dir] = child->natural[dir];
+ for (i = 0; i < maxGlue; i++)
+ {
+ if (glue->order == totalGlue[i].order)
+ {
+ remainingGlue -= glue->value;
+ if (remainingGlue <= 0)
+ change = remainingChange;
+ else
+ change = GluePart (glue->value,
+ totalGlue[i].value,
+ totalChange[i]);
+ child->size[dir] += change;
+ remainingChange -= change;
+ }
+ }
+ child->size[!dir] = box->size[!dir];
+ totalSizes += child->size[dir];
+ if (child->type == BoxBox)
+ if (!ComputeSizes (child))
+ happy = False;
+ }
+ return totalSizes == box->size[dir] && happy;
+}
+
+static void
+SetSizes (box, x, y)
+ BoxPtr box;
+ Position x, y;
+{
+ BoxPtr child;
+ int width, height;
+ int bw;
+ Widget w;
+ SubInfoPtr info;
+
+ switch (box->type) {
+ case WidgetBox:
+ w = box->u.widget.widget;
+ if (w)
+ {
+ info = SubInfo(w);
+ /* info = (SubInfoPtr) w->core.constraints; */
+ width = box->size[LayoutHorizontal];
+ height = box->size[LayoutVertical];
+ bw = info->naturalBw;
+ width -= bw * 2;
+ height -= bw * 2;
+ /* Widgets which grow too small are placed off screen */
+ if (width <= 0 || height <= 0)
+ {
+ width = 1;
+ height = 1;
+ bw = 0;
+ x = -1;
+ y = -1;
+ }
+ XtConfigureWidget (w, x, y,
+ (Dimension)width, (Dimension)height,
+ (Dimension)bw);
+ }
+ break;
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 18Mar94 DCT - omit VariableBox here. */
+ if (child->type != VariableBox) {
+ SetSizes (child, x, y);
+ if (box->u.box.dir == LayoutHorizontal)
+ x += child->size[LayoutHorizontal];
+ else
+ y += child->size[LayoutVertical];
+ }
+ }
+ break;
+ case GlueBox:
+ case VariableBox:
+ break;
+ }
+}
+
+static void
+LayoutFreeLayout (box)
+ BoxPtr box;
+{
+ BoxPtr child, next;
+
+ switch (box->type) {
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = next)
+ {
+ next = child->nextSibling;
+ LayoutFreeLayout (child);
+ }
+ break;
+ case GlueBox:
+ DisposeExpr (box->u.glue.expr);
+ break;
+ case WidgetBox:
+ case VariableBox:
+ default:
+ break;
+ }
+ DisposeExpr (box->params.stretch[LayoutHorizontal].expr);
+ DisposeExpr (box->params.shrink[LayoutHorizontal].expr);
+ DisposeExpr (box->params.stretch[LayoutVertical].expr);
+ DisposeExpr (box->params.shrink[LayoutVertical].expr);
+ Dispose (box);
+}
+
+
+static void
+LayoutGetNaturalSize (l, widthp, heightp)
+ LayoutWidget l;
+ Dimension *widthp, *heightp;
+{
+ BoxPtr box;
+
+ box = l->layout.layout;
+ if (box)
+ {
+ ComputeNaturalSizes (l, box, LayoutHorizontal);
+ *widthp = box->natural[LayoutHorizontal];
+ *heightp = box->natural[LayoutVertical];
+ }
+ else
+ {
+ *widthp = 0;
+ *heightp = 0;
+ }
+}
+
+static void
+LayoutLayout (l, attemptResize)
+ LayoutWidget l;
+ Bool attemptResize;
+{
+ BoxPtr box;
+ Dimension width, height;
+ Dimension prefered_width, prefered_height;
+
+ box = l->layout.layout;
+ if (!box)
+ return;
+ LayoutGetNaturalSize (l, &prefered_width, &prefered_height);
+ if (l->core.width == 0 || l->core.height == 0)
+ {
+ l->core.width = prefered_width;
+ l->core.height = prefered_height;
+ }
+ box->size[LayoutHorizontal] = l->core.width;
+ box->size[LayoutVertical] = l->core.height;
+ if (!ComputeSizes (box) && attemptResize)
+ {
+ XtMakeResizeRequest ((Widget) l,
+ prefered_width, prefered_height,
+ &width, &height);
+ if (width != box->size[LayoutHorizontal] ||
+ height != box->size[LayoutVertical])
+ {
+ box->size[LayoutHorizontal] = width;
+ box->size[LayoutVertical] = height;
+ ComputeSizes (box);
+ }
+ }
+ if (l->layout.debug)
+ {
+ printf ("------------------- %s layout ------------------\n",
+ l->core.name);
+ PrintBox (box, 0);
+ fflush (stdout);
+ }
+ SetSizes (box, 0, 0);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/Layout.c.ORIG b/vendor/x11iraf/obm/ObmW/Layout.c.ORIG
new file mode 100644
index 00000000..d11b036a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Layout.c.ORIG
@@ -0,0 +1,952 @@
+/*
+ * $XConsortium: Layout.c,v 1.1 91/09/13 18:51:44 keith Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Misc.h>
+#include <X11/Xmu/Converters.h>
+
+#include "LayoutP.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+/*****************************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************************/
+
+#define offset(field) XtOffsetOf(LayoutRec, layout.field)
+
+static XtResource resources[] = {
+ {XtNlayout, XtCLayout, XtRLayout, sizeof (BoxPtr),
+ offset(layout), XtRLayout, NULL },
+ {XtNdebug, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(debug), XtRImmediate, (XtPointer) FALSE},
+};
+
+#undef offset
+
+static void ClassInitialize(), Initialize();
+static void Resize();
+static Boolean SetValues();
+static XtGeometryResult GeometryManager();
+static void ChangeManaged();
+static void InsertChild();
+static XtGeometryResult QueryGeometry ();
+static void GetDesiredSize ();
+
+static void LayoutLayout ();
+static void LayoutGetNaturalSize ();
+static void LayoutFreeLayout ();
+
+extern void LayYYsetsource(), LayYYsetdest();
+extern int LayYYparse();
+
+#define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
+
+LayoutClassRec layoutClassRec = {
+ {
+/* core class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class name */ "Layout",
+ /* size */ sizeof(LayoutRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part init */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ FALSE,
+ /* compress_exposure */ FALSE,
+ /* compress_enterleave*/ FALSE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+ /* expose */ NULL,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }, {
+/* composite class fields */
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ InsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ }, {
+/* constraint class fields */
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ sizeof(LayoutConstraintsRec),
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec;
+
+#define ForAllChildren(pw, childP) \
+ for ( (childP) = (pw)->composite.children ; \
+ (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
+ (childP)++ ) if (!XtIsManaged(*childP)) ; else
+
+/************************************************************
+ *
+ * Semi-public routines.
+ *
+ ************************************************************/
+
+/* Function Name: ClassInitialize
+ * Description: The Layout widgets class initialization proc.
+ * Arguments: none.
+ * Returns: none.
+ */
+
+/*ARGSUSED*/
+static Boolean
+CvtStringToLayout (dpy, args, num_args, from, to, converter_data)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *num_args;
+ XrmValue *from, *to;
+ XtPointer *converter_data;
+{
+ LayYYsetsource ((char *) from->addr);
+ LayYYsetdest ((BoxPtr *) to->addr);
+ if (LayYYparse () == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*ARGSUSED*/
+static void
+DisposeLayout (app, to, data, args, num_args)
+ XtAppContext app;
+ XrmValue *to;
+ XtPointer data;
+ XrmValuePtr args;
+ Cardinal *num_args;
+{
+ LayoutFreeLayout (* (LayoutPtr *) to->addr);
+}
+
+static void
+ClassInitialize()
+{
+ XtSetTypeConverter ( XtRString, XtRLayout, CvtStringToLayout,
+ (XtConvertArgList)NULL, (Cardinal)0, XtCacheNone,
+ DisposeLayout );
+}
+
+/*ARGSUSED*/
+static XtGeometryResult GeometryManager(child, request, reply)
+ Widget child;
+ XtWidgetGeometry *request, *reply;
+{
+ LayoutWidget w = (LayoutWidget) XtParent(child);
+ SubInfoPtr p = SubInfo(child);
+ int bw;
+ Bool changed, bwChanged;
+
+ bw = p->naturalBw;
+ changed = FALSE;
+ bwChanged = FALSE;
+ if (request->request_mode & CWBorderWidth &&
+ request->border_width != child->core.border_width)
+ {
+ p->naturalBw = bw;
+ bw = request->border_width;
+ changed = TRUE;
+ bwChanged = TRUE;
+ }
+ if (bwChanged || request->request_mode & CWWidth &&
+ request->width != child->core.width)
+ {
+ p->naturalSize[LayoutHorizontal] = request->width + bw * 2;
+ changed = TRUE;
+ }
+ if (bwChanged || request->request_mode & CWHeight &&
+ request->height != child->core.height)
+ {
+ p->naturalSize[LayoutVertical] = request->height + bw * 2;
+ changed = TRUE;
+ }
+ if (changed)
+ LayoutLayout (w, TRUE);
+ return XtGeometryDone;
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+Widget request, new;
+ArgList args;
+Cardinal *num_args;
+{
+/* LayoutWidget w = (LayoutWidget)new; */
+}
+
+static void ChangeManaged(gw)
+ Widget gw;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ Widget *children;
+
+ ForAllChildren (w, children)
+ GetDesiredSize (*children);
+ LayoutLayout ((LayoutWidget) w, TRUE);
+}
+
+static void
+GetDesiredSize (child)
+ Widget child;
+{
+ XtWidgetGeometry desired;
+ SubInfoPtr p;
+
+ XtQueryGeometry (child, (XtWidgetGeometry *) NULL, &desired);
+ p = SubInfo (child);
+ p->naturalBw = desired.border_width;
+ p->naturalSize[LayoutHorizontal] = desired.width + desired.border_width * 2;
+ p->naturalSize[LayoutVertical] = desired.height + desired.border_width * 2;
+}
+
+static void InsertChild (child)
+ Widget child;
+{
+ (*SuperClass->composite_class.insert_child) (child);
+ GetDesiredSize (child);
+}
+
+static void
+Resize(gw)
+ Widget gw;
+{
+ LayoutLayout ((LayoutWidget) gw, FALSE);
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues(gold, greq, gnew, args, num_args)
+ Widget gold, greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ LayoutWidget old = (LayoutWidget) gold,
+ new = (LayoutWidget) gnew;
+
+ if (old->layout.layout != new->layout.layout)
+ LayoutLayout (new, TRUE);
+ return FALSE;
+} /* SetValues */
+
+static XtGeometryResult
+QueryGeometry (gw, request, prefered_return)
+ Widget gw;
+ XtWidgetGeometry *request, *prefered_return;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ XtGeometryResult result;
+ XtWidgetGeometry prefered_size;
+
+ if (request && !(request->request_mode & CWWidth|CWHeight))
+ return XtGeometryYes;
+ LayoutGetNaturalSize (w, &prefered_size.width, &prefered_size.height);
+ prefered_return->request_mode = 0;
+ result = XtGeometryYes;
+ if (!request) {
+ prefered_return->width = prefered_size.width;
+ prefered_return->height= prefered_size.height;
+ if (prefered_size.width != w->core.width) {
+ prefered_return->request_mode |= CWWidth;
+ result = XtGeometryAlmost;
+ }
+ if (prefered_size.height != w->core.height) {
+ prefered_return->request_mode |= CWHeight;
+ result = XtGeometryAlmost;
+ }
+ } else {
+ if (request->request_mode & CWWidth) {
+ if (prefered_size.width > request->width)
+ {
+ if (prefered_size.width == w->core.width)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWWidth;
+ prefered_return->width = prefered_size.width;
+ }
+ }
+ }
+ if (request->request_mode & CWHeight) {
+ if (prefered_size.height > request->height)
+ {
+ if (prefered_size.height == w->core.height)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWHeight;
+ prefered_return->height = prefered_size.height;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * Layout section. Exports LayoutGetNaturalSize and
+ * LayoutLayout to above section
+ */
+
+static void
+PrintGlue (g)
+ GlueRec g;
+{
+ if (g.order == 0 || g.value != 1.0)
+ (void) printf ("%g", g.value);
+ if (g.order > 0)
+ {
+ (void) printf ("%s", " inf");
+ if (g.order > 1);
+ (void) printf (" %d", g.order);
+ }
+}
+
+static void
+PrintDirection (dir)
+ LayoutDirection dir;
+{
+ switch (dir) {
+ case LayoutHorizontal:
+ (void) printf ("%s", "horizontal");
+ break;
+ case LayoutVertical:
+ (void) printf ("%s", "vertical");
+ break;
+ default:
+ (void) printf ("Unknown layout direction %d\n", dir);
+ break;
+
+ }
+}
+
+static void
+TabTo(level)
+ int level;
+{
+ while (level--)
+ (void) printf ("%s", " ");
+}
+
+static void
+PrintBox (box, level)
+ BoxPtr box;
+ int level;
+{
+ BoxPtr child;
+
+ TabTo (level);
+ (void) printf ("%s", "< ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutHorizontal]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutHorizontal]);
+ (void) printf ("%s", " * ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutVertical]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutVertical]);
+ (void) printf ("%s", " >");
+ (void) printf (" size: %d x %d", box->size[0], box->size[1]);
+ (void) printf (" natural: %d x %d ", box->natural[0], box->natural[1]);
+ switch (box->type) {
+ case BoxBox:
+ PrintDirection (box->u.box.dir);
+ (void) printf ("%s\n", "");
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ PrintBox (child, level+1);
+ break;
+ case WidgetBox:
+ (void) printf (" %s\n", XrmQuarkToString (box->u.widget.quark));
+ break;
+ case GlueBox:
+ (void) printf ("%s\n", " glue");
+ break;
+ case VariableBox:
+ (void) printf (" variable %s\n", XrmQuarkToString (box->u.variable.quark));
+ break;
+ }
+}
+
+ExprPtr
+LookupVariable (child, quark)
+ BoxPtr child;
+ XrmQuark quark;
+{
+ BoxPtr parent, box;
+
+ while (parent = child->parent)
+ {
+ for (box = parent->u.box.firstChild;
+ box != child;
+ box = box->nextSibling)
+ {
+ if (box->type == VariableBox && box->u.variable.quark == quark)
+ return box->u.variable.expr;
+ }
+ child = parent;
+ }
+ return 0;
+}
+
+static double
+Evaluate (l, box, expr, natural)
+ LayoutWidget l;
+ BoxPtr box;
+ ExprPtr expr;
+ double natural;
+{
+ double left, right, down;
+ Widget widget;
+ SubInfoPtr info;
+
+ switch (expr->type) {
+ case Constant:
+ return expr->u.constant;
+ case Binary:
+ left = Evaluate (l, box, expr->u.binary.left, natural);
+ right = Evaluate (l, box, expr->u.binary.right, natural);
+ switch (expr->u.binary.op) {
+ case Plus:
+ return left + right;
+ case Minus:
+ return left - right;
+ case Times:
+ return left * right;
+ case Divide:
+ return left / right;
+ case Percent:
+ return right * left / 100.0;
+ }
+ case Unary:
+ down = Evaluate (l, box, expr->u.unary.down, natural);
+ switch (expr->u.unary.op) {
+ case Percent:
+ return natural * down / 100.0;
+ case Minus:
+ return -down;
+ }
+ case Width:
+ widget = QuarkToWidget (l, expr->u.width);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutHorizontal];
+ case Height:
+ widget = QuarkToWidget (l, expr->u.height);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutVertical];
+ case Variable:
+ expr = LookupVariable (box, expr->u.variable);
+ if (!expr)
+ {
+ char buf[256];
+ (void) sprintf (buf, "Layout: undefined variable %s\n",
+ XrmQuarkToString (expr->u.variable));
+ XtError (buf);
+ return 0.0;
+ }
+ return Evaluate (l, box, expr, natural);
+ }
+}
+
+static void
+DisposeExpr (expr)
+ ExprPtr expr;
+{
+ if (!expr)
+ return;
+ switch (expr->type) {
+ case Constant:
+ break;
+ case Binary:
+ DisposeExpr (expr->u.binary.left);
+ DisposeExpr (expr->u.binary.right);
+ break;
+ case Unary:
+ DisposeExpr (expr->u.unary.down);
+ break;
+ case Width:
+ break;
+ case Height:
+ break;
+
+ }
+ Dispose (expr);
+}
+
+#define CheckGlue(l, box, glue, n) { \
+ if (glue.expr) \
+ glue.value = Evaluate (l, box, glue.expr, n); \
+ if (glue.order == 0 && glue.value == 0) \
+ glue.order = -1; \
+ else if (glue.order == -1 && glue.value != 0) \
+ glue.order = 0; \
+}
+
+#define DoStretch(l, box, dir) \
+ CheckGlue (l, box, box->params.stretch[dir], (double) box->natural[dir]);
+
+#define DoShrink(l, box, dir) \
+ CheckGlue (l, box, box->params.shrink[dir], (double) box->natural[dir])
+
+/* compute the natural sizes of a box */
+static void
+ComputeNaturalSizes (l, box, dir)
+ LayoutWidget l;
+ BoxPtr box;
+ LayoutDirection dir;
+{
+ BoxPtr child;
+ Widget w;
+ SubInfoPtr info;
+ int minStretchOrder, minShrinkOrder;
+ LayoutDirection thisDir;
+
+ switch (box->type) {
+ case VariableBox:
+ box->natural[LayoutHorizontal] = 0;
+ box->natural[LayoutVertical] = 0;
+ break;
+
+ case WidgetBox:
+ w = box->u.widget.widget = QuarkToWidget (l, box->u.widget.quark);
+ if (!w)
+ {
+ box->natural[LayoutHorizontal] = 0;
+ box->natural[LayoutVertical] = 0;
+ }
+ else
+ {
+ info = SubInfo (w);
+ box->natural[LayoutHorizontal] = info->naturalSize[LayoutHorizontal];
+ box->natural[LayoutVertical] = info->naturalSize[LayoutVertical];
+ }
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ DoStretch (l, box, !dir);
+ DoShrink (l, box, !dir);
+ break;
+ case GlueBox:
+ box->natural[dir] = Evaluate (l, box, box->u.glue.expr, 0.0);
+ box->natural[!dir] = 0;
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ break;
+ case BoxBox:
+ thisDir = box->u.box.dir;
+ box->natural[0] = 0;
+ box->natural[1] = 0;
+ minStretchOrder = 100000;
+ minShrinkOrder = 100000;
+ ZeroGlue (box->params.shrink[thisDir]);
+ ZeroGlue (box->params.stretch[thisDir]);
+ box->params.shrink[!thisDir].order = 100000;
+ box->params.stretch[!thisDir].order = 100000;
+
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+
+ ComputeNaturalSizes (l, child, thisDir);
+ /*
+ * along box axis:
+ * normal size += child normal size
+ * shrink += child shrink
+ * stretch += child stretch
+ */
+ box->natural[thisDir] += child->natural[thisDir];
+ AddGlue (box->params.shrink[thisDir],
+ box->params.shrink[thisDir],
+ child->params.shrink[thisDir]);
+ AddGlue (box->params.stretch[thisDir],
+ box->params.stretch[thisDir],
+ child->params.stretch[thisDir]);
+ /*
+ * normal to box axis:
+ * normal size = maximum child normal size of minimum shrink order
+ * shrink = difference between normal size and minimum shrink
+ * stretch = minimum child stretch
+ */
+ if (box->natural[!thisDir] >= child->natural[!thisDir])
+ {
+ if (child->params.stretch[!thisDir].order < minShrinkOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ if (child->params.shrink[!thisDir].order < minShrinkOrder)
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ }
+ }
+ else
+ {
+ if (child->params.shrink[!thisDir].order <= minStretchOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ if (child->params.stretch[!thisDir].order < minStretchOrder)
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ }
+ }
+ MinGlue (box->params.stretch[!thisDir],
+ box->params.stretch[!thisDir],
+ child->params.stretch[!thisDir]);
+ MinGlue (box->params.shrink[!thisDir],
+ box->params.shrink[!thisDir],
+ child->params.shrink[!thisDir]);
+ }
+ if (box->params.shrink[!thisDir].order <= 0)
+ {
+ int minSize;
+ int largestMinSize;
+
+ largestMinSize = 0;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+ if (child->params.shrink[!thisDir].order <= 0)
+ {
+ minSize = child->natural[!thisDir] -
+ child->params.shrink[!thisDir].value;
+ if (minSize > largestMinSize)
+ largestMinSize = minSize;
+ }
+ }
+ box->params.shrink[!thisDir].value = box->natural[!thisDir] -
+ largestMinSize;
+ if (box->params.shrink[!thisDir].value == 0)
+ box->params.shrink[!thisDir].order = -1;
+ else
+ box->params.shrink[!thisDir].order = 0;
+ }
+ }
+}
+
+/* given the boxs geometry, set the geometry of the pieces */
+
+#define GluePart(a,b,dist) ((a) ? ((int) (((a) * (dist)) / (b) + \
+ ((dist >= 0) ? 0.5 : -0.5))) : 0)
+
+static Bool
+ComputeSizes (box)
+ BoxPtr box;
+{
+ LayoutDirection dir;
+ BoxPtr child;
+ GlueRec stretch;
+ GlueRec shrink;
+ GlueRec totalGlue[2];
+ double remainingGlue;
+ GluePtr glue;
+ int size;
+ int totalSizes;
+ int totalChange[2];
+ int change;
+ int remainingChange;
+ Bool shrinking;
+ Bool happy;
+ int i;
+ int maxGlue;
+
+ dir = box->u.box.dir;
+ size = box->size[dir];
+
+ stretch = box->params.stretch[dir];
+ shrink = box->params.shrink[dir];
+
+ /* pick the correct adjustment parameters based on the change direction */
+
+ totalChange[0] = size - box->natural[dir];
+
+ shrinking = totalChange[0] < 0;
+
+ totalChange[1] = 0;
+ totalGlue[1].order = 100000;
+ totalGlue[1].value = 0;
+ maxGlue = 1;
+ if (shrinking)
+ {
+ totalGlue[0] = shrink;
+ /* for first-order infinites, shrink it to zero and then
+ * shrink the zero-orders
+ */
+ if (shrink.order == 1) {
+ totalSizes = 0;
+ remainingGlue = 0;
+ for (child = box->u.box.firstChild;
+ child;
+ child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+ switch (child->params.shrink[dir].order) {
+ case 0:
+ remainingGlue += child->params.shrink[dir].value;
+ break;
+ case 1:
+ totalSizes += child->natural[dir];
+ break;
+ }
+ }
+ if (totalSizes < -totalChange[0])
+ {
+ totalGlue[1] = shrink;
+ totalGlue[0].order = 0;
+ totalGlue[0].value = remainingGlue;
+ totalChange[1] = -totalSizes;
+ totalChange[0] = totalChange[0] - totalChange[1];
+ maxGlue = 2;
+ }
+ }
+ if (totalGlue[0].order <= 0 &&
+ totalChange[0] > totalGlue[0].value)
+ {
+ totalChange[0] = totalGlue[0].value;
+ }
+ }
+ else
+ totalGlue[0] = stretch;
+
+ /* adjust each box */
+ totalSizes = 0;
+ remainingGlue = totalGlue[0].value + totalGlue[1].value;
+ remainingChange = totalChange[0] + totalChange[1];
+ happy = True;
+
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 02Jan95 DCT - omit VariableBox here. */
+ if (child->type == VariableBox)
+ continue;
+
+ if (shrinking)
+ glue = &child->params.shrink[dir];
+ else
+ glue = &child->params.stretch[dir];
+
+ child->size[dir] = child->natural[dir];
+ for (i = 0; i < maxGlue; i++)
+ {
+ if (glue->order == totalGlue[i].order)
+ {
+ remainingGlue -= glue->value;
+ if (remainingGlue <= 0)
+ change = remainingChange;
+ else
+ change = GluePart (glue->value,
+ totalGlue[i].value,
+ totalChange[i]);
+ child->size[dir] += change;
+ remainingChange -= change;
+ }
+ }
+ child->size[!dir] = box->size[!dir];
+ totalSizes += child->size[dir];
+ if (child->type == BoxBox)
+ if (!ComputeSizes (child))
+ happy = False;
+ }
+ return totalSizes == box->size[dir] && happy;
+}
+
+static void
+SetSizes (box, x, y)
+ BoxPtr box;
+ Position x, y;
+{
+ BoxPtr child;
+ int width, height;
+ int bw;
+ Widget w;
+ SubInfoPtr info;
+
+ switch (box->type) {
+ case WidgetBox:
+ w = box->u.widget.widget;
+ if (w)
+ {
+ info = (SubInfoPtr) w->core.constraints;
+ width = box->size[LayoutHorizontal];
+ height = box->size[LayoutVertical];
+ bw = info->naturalBw;
+ width -= bw * 2;
+ height -= bw * 2;
+ /* Widgets which grow too small are placed off screen */
+ if (width <= 0 || height <= 0)
+ {
+ width = 1;
+ height = 1;
+ bw = 0;
+ x = -1;
+ y = -1;
+ }
+ XtConfigureWidget (w, x, y,
+ (Dimension)width, (Dimension)height,
+ (Dimension)bw);
+ }
+ break;
+ case GlueBox:
+ break;
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* 18Mar94 DCT - omit VariableBox here. */
+ if (child->type != VariableBox) {
+ SetSizes (child, x, y);
+ if (box->u.box.dir == LayoutHorizontal)
+ x += child->size[LayoutHorizontal];
+ else
+ y += child->size[LayoutVertical];
+ }
+ }
+ break;
+ }
+}
+
+static void
+LayoutFreeLayout (box)
+ BoxPtr box;
+{
+ BoxPtr child, next;
+
+ switch (box->type) {
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = next)
+ {
+ next = child->nextSibling;
+ LayoutFreeLayout (child);
+ }
+ break;
+ case GlueBox:
+ DisposeExpr (box->u.glue.expr);
+ break;
+ }
+ DisposeExpr (box->params.stretch[LayoutHorizontal].expr);
+ DisposeExpr (box->params.shrink[LayoutHorizontal].expr);
+ DisposeExpr (box->params.stretch[LayoutVertical].expr);
+ DisposeExpr (box->params.shrink[LayoutVertical].expr);
+ Dispose (box);
+}
+
+
+static void
+LayoutGetNaturalSize (l, widthp, heightp)
+ LayoutWidget l;
+ Dimension *widthp, *heightp;
+{
+ BoxPtr box;
+
+ box = l->layout.layout;
+ if (box)
+ {
+ ComputeNaturalSizes (l, box, LayoutHorizontal);
+ *widthp = box->natural[LayoutHorizontal];
+ *heightp = box->natural[LayoutVertical];
+ }
+ else
+ {
+ *widthp = 0;
+ *heightp = 0;
+ }
+}
+
+static void
+LayoutLayout (l, attemptResize)
+ LayoutWidget l;
+ Bool attemptResize;
+{
+ BoxPtr box;
+ Dimension width, height;
+ Dimension prefered_width, prefered_height;
+
+ box = l->layout.layout;
+ if (!box)
+ return;
+ LayoutGetNaturalSize (l, &prefered_width, &prefered_height);
+ if (l->core.width == 0 || l->core.height == 0)
+ {
+ l->core.width = prefered_width;
+ l->core.height = prefered_height;
+ }
+ box->size[LayoutHorizontal] = l->core.width;
+ box->size[LayoutVertical] = l->core.height;
+ if (!ComputeSizes (box) && attemptResize)
+ {
+ XtMakeResizeRequest ((Widget) l,
+ prefered_width, prefered_height,
+ &width, &height);
+ if (width != box->size[LayoutHorizontal] ||
+ height != box->size[LayoutVertical])
+ {
+ box->size[LayoutHorizontal] = width;
+ box->size[LayoutVertical] = height;
+ ComputeSizes (box);
+ }
+ }
+ if (l->layout.debug)
+ {
+ printf ("------------------- %s layout ------------------\n", l->core.name);
+ PrintBox (box, 0);
+ fflush (stdout);
+ }
+ SetSizes (box, 0, 0);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/Layout.ex b/vendor/x11iraf/obm/ObmW/Layout.ex
new file mode 100644
index 00000000..828fae45
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Layout.ex
@@ -0,0 +1,463 @@
+Sample layout resources from various app-defaults files.
+----------------------------
+
+*layout: vertical { \
+ NormalSpace = (25 % of height cards) \
+ NormalAdjust = 25% \
+ horizontal {\
+ $NormalSpace < +infinity -$NormalSpace > \
+ label1 label2 label3 \
+ $NormalSpace < +infinity -$NormalSpace > \
+ } \
+ horizontal {\
+ cards < * +infinity -$NormalAdjust > \
+ 0 < +infinity > \
+ } \
+ }
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ hint \
+ 5 < -5 > \
+ score \
+ 5 < -5 > \
+ pileAll \
+ 5 <+inf -inf> \
+ baseRank \
+ 5 < -5 > \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ horizontal { \
+ 0 < +inf -inf > \
+ vertical { \
+ 0 < +inf -inf > \
+ logo \
+ 0 < +inf -inf > \
+ } \
+ 0 < +inf -inf > \
+ foundation < -100% * -90% > \
+ 10 < -inf > \
+ } \
+ 10 < -inf > \
+ horizontal {\
+ 10 < -inf > \
+ vertical { \
+ horizontal { \
+ stock < -75% * -90% > \
+ 0 < +inf > \
+ } \
+ 10 < -inf > \
+ talon < -75% * -90% > \
+ } \
+ 10 < +inf -inf > \
+ tableau < -50% * +inf -50% > \
+ 10 < -inf > \
+ } \
+ horizontal { \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ hint \
+ 5 < -5 > \
+ score \
+ 5 < -5 > \
+ pileAll \
+ 0 <+inf -inf> \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ horizontal { \
+ 10 < -inf > \
+ deck < -75% * -90% > \
+ 10 < +inf -inf > \
+ piles < -100% * -90% > \
+ 10 < -inf > \
+ } \
+ 10 < -inf > \
+ stacks < -50% * +inf -50% > \
+ horizontal { \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ deal \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ score \
+ 0 <+inf -inf> \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ cards < +100% -100% * +100% -100% > \
+ horizontal { \
+ -1 \
+ dealDisplay < -100% * > \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ hint \
+ 5 < -5 > \
+ score \
+ 0 <+inf -inf> \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ horizontal { \
+ 10 < -inf > \
+ deck < -75% * -90% > \
+ 10 < +inf -inf > \
+ piles < -100% * -90% > \
+ 10 < -inf > \
+ } \
+ 10 < -inf > \
+ stacks < -50% * +inf -50% > \
+ horizontal { \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ hint \
+ 5 < -5 > \
+ score \
+ 0 <+inf -inf> \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ horizontal { \
+ 10 < -inf > \
+ vertical { \
+ stacks < -50% * +inf -50% > \
+ 10 < -inf > \
+ horizontal { \
+ vertical { \
+ 10 < +inf -inf > \
+ draw < +inf -100% * -90% > \
+ } \
+ 10 < -inf > \
+ vertical { \
+ deckCount < +inf -inf * > \
+ deck < -75% * -90% > \
+ } \
+ } \
+ } \
+ 10 < -inf > \
+ vertical { \
+ piles < -50% * -50% > \
+ 0 < +inf > \
+ } \
+ 10 < -inf > \
+ } \
+ horizontal { \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*menuBar.layout: vertical { \
+ 5 < -5 >\
+ horizontal { \
+ 5 < -5 > \
+ fileMenuButton \
+ 5 < -5 > \
+ newGame \
+ 5 < -5 > \
+ undo \
+ 5 < -5 > \
+ hint \
+ 5 < -5 > \
+ score \
+ 5 < -5 > \
+ pileAll \
+ 0 <+inf -inf> \
+ } \
+ 5 < -5 > \
+}
+
+*frame.layout: vertical {\
+ -1 \
+ horizontal {\
+ -1 \
+ menuBar < +inff -100% * >\
+ -1 \
+ } \
+ 10 < -inf > \
+ horizontal { \
+ 10 < -inf > \
+ suits < -75% * -90% > \
+ 10 < +inf -inf > \
+ piles < -100% * -90% > \
+ 10 < -inf > \
+ } \
+ 10 < -inf > \
+ stacks < -50% * +inf -50% > \
+ horizontal { \
+ -1 \
+ message < +inff -100% * > \
+ -1 \
+ } \
+ -1 \
+}
+
+*layout.layout: horizontal {\n \
+ -1 \n \
+ vertical { \n \
+ -1 \n \
+ reversi < +inff -100% * +inff -100% > \n \
+ -1 \n \
+ error < +inff -100% * > \
+ -1 \n \
+ } \n \
+ vertical { \n \
+ 10 < +10 -100% > \n \
+ horizontal { \
+ 5 < +inf -100% > \n \
+ quit \n \
+ 5 < +inf -100% > \n \
+ hint \n \
+ 5 < +inf -100% > \n \
+ undo \n \
+ 5 < +inf -100% > \n \
+ restart \n \
+ 5 < +inf -100% > \n \
+ } \n \
+ 10 < +10 -100% > \n \
+ horizontal { \n \
+ 5 < -100% > \n \
+ vertical { \n \
+ horizontal { \n \
+ playerLabel \n \
+ 0 < +inf > \n \
+ } \
+ 10 < +10 - 100% > \n \
+ horizontal { \n \
+ playWhite \n \
+ 5 < +inf -100% > \n \
+ playBlack \n \
+ 5 < +inf -100% > \n \
+ playBoth \n \
+ 5 < +inf -100% > \n \
+ playNeither \n \
+ } \n \
+ } \n \
+ 5 < +inf -100% > \n \
+ } \n \
+ 10 < +10 -100% > \n \
+ horizontal { \n \
+ 5 < -100% > \n \
+ vertical { \
+ 0 < +inf > \n \
+ levelLabel \n \
+ 0 < +inf > \n \
+ } \n \
+ 10 < -100% > \n \
+ levelValue \n \
+ 5 < +inf -100% > \n \
+ } \n \
+ 10 < +10 -100% > \n \
+ horizontal { \n \
+ 5 < -100% > \n \
+ turn \n \
+ 5 < +inf -100% > \n \
+ } \n \
+ 10 < +1000 -100% > \n \
+ } \n \
+}
+
+*layout.layout: vertical {\
+MenuBarBorderWidth = 1\
+HumanHandBorderWidth = 1\
+-$MenuBarBorderWidth \
+horizontal { \
+ -$MenuBarBorderWidth menuBar < +inf -100% * > -$MenuBarBorderWidth \
+} \
+horizontal { \
+ vertical { \
+ MinPlayHeight = 20 \
+ MinPlayWidth = 550 \
+ PlayVertShrink = (100% - $MinPlayHeight) \
+ PlayHorzShrink = (100% - $MinPlayWidth) \
+ computerPlay < -$PlayHorzShrink * +inf -$PlayVertShrink > \
+ horizontal { \
+ -1 \
+ vertical { \
+ computerMiles < +1 -100% * >\
+ horizontal { \
+ 0 < +inf > \
+ vertical { \
+ message \
+ errors \
+ 0 < +1 > \
+ }\
+ vertical { \
+ deckCount < +inf -100% * >\
+ deck < -100% * -100% > \
+ 0 < +1 > \
+ } \
+ (width deck / 4) < -inf > \
+ } \
+ humanMiles < +1 -100% * > \
+ } \
+ 10 < -inf > \
+ score < +1 * +1 > \
+ } \
+ humanPlay < -$PlayHorzShrink * +inf -$PlayVertShrink > \
+ horizontal { \
+ -$HumanHandBorderWidth \
+ humanHand < -$PlayHorzShrink * -$PlayVertShrink > \
+ } \
+ -$HumanHandBorderWidth \
+ } \
+ vertical { \
+ computerSafeties < -150% * -100% > \
+ computerSafetyLabel < +inf -inf * > \
+ 0 < +inf >\
+ humanSafeties < -150% * -100% > \
+ humanSafetyLabel < +inf -inf * >\
+ } \
+ 0 < +inf > \
+} \
+}
+
+*yesOrNoDialog.layout: vertical {\
+ Spacing = (50 % of height yesOrNoLabel) \
+ $Spacing < +inf -inf > \
+ yesOrNoLabel \
+ $Spacing < +inf -inf > \
+ horizontal { \
+ $Spacing < -inf > \
+ yesOrNoOk \
+ $Spacing < +inf -inf > \
+ yesOrNoNo \
+ $Spacing < -inf > \
+ } \
+ $Spacing < +inf -inf > \
+}
+
+*promptedDialog.layout: vertical {\
+ Spacing = (20 % of height promptedLabel) \
+ $Spacing < +inf -inf > \
+ promptedLabel \
+ $Spacing < +inf -inf > \
+ horizontal { \
+ $Spacing < -inf > \
+ promptedValue \
+ $Spacing < +inf -inf > \
+ } \
+ horizontal { \
+ $Spacing < -inf > \
+ promptedOk \
+ $Spacing < +inf -inf > \
+ promptedCancel \
+ $Spacing < -inf > \
+ } \
+ $Spacing < +inf -inf > \
+}
diff --git a/vendor/x11iraf/obm/ObmW/Layout.h b/vendor/x11iraf/obm/ObmW/Layout.h
new file mode 100644
index 00000000..7d9e636a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Layout.h
@@ -0,0 +1,94 @@
+/*
+ * $XConsortium: Layout.h,v 1.2 92/01/22 18:03:05 keith Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+
+#ifndef _XawLayout_h
+#define _XawLayout_h
+
+#include <X11/Constraint.h>
+#include <X11/Xfuncproto.h>
+
+/****************************************************************
+ *
+ * Layout Widget (SubClass of CompositeClass)
+ *
+ ****************************************************************/
+
+/* RESOURCES:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+ layout Layout Layout NULL
+
+*/
+
+/*
+ * Syntax of layout resource
+ *
+ * *layout:\
+ * <widget-name>.<edge>,<widget-name>.<edge>: distance + stretch-factor\n\
+ * ...
+ * where the null widget-name is taken to be the Layout widget
+ *
+ * e.g:
+ *
+ * *label-1.hStretch: 0
+ * *label-2.vStretch: 1
+ * *layout:\
+ * .left, label-1.left: 10 + 0\n\
+ * label-1.right, label-2.left: 10 + 1\n\
+ * label-2.right, .right: 10 + 0
+ *
+ * This layout causes label-1 to be set 10 pixels from the left edge
+ * and be whatever size the label widget requests, while label-2 will
+ * be set 10 pixels from the right edge, and take up half of the remaining
+ * space to 10 pixels from the right edge of label-1.
+ */
+
+/* New Fields */
+#define XtNlayout "layout"
+#define XtCLayout "Layout"
+#define XtRLayout "Layout"
+#define XtNdebug "debug"
+
+/* Class record constant */
+
+extern WidgetClass layoutWidgetClass;
+
+typedef struct _LayoutClassRec *LayoutWidgetClass;
+typedef struct _LayoutRec *LayoutWidget;
+
+#endif /* _Layout_h */
diff --git a/vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip b/vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip
new file mode 100644
index 00000000..e49074c6
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip
Binary files differ
diff --git a/vendor/x11iraf/obm/ObmW/LayoutP.h b/vendor/x11iraf/obm/ObmW/LayoutP.h
new file mode 100644
index 00000000..d7cbb318
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/LayoutP.h
@@ -0,0 +1,213 @@
+/*
+ * $XConsortium: LayoutP.h,v 1.2 92/01/22 18:03:08 keith Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#ifndef _XawLayoutP_h
+#define _XawLayoutP_h
+
+#include "Layout.h"
+#include <X11/ConstrainP.h>
+
+#define GlueEqual(a,b) ((a).order == (b).order && (a).value == (b).value)
+
+#define AddGlue(r,a,b) if (a.order == b.order) { \
+ r.order = a.order; \
+ r.value = a.value + b.value; \
+ } else { \
+ if (a.order > b.order) \
+ r = a; \
+ else \
+ r = b; \
+ }
+
+#define MinGlue(r,a,b) if (a.order == b.order) { \
+ r.order = a.order; \
+ if (a.value > b.value) \
+ r.value = b.value; \
+ else \
+ r.value = a.value; \
+ } else { \
+ if (a.order > b.order) \
+ r = b; \
+ else \
+ r = a; \
+ }
+
+#define SubGlue(r,a,b) if (a.order == b.order) { \
+ r.order = a.order; \
+ r.value = a.value - b.value; \
+ } else { \
+ if (a.order > b.order) \
+ r = a; \
+ else { \
+ r.order = b.order; \
+ r.value = -b.value; \
+ } \
+ }
+
+#define ZeroGlue(g) ((g).value = 0, (g).order = 0, (g).expr = 0)
+#define IsZeroGlue(g) ((g).value == 0)
+
+#define QuarkToWidget(l,q) XtNameToWidget((Widget) l, \
+ (char *) XrmQuarkToString(q));
+
+typedef enum _BoxType { BoxBox, WidgetBox, GlueBox, VariableBox } BoxType;
+
+typedef enum _LayoutDirection {
+ LayoutHorizontal = 0, LayoutVertical = 1
+} LayoutDirection;
+
+typedef enum _Operator {
+ Plus, Minus, Times, Divide, Percent
+} Operator;
+
+typedef enum _ExprType {
+ Constant,
+ Binary,
+ Unary,
+ Width,
+ Height,
+ Variable
+} ExprType;
+
+typedef struct _Expr *ExprPtr;
+
+typedef struct _Expr {
+ ExprType type;
+ union {
+ double constant;
+ struct {
+ Operator op;
+ ExprPtr left, right;
+ } binary;
+ struct {
+ Operator op;
+ ExprPtr down;
+ } unary;
+ XrmQuark width;
+ XrmQuark height;
+ XrmQuark variable;
+ } u;
+} ExprRec;
+
+typedef struct _Glue {
+ int order;
+ double value;
+ ExprPtr expr;
+} GlueRec, *GluePtr;
+
+typedef struct _BoxParams {
+ GlueRec stretch[2];
+ GlueRec shrink[2];
+} BoxParamsRec, *BoxParamsPtr;
+
+typedef struct _Box *BoxPtr;
+
+typedef BoxPtr LayoutPtr;
+
+typedef struct _Box {
+ BoxPtr nextSibling;
+ BoxPtr parent;
+ BoxParamsRec params;
+ int size[2];
+ int natural[2];
+ BoxType type;
+ union {
+ struct {
+ BoxPtr firstChild;
+ LayoutDirection dir;
+ } box;
+ struct {
+ XrmQuark quark;
+ Widget widget;
+ } widget;
+ struct {
+ ExprPtr expr;
+ } glue;
+ struct {
+ XrmQuark quark;
+ ExprPtr expr;
+ } variable;
+ } u;
+} LBoxRec; /* this conflicted with Box's BoxRec, besides, it's not used anywhere */
+
+typedef struct _SubInfo {
+ int naturalSize[2];
+ int naturalBw;
+} SubInfoRec, *SubInfoPtr;
+
+#define New(t) (t *) XtCalloc(1,sizeof (t))
+#define Dispose(p) XtFree((char *) p)
+#define Some(t,n) (t*) XtCalloc(1,sizeof(t) * n)
+#define More(p,t,n) ((p)? (t *) XtRealloc((char *) p, sizeof(t)*n):Some(t,n)
+
+/*********************************************************************
+ *
+ * Layout Widget Private Data
+ *
+ *********************************************************************/
+
+/* New fields for the Layout widget class record */
+
+typedef struct _LayoutClassPart {
+ int foo; /* keep compiler happy. */
+} LayoutClassPart;
+
+/* Full Class record declaration */
+typedef struct _LayoutClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ LayoutClassPart layout_class;
+} LayoutClassRec;
+
+extern LayoutClassRec layoutClassRec;
+
+typedef struct _LayoutConstraintsRec {
+ SubInfoRec layout;
+} LayoutConstraintsRec, *LayoutConstraints;
+
+#define SubInfo(w) (&(((LayoutConstraints) (w)->core.constraints)->layout))
+
+/* New Fields for the Layout widget record */
+
+typedef struct {
+ /* resources */
+ LayoutPtr layout;
+ Boolean debug;
+} LayoutPart;
+
+/**************************************************************************
+ *
+ * Full instance record declaration
+ *
+ **************************************************************************/
+
+typedef struct _LayoutRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ LayoutPart layout;
+} LayoutRec;
+#endif
diff --git a/vendor/x11iraf/obm/ObmW/ListTree.c b/vendor/x11iraf/obm/ObmW/ListTree.c
new file mode 100644
index 00000000..23d67475
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ListTree.c
@@ -0,0 +1,2265 @@
+/*-----------------------------------------------------------------------------
+** ListTree.c A Specialized List widget
+**
+** Widget source code
+**
+** Copyright (c) 1995 Robert W. McMullen
+**
+** Permission to use, copy, modify, distribute, and sell this software and its
+** documentation for any purpose is hereby granted without fee, provided that
+** the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. The author makes no representations about the suitability
+** of this software for any purpose. It is provided "as is" without express
+** or implied warranty.
+**
+** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+** ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+** THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+** ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+** SOFTWARE.
+*/
+
+#define _ListTree_
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <stdio.h>
+/*#include <stdlib.h> */
+
+#include "ListTreeP.h"
+#ifdef USE_RDD
+#include "rdd.h"
+#endif
+
+
+#define USE_FOLDERS
+
+#ifdef USE_FOLDERS
+#define folder_width 16
+#define folder_height 12
+static unsigned char folder_bits[] =
+{
+ 0x00, 0x1f, 0x80, 0x20, 0x7c, 0x5f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
+ 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0xfc, 0x3f,
+};
+
+#define folderopen_width 16
+#define folderopen_height 12
+static unsigned char folderopen_bits[] =
+{
+ 0x00, 0x3e, 0x00, 0x41, 0xf8, 0xd5, 0xac, 0xaa, 0x54, 0xd5, 0xfe, 0xaf,
+ 0x01, 0xd0, 0x02, 0xa0, 0x02, 0xe0, 0x04, 0xc0, 0x04, 0xc0, 0xf8, 0x7f,
+};
+
+#define document_width 9
+#define document_height 14
+static unsigned char document_bits[] =
+{
+ 0x1f, 0x00, 0x31, 0x00, 0x51, 0x00, 0x91, 0x00, 0xf1, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0xff, 0x01,};
+
+#else
+#define folder_width 12
+#define folder_height 12
+static unsigned char folder_bits[] = {
+ 0xff, 0x0f, 0x01, 0x08, 0x61, 0x08, 0x61, 0x08, 0x61, 0x08, 0xfd, 0x0b,
+ 0xfd, 0x0b, 0x61, 0x08, 0x61, 0x08, 0x61, 0x08, 0x01, 0x08, 0xff, 0x0f};
+
+#define folderopen_width 12
+#define folderopen_height 12
+static unsigned char folderopen_bits[] = {
+ 0xff, 0x0f, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0xfd, 0x0b,
+ 0xfd, 0x0b, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0xff, 0x0f};
+
+#define document_width 12
+#define document_height 12
+static unsigned char document_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf0, 0x01, 0xf8, 0x03,
+ 0xf8, 0x03, 0xf8, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+#endif
+
+#define offset(field) XtOffsetOf(ListTreeRec, list.field)
+static XtResource resources[] =
+{
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(foreground_pixel), XtRString, XtDefaultForeground},
+ {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(Margin), XtRString, "2"},
+ {XtNindent, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(Indent), XtRString, "0"},
+ {XtNhorizontalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(HSpacing), XtRString, "2"},
+ {XtNverticalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(VSpacing), XtRString, "0"},
+ {XtNlineWidth, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(LineWidth), XtRString, "0"},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ offset(font), XtRString, XtDefaultFont},
+ {XtNbranchPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
+ offset(Closed.bitmap), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
+ {XtNbranchOpenPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
+ offset(Open.bitmap), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
+ {XtNleafPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
+ offset(Leaf.bitmap), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
+ {XtNleafOpenPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
+ offset(LeafOpen.bitmap), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
+ {XtNleafCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(LeafCallback), XtRCallback, NULL},
+ {XtNbranchCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(BranchCallback), XtRCallback, NULL},
+ {XtNpathCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(PathCallback), XtRCallback, NULL},
+ {XtNhighlightCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(HighlightCallback), XtRCallback, NULL},
+ {XtNactivateCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(ActivateCallback), XtRCallback, NULL},
+};
+
+#undef offset
+
+static void Initialize();
+static void Destroy();
+static void Redisplay();
+static void Resize();
+static void ChangeSize();
+static XtGeometryResult QueryGeometry();
+static Boolean SetValues();
+static void Draw();
+static void DrawAll();
+static void DrawItemHighlight(), DrawItemHighlightClear();
+static ListTreeItem *GetItem();
+static void Select(), Notify(), Unset(), Extend();
+static void DeleteChildren();
+static Boolean Layout();
+
+#ifdef USE_RDD
+static void StartDrag(), EndDrag(), Drop();
+
+#endif
+
+#ifdef USE_RDD
+static char defaultTranslations[] =
+"<Btn2Down>: StartDrag()\n\
+<Btn2Motion>: rddDragAction()\n\
+<Btn2Up>: EndDrag()\n\
+<Btn1Up>: Notify()\n\
+<Btn1Down>: Select()\n\
+Button1 <Btn1Motion>: Extend()";
+
+#else
+static char defaultTranslations[] =
+"<Btn1Down>: Select()\n\
+<Btn1Up>: Notify()\n\
+Button1 <Btn1Motion>: Extend()";
+
+#endif
+
+static XtActionsRec actions[] =
+{
+ {"Notify", Notify},
+ {"Select", Select},
+ {"Extend", Extend},
+ {"Unset", Unset},
+#ifdef USE_RDD
+ {"StartDrag", StartDrag},
+ {"EndDrag", EndDrag},
+#endif
+};
+
+ListTreeClassRec listtreeClassRec =
+{
+ {
+ /* core_class fields */
+ /* superclass */ (WidgetClass) & widgetClassRec,
+ /* class_name */ "ListTree",
+ /* widget_size */ sizeof(ListTreeRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ True,
+ /* compress_exposure */ XtExposeCompressMultiple,
+ /* compress_enterleave */ True,
+ /* visible_interest */ True,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ {
+ /* some stupid compilers barf on empty structures */ 0
+ }
+};
+
+WidgetClass listtreeWidgetClass = (WidgetClass) & listtreeClassRec;
+
+static void
+MakePixmap(w, pix)
+ListTreeWidget w;
+Pixinfo *pix;
+{
+ Window root;
+ int x, y;
+ unsigned int width, height, bw, depth;
+
+ if (pix->bitmap && XGetGeometry(XtDisplay((Widget) w), pix->bitmap,
+ &root, &x, &y, &width, &height, &bw, &depth)) {
+ pix->width = (int) width;
+ pix->height = (int) height;
+ if (depth == 1) {
+ pix->pix = XmuCreatePixmapFromBitmap(XtDisplay((Widget) w),
+ RootWindowOfScreen(XtScreen((Widget) w)),
+ pix->bitmap,
+ width, height, w->core.depth,
+ w->list.foreground_pixel,
+ w->core.background_pixel);
+ }
+ else
+ pix->pix = pix->bitmap;
+ }
+ else {
+ pix->width = pix->height = 0;
+ pix->pix = (Pixmap) NULL;
+ }
+}
+
+static void
+FreePixmap(w, pix)
+ListTreeWidget w;
+Pixinfo *pix;
+{
+ if (pix->pix)
+ XFreePixmap(XtDisplay((Widget) w), pix->pix);
+}
+
+
+static void
+Initialize(treq, tnew, args, num)
+Widget treq, tnew;
+ArgList args;
+Cardinal *num;
+{
+ ListTreeWidget new;
+ XGCValues values;
+ XtGCMask mask;
+
+ new = (ListTreeWidget) tnew;
+
+ values.line_style = LineSolid;
+ values.line_width = new->list.LineWidth;
+ values.fill_style = FillSolid;
+ values.font = new->list.font->fid;
+ values.background = new->core.background_pixel;
+ values.foreground = new->list.foreground_pixel;
+
+ mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground | GCFont;
+ new->list.drawGC = XtGetGC((Widget) new, mask, &values);
+
+ values.function = GXinvert;
+ mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground | GCFont | GCFunction;
+ new->list.eorGC = XtGetGC((Widget) new, mask, &values);
+
+ values.background = new->list.foreground_pixel;
+ values.foreground = new->core.background_pixel;
+ mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground | GCFont;
+ new->list.highlightGC = XtGetGC((Widget) new, mask, &values);
+
+ new->list.ret_item_list=NULL;
+ new->list.ret_item_alloc=0;
+ new->list.first = new->list.highlighted = NULL;
+ new->list.Refresh = True;
+
+ new->list.timer_id = (XtIntervalId) 0;
+ new->list.multi_click_time = XtGetMultiClickTime(XtDisplay((Widget) new));
+
+ if (new->list.Closed.bitmap == XtUnspecifiedPixmap)
+ new->list.Closed.bitmap = XCreateBitmapFromData(XtDisplay((Widget) new),
+ RootWindowOfScreen(XtScreen((Widget) new)),
+ (char *)folder_bits,
+ folder_width, folder_height);
+ MakePixmap(new, &new->list.Closed);
+
+ if (new->list.Open.bitmap == XtUnspecifiedPixmap)
+ new->list.Open.bitmap = XCreateBitmapFromData(XtDisplay((Widget) new),
+ RootWindowOfScreen(XtScreen((Widget) new)),
+ (char *)folderopen_bits,
+ folderopen_width, folderopen_height);
+ MakePixmap(new, &new->list.Open);
+
+ if (new->list.Leaf.bitmap == XtUnspecifiedPixmap)
+ new->list.Leaf.bitmap = XCreateBitmapFromData(XtDisplay((Widget) new),
+ RootWindowOfScreen(XtScreen((Widget) new)),
+ (char *)document_bits,
+ document_width, document_height);
+ MakePixmap(new, &new->list.Leaf);
+
+ if (new->list.LeafOpen.bitmap == XtUnspecifiedPixmap)
+ new->list.LeafOpen.bitmap = XCreateBitmapFromData(XtDisplay((Widget) new),
+ RootWindowOfScreen(XtScreen((Widget) new)),
+ (char *)document_bits,
+ document_width, document_height);
+ MakePixmap(new, &new->list.LeafOpen);
+
+ new->list.pixWidth = new->list.Closed.width;
+ if (new->list.Open.width > new->list.pixWidth)
+ new->list.pixWidth = new->list.Open.width;
+ if (new->list.Leaf.width > new->list.pixWidth)
+ new->list.pixWidth = new->list.Leaf.width;
+ if (new->list.LeafOpen.width > new->list.pixWidth)
+ new->list.pixWidth = new->list.LeafOpen.width;
+ new->list.Closed.xoff = (new->list.pixWidth - new->list.Closed.width) / 2;
+ new->list.Open.xoff = (new->list.pixWidth - new->list.Open.width) / 2;
+ new->list.Leaf.xoff = (new->list.pixWidth - new->list.Leaf.width) / 2;
+ new->list.LeafOpen.xoff = (new->list.pixWidth - new->list.LeafOpen.width) / 2;
+
+ if (new->core.height<2) new->core.height=2;
+ if (new->core.width<2) new->core.width=2;
+}
+
+static void
+Destroy(w)
+ListTreeWidget w;
+{
+ ListTreeItem *item, *sibling;
+
+ XtReleaseGC((Widget) w, w->list.drawGC);
+ XtReleaseGC((Widget) w, w->list.highlightGC);
+ item = w->list.first;
+ while (item) {
+ if (item->firstchild) {
+ DeleteChildren(w, item->firstchild);
+ }
+ sibling = item->nextsibling;
+ XtFree((char *) item->text);
+ XtFree((char *) item);
+ item = sibling;
+ }
+ FreePixmap(w, &w->list.Closed);
+ FreePixmap(w, &w->list.Open);
+ FreePixmap(w, &w->list.Leaf);
+ FreePixmap(w, &w->list.LeafOpen);
+}
+
+static void
+Redisplay(w, event, region)
+Widget w;
+XExposeEvent *event;
+Region region;
+{
+ ListTreeWidget lw = (ListTreeWidget) w;
+
+ if (!XtIsRealized(w))
+ return;
+
+ if (event) {
+ Draw(lw, (Boolean) True, (int) event->y, (int) event->height);
+ }
+ else { /* event==NULL ==> repaint the entire list */
+ DrawAll(lw);
+ }
+}
+
+static Boolean
+SetValues(current, request, new, args, nargs)
+Widget current, request, new;
+ArgList args;
+Cardinal *nargs;
+{
+ if (!XtIsRealized(current))
+ return False;
+
+ return True;
+}
+
+
+static void
+Resize(w)
+Widget w;
+{
+ ListTreeWidget lw = (ListTreeWidget) w;
+ Dimension width, height;
+
+ if (!XtIsRealized(w))
+ return;
+ width = lw->list.preferredWidth;
+ height = lw->list.preferredHeight;
+
+/* w->core.width=width; */
+/* w->core.height=height; */
+
+ if (Layout(w, FALSE, FALSE, &width, &height))
+ XtAppWarning(XtWidgetToApplicationContext(w),
+ "ListTree Widget: Size changed when it shouldn't have when resising.");
+}
+
+/* Display functions */
+
+#define FontHeight(f) (int)(f->max_bounds.ascent + f->max_bounds.descent)
+#define FontDescent(f) (int)(f->max_bounds.descent)
+#define FontAscent(f) (int)(f->max_bounds.ascent)
+#define FontTextWidth(f,c) (int)XTextWidth(f, c, strlen(c))
+
+static void
+PreferredSize(lw, w, h)
+ListTreeWidget lw;
+Dimension *w, *h;
+{
+ *w = (Dimension) lw->list.preferredWidth;
+ *h = (Dimension) lw->list.preferredHeight;
+}
+
+/* #define DEBUG_GEOM */
+static void
+ChangeSize(w)
+ListTreeWidget w;
+{
+ XtWidgetGeometry request, reply;
+
+ request.request_mode = CWHeight | CWWidth;
+ request.height = (Dimension) w->list.preferredHeight;
+ request.width = (Dimension) w->list.preferredWidth;
+
+/* printf("requesting w=%d h=%d\n",request.width,request.height); */
+/* XtMakeGeometryRequest((Widget)w, &request, &reply); */
+/* printf("replying w=%d h=%d\n",reply.width,reply.height); */
+/* return; */
+
+#ifdef DEBUG_GEOM
+ printf("requesting w=%d h=%d\n", request.width, request.height);
+#endif
+ switch (XtMakeGeometryRequest((Widget) w, &request, &reply)) {
+ case XtGeometryYes:
+ case XtGeometryNo:
+#ifdef DEBUG_GEOM
+ printf("Yes/No: replying w=%d h=%d\n", reply.width, reply.height);
+#endif
+ break;
+ case XtGeometryAlmost:
+#ifdef DEBUG_GEOM
+ printf("Almost: replying w=%d h=%d\n", reply.width, reply.height);
+#endif
+ PreferredSize(w, &(reply.width), &(reply.height));
+ request = reply;
+ switch (XtMakeGeometryRequest((Widget) w, &request, &reply)) {
+ case XtGeometryYes:
+ case XtGeometryNo:
+ break;
+ case XtGeometryAlmost:
+#ifdef DEBUG_GEOM
+ printf("Almost again: replying w=%d h=%d\n", reply.width, reply.height);
+#endif
+ request = reply;
+ request.request_mode = CWHeight | CWWidth;
+ XtMakeGeometryRequest((Widget) w, &request, &reply);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef OLD_QUERY
+static XtGeometryResult
+oldQueryGeometry(widget, intended, reply)
+Widget widget;
+XtWidgetGeometry *intended, *reply;
+{
+ ListTreeWidget lw = (ListTreeWidget) widget;
+ Dimension w, h;
+
+/*#ifdef DEBUG_GEOM */
+/*printf("Querying geometry...\n"); */
+/*#endif */
+/**/
+/* if (intended->request_mode & (~(CWWidth | CWHeight))) */
+/* return (XtGeometryYes); */
+
+ PreferredSize(lw, &w, &h);
+
+ if (w == 0)
+ w = lw->core.width;
+ if (h == 0)
+ h = lw->core.height;
+
+#ifdef DEBUG_GEOM
+ printf("Querying geometry... intended=(%d,%d) preferred=(%d,%d)\n",
+ (int) intended->width, (int) intended->height,
+ (int) w, (int) h);
+#endif
+
+ if (intended->request_mode & CWWidth &&
+ intended->width == w &&
+ intended->request_mode & CWHeight &&
+ intended->height == h)
+ return (XtGeometryYes);
+
+ if (w == widget->core.width &&
+ h == widget->core.height)
+ return (XtGeometryNo);
+
+ reply->request_mode = CWWidth | CWHeight;
+ reply->width = w;
+ reply->height = h;
+ return XtGeometryAlmost;
+}
+#endif
+
+static Boolean
+Layout(w, xfree, yfree, width, height)
+Widget w;
+Boolean xfree, yfree;
+Dimension *width, *height;
+{
+ ListTreeWidget lw = (ListTreeWidget) w;
+ Boolean change = FALSE;
+
+#ifdef DEBUG_GEOM
+ printf("Layout... xfree=%d yfree=%d size=(%d,%d)\n",
+ (int) xfree, (int) yfree, (int) (*width), (int) (*height));
+#endif
+/*
+ * If both width and height are free to change the use default_cols
+ * to determine the number columns and set new width and height to
+ * just fit the window.
+ */
+
+ if (xfree && yfree) {
+ *width = lw->list.preferredWidth;
+ *height = lw->list.preferredHeight;
+ change = TRUE;
+ }
+
+/*
+ * If the width is fixed then use it to determine the number of columns.
+ * If the height is free to move (width still fixed) then resize the height
+ * of the widget to fit the current list exactly.
+ */
+ else if (!xfree) {
+ if (yfree) {
+ *height = lw->list.preferredHeight;
+ change = TRUE;
+ }
+ }
+
+/*
+ * The last case is xfree and !yfree we use the height to determine
+ * the number of rows and then set the width to just fit the resulting
+ * number of columns.
+ */
+ else if (!yfree) { /* xfree must be TRUE. */
+ *width = lw->list.preferredWidth;
+ change = TRUE;
+ }
+ return (change);
+}
+
+static XtGeometryResult
+QueryGeometry(lw, parent_idea, our_idea)
+ListTreeWidget lw;
+XtWidgetGeometry *parent_idea, *our_idea;
+{
+ Dimension nw, nh;
+ Boolean parent_wants_w, parent_wants_h, we_changed_size;
+
+ parent_wants_w = (parent_idea->request_mode) & CWWidth;
+ parent_wants_h = (parent_idea->request_mode) & CWHeight;
+
+ if (parent_wants_w)
+ nw = parent_idea->width;
+ else
+ nw = (Dimension) lw->list.preferredWidth;
+
+ if (parent_wants_h)
+ nh = parent_idea->height;
+ else
+ nh = (Dimension) lw->list.preferredHeight;
+
+#ifdef DEBUG_GEOM
+ printf("Querying geometry... intended=(%d,%d) preferred=(%d,%d)\n",
+ (int) parent_idea->width, (int) parent_idea->height,
+ (int) nw, (int) nh);
+#endif
+
+ our_idea->request_mode = 0;
+ if (!parent_wants_w && !parent_wants_h)
+ return (XtGeometryYes);
+
+ we_changed_size = Layout(lw, !parent_wants_w, !parent_wants_h, &nw, &nh);
+ our_idea->request_mode |= (CWWidth | CWHeight);
+ our_idea->width = nw;
+ our_idea->height = nh;
+
+ if (we_changed_size)
+ return (XtGeometryAlmost);
+ else
+ return (XtGeometryYes);
+} /* End PreferredGeometry */
+
+
+/* DEBUGGING FUNCTIONS */
+
+#ifdef DEBUG_TREE
+void
+ItemCheck(ListTreeWidget w, ListTreeItem * item)
+{
+ ListTreeItem *p;
+ char text[1024];
+
+ p = item;
+/* if (p->parent) fprintf(stderr,"%x %x \t",p,p->parent); */
+/* else fprintf(stderr,"%x 00000000 \t",p); */
+/* while (p) { fprintf(stderr," "); p=p->parent; } */
+/* p=item; */
+/* while (p) { */
+/* fprintf(stderr,"%s/",p->text); */
+/* p=p->parent; */
+/* } */
+/* fprintf(stderr,"\n"); */
+
+ if (strcmp(item->text, "pixmaps") == 0) {
+ fprintf(stderr, "parent: %x\n", item->parent);
+ fprintf(stderr, "firstchild: %x\n", item->firstchild);
+ fprintf(stderr, "prevsibling: %x\n", item->prevsibling);
+ fprintf(stderr, "nextsibling: %x\n", item->nextsibling);
+ }
+}
+
+void
+ChildrenCheck(ListTreeWidget w, ListTreeItem * item)
+{
+ while (item) {
+ ItemCheck(w, item);
+ if (item->firstchild)
+ ChildrenCheck(w, item->firstchild);
+ item = item->nextsibling;
+ }
+}
+
+void
+TreeCheck(ListTreeWidget w, char *txt)
+{
+ ListTreeItem *item;
+
+ fprintf(stderr, "\n\n%s\n", txt);
+ item = w->list.first;
+ while (item) {
+ ItemCheck(w, item);
+ if (item->firstchild)
+ ChildrenCheck(w, item->firstchild);
+ item = item->nextsibling;
+ }
+}
+#else
+#define TreeCheck(a,b)
+#endif
+
+/* Highlighting Utilities ----------------------------------------------- */
+
+static void
+HighlightItem(ListTreeWidget w, ListTreeItem * item, Boolean state, Boolean draw)
+{
+ if (item) {
+ if (item == w->list.highlighted && !state) {
+ w->list.highlighted = NULL;
+ if (draw)
+ DrawItemHighlightClear(w, item);
+ }
+ else if (state != item->highlighted) {
+ /* printf("Highlighting '%s' state=%d x=%d y=%d\n", item->text, draw, item->x, item->ytext); */
+ item->highlighted = state;
+ if (draw)
+ DrawItemHighlightClear(w, item);
+ }
+ }
+}
+
+static void
+HighlightChildren(ListTreeWidget w, ListTreeItem * item, Boolean state, Boolean draw)
+{
+ while (item) {
+ HighlightItem(w, item, state, draw);
+ if (item->firstchild) {
+ Boolean drawkids;
+
+ if (item->open)
+ drawkids = draw;
+ else
+ drawkids = False;
+ HighlightChildren(w, item->firstchild, state, drawkids);
+ }
+ item = item->nextsibling;
+ }
+}
+
+static void
+HighlightAll(ListTreeWidget w, Boolean state, Boolean draw)
+{
+ ListTreeItem *item;
+
+ item = w->list.first;
+ while (item) {
+ HighlightItem(w, item, state, draw);
+ if (item->firstchild) {
+ Boolean drawkids;
+
+ if (item->open)
+ drawkids = draw;
+ else
+ drawkids = False;
+ HighlightChildren(w, item->firstchild, state, drawkids);
+ }
+ item = item->nextsibling;
+ }
+}
+
+static void
+HighlightVisibleChildren(ListTreeWidget w, ListTreeItem * item, Boolean state, Boolean draw)
+{
+ while (item) {
+ HighlightItem(w, item, state, draw);
+ if (item->firstchild && item->open) {
+ HighlightVisibleChildren(w, item->firstchild, state, draw);
+ }
+ item = item->nextsibling;
+ }
+}
+
+static void
+HighlightAllVisible(ListTreeWidget w, Boolean state, Boolean draw)
+{
+ ListTreeItem *item;
+
+ item = w->list.first;
+ while (item) {
+ HighlightItem(w, item, state, draw);
+ if (item->firstchild && item->open) {
+ HighlightVisibleChildren(w, item->firstchild, state, draw);
+ }
+ item = item->nextsibling;
+ }
+}
+
+static void
+AddItemToReturnList(ListTreeWidget w, ListTreeItem * item,int loc)
+{
+ if (loc>=w->list.ret_item_alloc) {
+ w->list.ret_item_alloc+=ListTreeRET_ALLOC;
+ w->list.ret_item_list=(ListTreeItem **)XtRealloc((char *)w->list.ret_item_list,w->list.ret_item_alloc*sizeof(ListTreeItem *));
+ }
+ w->list.ret_item_list[loc]=item;
+}
+
+static void
+MultiAddToReturn(ListTreeWidget w, ListTreeItem * item, ListTreeMultiReturnStruct * ret)
+{
+ AddItemToReturnList(w,item,ret->count);
+ ret->items=w->list.ret_item_list;
+ ret->count++;
+}
+
+static void
+HighlightCount(ListTreeWidget w, ListTreeItem * item, ListTreeMultiReturnStruct * ret)
+{
+ while (item) {
+ if (item->highlighted)
+ MultiAddToReturn(w,item,ret);
+ if (item->firstchild && item->open)
+ HighlightCount(w,item->firstchild,ret);
+ item = item->nextsibling;
+ }
+}
+
+static void
+MakeMultiCallbackStruct(ListTreeWidget w,ListTreeMultiReturnStruct * ret)
+{
+ ListTreeItem *item;
+
+ ret->items=NULL;
+ ret->count = 0;
+ item = w->list.first;
+ while (item) {
+ if (item->highlighted)
+ MultiAddToReturn(w,item,ret);
+ if (item->firstchild && item->open)
+ HighlightCount(w,item->firstchild,ret);
+ item = item->nextsibling;
+ }
+}
+
+static void
+HighlightDoCallback(ListTreeWidget w)
+{
+ ListTreeMultiReturnStruct ret;
+
+ if (w->list.HighlightCallback) {
+ MakeMultiCallbackStruct(w,&ret);
+ XtCallCallbacks((Widget) w, XtNhighlightCallback, &ret);
+ }
+}
+
+/* Events ------------------------------------------------------------------ */
+
+
+static ListTreeReturnStruct *
+MakeV1CallbackStruct(w, item)
+ListTreeWidget w;
+ListTreeItem *item;
+{
+ ListTreeItem *parent;
+ ListTreeReturnStruct *ret;
+ int count, size;
+ char *ptr;
+
+ TreeCheck(w, "in MakeV1CallbackStruct");
+ count = 1;
+ parent = item;
+ while (parent->parent) {
+ parent = parent->parent;
+ count++;
+ }
+ size = sizeof(ListTreeReturnStruct) + ((count + 1) * sizeof(ListTreeItem *));
+ ptr = (char *) XtMalloc(size);
+ ret = (ListTreeReturnStruct *) ptr;
+ ret->path = (ListTreeItem **) (ptr +
+ (((sizeof(ListTreeReturnStruct) +
+ sizeof(ListTreeItem *) - 1) /
+ sizeof(ListTreeItem *)) *
+ sizeof(ListTreeItem *)));
+/* fprintf(stderr,"ret=%x ret->path=%x\n",ret,ret->path); */
+ ret->item = item;
+ ret->count = count;
+ ret->open = item->open;
+ while (count > 0) {
+ count--;
+ ret->path[count] = item;
+ item = item->parent;
+ }
+
+ TreeCheck(w, "exiting MakeV1CallbackStruct");
+ return ret;
+}
+
+/* Do the historical callbacks. After Further Review, I don't really
+ like requiring the user to free the data. But, I don't want to
+ break everybody's code, so I will mark these routines as HISTORICAL.
+
+ MIGRATE TO THE NEW CALLBACKS! */
+static void
+HistoricalCallbacks(ListTreeWidget w)
+{
+ ListTreeReturnStruct *ret;
+
+ if (w->list.PathCallback) {
+ ret = MakeV1CallbackStruct(w, w->list.timer_item);
+ if (w->list.timer_item->firstchild)
+ ret->reason = XtBRANCH;
+ else
+ ret->reason = XtLEAF;
+ XtCallCallbacks((Widget) w, XtNpathCallback, (XtPointer) ret);
+ }
+ if (w->list.BranchCallback && w->list.timer_item->firstchild) {
+ ret = MakeV1CallbackStruct(w, w->list.timer_item);
+ ret->reason = XtBRANCH;
+ XtCallCallbacks((Widget) w, XtNbranchCallback, (XtPointer) ret);
+ }
+ else if (w->list.LeafCallback && !w->list.timer_item->firstchild) {
+ ret = MakeV1CallbackStruct(w, w->list.timer_item);
+ ret->reason = XtLEAF;
+ XtCallCallbacks((Widget) w, XtNleafCallback, (XtPointer) ret);
+ }
+}
+
+static void
+MakeActivateCallbackStruct(ListTreeWidget w, ListTreeItem *item,ListTreeActivateStruct *ret)
+{
+ int count;
+ ListTreeItem *parent;
+
+ count = 1;
+ parent = item;
+ while (parent->parent) {
+ parent = parent->parent;
+ count++;
+ }
+
+ ret->item = item;
+ ret->count = count;
+ ret->open = item->open;
+ if (item->firstchild)
+ ret->reason = XtBRANCH;
+ else
+ ret->reason = XtLEAF;
+ while (count > 0) {
+ count--;
+ AddItemToReturnList(w,item,count);
+ item = item->parent;
+ }
+ ret->path=w->list.ret_item_list;
+}
+
+static void
+SelectDouble(ListTreeWidget w)
+{
+ ListTreeActivateStruct ret;
+
+ TreeCheck(w, "in SelectDouble");
+ if (w->list.timer_item) {
+ w->list.timer_type=TIMER_DOUBLE;
+ w->list.timer_item->open = !w->list.timer_item->open;
+ w->list.highlighted = w->list.timer_item;
+ HighlightAll(w, False, True);
+ w->list.timer_item->highlighted = True;
+ DrawAll(w);
+
+ if (w->list.ActivateCallback) {
+ MakeActivateCallbackStruct(w, w->list.timer_item,&ret);
+ XtCallCallbacks((Widget) w, XtNactivateCallback, (XtPointer) &ret);
+ }
+
+ HistoricalCallbacks(w);
+ }
+ TreeCheck(w, "exiting SelectDouble");
+}
+
+/* ARGSUSED */
+static void
+SelectSingle(XtPointer client_data, XtIntervalId * idp)
+{
+ ListTreeWidget w = (ListTreeWidget) client_data;
+
+ w->list.timer_id = (XtIntervalId) 0;
+/*
+ if (w->list.timer_x<w->list.timer_item->x) {
+*/
+ SelectDouble(w);
+/*
+ }
+ else {
+ HighlightAll(w, False, True);
+ HighlightItem(w, w->list.timer_item, True, True);
+ if (w->list.timer_type!=TIMER_CLEAR)
+ HighlightDoCallback(w);
+ w->list.timer_type=TIMER_SINGLE;
+ }
+*/
+}
+
+/* ARGSUSED */
+static void
+Select(aw, event, params, num_params)
+Widget aw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeWidget w = (ListTreeWidget) aw;
+
+ w->list.timer_type=TIMER_WAITING;
+ w->list.timer_item = GetItem(w, event->xbutton.y);
+ w->list.timer_x=event->xbutton.x;
+ w->list.timer_y=event->xbutton.y;
+ if (!w->list.timer_item) {
+ if (w->list.timer_id) {
+ XtRemoveTimeOut(w->list.timer_id);
+ w->list.timer_id = (XtIntervalId) 0;
+ }
+ }
+ else {
+ if (w->list.timer_id) {
+ XtRemoveTimeOut(w->list.timer_id);
+ w->list.timer_id = (XtIntervalId) 0;
+ SelectDouble(w);
+ }
+ else {
+ w->list.timer_id = XtAppAddTimeOut(
+ XtWidgetToApplicationContext((Widget) w),
+ (unsigned long) w->list.multi_click_time,
+ SelectSingle,
+ (XtPointer) w);
+
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+Extend(aw, event, params, num_params)
+Widget aw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeItem *item;
+ ListTreeWidget w = (ListTreeWidget) aw;
+ int y, yend;
+
+/* If we are waiting for a double click, return before doing anything */
+ if (w->list.timer_id)
+ return;
+
+/* We need the timer_item to be pointing to the first selection in this */
+/* group. If we got here without it being set, something is very wrong. */
+ if (!w->list.timer_item)
+ return;
+
+ y = w->list.timer_y;
+ yend = event->xbutton.y;
+ item = GetItem(w, y);
+ if (y < yend) {
+ while (item && y < yend && y < w->core.height) {
+ if (item) {
+ HighlightItem(w, item, True, True);
+ y += item->height;
+ }
+ item = GetItem(w, y);
+ }
+ }
+ else {
+ while (item && y > yend && y > 0) {
+ if (item) {
+ HighlightItem(w, item, True, True);
+ y -= item->height;
+ }
+ item = GetItem(w, y);
+ }
+ }
+/* HighlightDoCallback(w); */
+}
+
+/* ARGSUSED */
+static void
+Unset(aw, event, params, num_params)
+Widget aw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeItem *item;
+ ListTreeWidget w = (ListTreeWidget) aw;
+
+ item = GetItem(w, event->xbutton.y);
+ if (item) {
+/* item->open=False; */
+/* lw->list.highlighted=item; */
+/* DrawAll(lw); */
+/* ListTreeDelete(lw,item); */
+ }
+}
+
+/* ARGSUSED */
+static void
+Notify(aw, event, params, num_params)
+Widget aw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeWidget w = (ListTreeWidget) aw;
+ ListTreeItem *item;
+
+
+ /* don't call highlightCallback if we are waiting for a double click */
+/*
+ if (w->list.timer_id) {
+ }
+ else if (w->list.timer_type==TIMER_WAITING) {
+*/
+ HighlightAll(w, False, True);
+ item = GetItem(w, event->xbutton.y);
+ HighlightItem(w, item, True, True);
+ HighlightDoCallback(w);
+ w->list.timer_type=TIMER_CLEAR;
+/*
+ }
+*/
+}
+
+/* ListTree private drawing functions */
+
+static void
+DrawItemHighlight(w, item)
+ListTreeWidget w;
+ListTreeItem *item;
+{
+ int width;
+
+ if (item->highlighted || item == w->list.highlighted) {
+ width = w->core.width - item->x;
+ XFillRectangle(XtDisplay(w), XtWindow(w),
+ w->list.drawGC,
+ item->x, item->ytext,
+ width, FontHeight(w->list.font));
+ XDrawString(XtDisplay(w), XtWindow(w), w->list.highlightGC,
+ item->x, item->ytext + FontAscent(w->list.font),
+ item->text, item->length);
+ }
+ else {
+ XDrawString(XtDisplay(w), XtWindow(w), w->list.drawGC,
+ item->x, item->ytext + FontAscent(w->list.font),
+ item->text, item->length);
+ }
+}
+
+static void
+DrawItemHighlightClear(w, item)
+ListTreeWidget w;
+ListTreeItem *item;
+{
+ int width;
+
+ width = w->core.width - item->x;
+ if (item->highlighted || item == w->list.highlighted) {
+ XFillRectangle(XtDisplay(w), XtWindow(w),
+ w->list.drawGC,
+ item->x, item->ytext,
+ width, FontHeight(w->list.font));
+ XDrawString(XtDisplay(w), XtWindow(w), w->list.highlightGC,
+ item->x, item->ytext + FontAscent(w->list.font),
+ item->text, item->length);
+ }
+ else {
+ XFillRectangle(XtDisplay(w), XtWindow(w),
+ w->list.highlightGC,
+ item->x, item->ytext,
+ width, FontHeight(w->list.font));
+ XDrawString(XtDisplay(w), XtWindow(w), w->list.drawGC,
+ item->x, item->ytext + FontAscent(w->list.font),
+ item->text, item->length);
+ }
+}
+
+static void
+DrawItem(w, draw, item, x, y, xroot, yroot, retwidth, retheight)
+ListTreeWidget w;
+Boolean draw;
+ListTreeItem *item;
+int x, y;
+int *xroot, *yroot, *retwidth, *retheight;
+{
+ int height, xpix, ypix, xbranch, ybranch, xtext, ytext, yline;
+ Pixinfo *pix;
+
+/* Select the pixmap to use, if any */
+ if (item->firstchild) {
+ if (item->open)
+ pix = &w->list.Open;
+ else
+ pix = &w->list.Closed;
+ }
+ else {
+ if (item->open)
+ pix = &w->list.LeafOpen;
+ else
+ pix = &w->list.Leaf;
+ }
+
+/* Compute the height of this line */
+ height = FontHeight(w->list.font);
+ xpix = x - w->list.pixWidth + pix->xoff;
+ xtext = x + (int) w->list.HSpacing;
+ if (pix) {
+ if (pix->height > height) {
+ ytext = y + ((pix->height - height) / 2);
+ height = pix->height;
+ ypix = y;
+ }
+ else {
+ ytext = y;
+ ypix = y + ((height - pix->height) / 2);
+ }
+ xbranch = xpix + (w->list.pixWidth / 2);
+ ybranch = ypix + pix->height;
+ yline = ypix + (pix->height / 2);
+ }
+ else {
+ ypix = ytext = y;
+ xbranch = xpix + (w->list.pixWidth / 2);
+ yline = ybranch = ypix + (height / 2);
+ yline = ypix + (height / 2);
+ }
+
+/* Save the basic graphics info for use by other functions */
+ item->x = xtext;
+ item->y = y;
+ item->ytext = ytext;
+ item->height = height;
+
+ if ((*xroot >= 0) &&
+ ((*yroot >= w->list.exposeTop && *yroot <= w->list.exposeBot) ||
+ (yline >= w->list.exposeTop && yline <= w->list.exposeBot) ||
+ (*yroot < w->list.exposeTop && yline > w->list.exposeBot)))
+ XDrawLine(XtDisplay(w), XtWindow(w), w->list.drawGC,
+ *xroot, *yroot,
+ *xroot, yline);
+ if (draw && y >= w->list.exposeTop && y <= w->list.exposeBot) {
+ if (*xroot >= 0)
+ XDrawLine(XtDisplay(w), XtWindow(w), w->list.drawGC,
+ *xroot, yline,
+ xbranch, yline);
+ if (pix && pix->pix)
+ XCopyArea(XtDisplay(w), pix->pix, XtWindow(w),
+ w->list.drawGC,
+ 0, 0, pix->width, pix->height,
+ xpix, ypix);
+/*if (1) { */
+/*ListTreeItem *p; */
+/*char text[1024]; */
+/**/
+/*p=item;*/
+/*if (p->parent) printf("%x %x \t",p,p->parent); */
+/*else printf("%x 00000000 \t",p); */
+/*while (p) { printf(" "); p=p->parent; } */
+/*p=item; */
+/*while (p) { */
+/*printf("%s/",p->text); */
+/*p=p->parent; */
+/*} */
+/*printf("\n"); */
+/*} */
+ DrawItemHighlight(w, item);
+ }
+ *xroot = xbranch;
+ *yroot = ybranch;
+ *retwidth = FontTextWidth(w->list.font, item->text);
+ *retheight = height;
+}
+
+static int
+DrawChildren(w, draw, item, x, y, xroot, yroot)
+ListTreeWidget w;
+Boolean draw;
+ListTreeItem *item;
+int x, y, xroot, yroot;
+{
+ int width, height;
+ int xbranch, ybranch;
+
+ x += (int) w->list.Indent + w->list.pixWidth;
+ while (item) {
+ xbranch = xroot;
+ ybranch = yroot;
+ DrawItem(w, draw, item, x, y, &xbranch, &ybranch, &width, &height);
+
+ width += x + (int) w->list.HSpacing + (int) w->list.Margin;
+
+ if (width > w->list.preferredWidth)
+ w->list.preferredWidth = width;
+
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open))
+ y = DrawChildren(w, draw, item->firstchild,
+ x, y, xbranch, ybranch);
+
+ item = item->nextsibling;
+ }
+ return y;
+}
+
+static void
+Draw(w, draw, yevent, hevent)
+ListTreeWidget w;
+Boolean draw;
+int yevent, hevent;
+{
+ int x, y, height, width;
+ int xbranch, ybranch;
+ ListTreeItem *item;
+ int saveheight, savewidth;
+
+ TreeCheck(w, "Draw");
+#ifdef DEBUG_GEOM
+ printf("Draw: y=%d h=%d\n", yevent, hevent);
+#endif
+/* Overestimate the expose region to be sure to draw an item that gets */
+/* cut by the region */
+ w->list.exposeTop = yevent - FontHeight(w->list.font);
+ w->list.exposeBot = yevent + hevent + FontHeight(w->list.font);
+ saveheight = w->list.preferredHeight;
+ savewidth = w->list.preferredWidth;
+ w->list.preferredWidth = w->list.preferredHeight = 2;
+
+ x = (int) w->list.Margin + w->list.pixWidth;
+ y = (int) w->list.Margin;
+ item = w->list.first;
+ while (item) {
+ xbranch = -1;
+ DrawItem(w, draw, item, x, y, &xbranch, &ybranch, &width, &height);
+
+ width += x + (int) w->list.HSpacing + (int) w->list.Margin;
+
+ if (width > w->list.preferredWidth)
+ w->list.preferredWidth = width;
+
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open))
+ y = DrawChildren(w, draw, item->firstchild,
+ x, y, xbranch, ybranch);
+
+ item = item->nextsibling;
+ }
+ w->list.preferredHeight = y + (int) w->list.Margin;
+ if (draw && (saveheight != w->list.preferredHeight ||
+ savewidth != w->list.preferredWidth))
+ ChangeSize(w);
+}
+
+
+static void
+DrawAll(w)
+ListTreeWidget w;
+{
+ XClearWindow(XtDisplay((Widget) w), XtWindow((Widget) w));
+ Draw(w, (Boolean) True, 0, (int) w->core.height);
+}
+
+
+/* Private Functions --------------------------------------------------------- */
+
+
+/* This function removes the specified item from the linked list. It does */
+/* not do anything with the data contained in the item, though. */
+static void
+RemoveReference(w, item)
+ListTreeWidget w;
+ListTreeItem *item;
+{
+
+/* If there exists a previous sibling, just skip over item to be dereferenced */
+ if (item->prevsibling) {
+ item->prevsibling->nextsibling = item->nextsibling;
+ if (item->nextsibling)
+ item->nextsibling->prevsibling = item->prevsibling;
+ }
+/* If not, then the deleted item is the first item in some branch. */
+ else {
+ if (item->parent)
+ item->parent->firstchild = item->nextsibling;
+ else
+ w->list.first = item->nextsibling;
+ if (item->nextsibling)
+ item->nextsibling->prevsibling = NULL;
+ }
+}
+
+static void
+DeleteChildren(w, item)
+ListTreeWidget w;
+ListTreeItem *item;
+{
+ ListTreeItem *sibling;
+
+ while (item) {
+ if (item->firstchild) {
+ DeleteChildren(w, item->firstchild);
+ item->firstchild = NULL;
+ }
+ sibling = item->nextsibling;
+ XtFree((char *) item->text);
+ XtFree((char *) item);
+ item = sibling;
+ }
+}
+
+static void
+InsertChild(w, parent, item)
+ListTreeWidget w;
+ListTreeItem *parent;
+ListTreeItem *item;
+{
+ ListTreeItem *i;
+
+ item->parent = parent;
+ item->nextsibling = item->prevsibling = NULL;
+ if (parent) {
+ if (parent->firstchild) {
+ i = parent->firstchild;
+ while (i->nextsibling) {
+ i = i->nextsibling;
+ }
+ i->nextsibling = item;
+ item->prevsibling = i;
+ }
+ else {
+ parent->firstchild = item;
+ }
+
+ }
+ else { /* if parent==NULL, this is a top level entry */
+ if (w->list.first) {
+ i = w->list.first;
+ while (i->nextsibling) {
+ i = i->nextsibling;
+ }
+ i->nextsibling = item;
+ item->prevsibling = i;
+ }
+ else {
+ w->list.first = item;
+ }
+ }
+}
+
+/* Insert a list of ALREADY LINKED children into another list */
+static void
+InsertChildren(w, parent, item)
+ListTreeWidget w;
+ListTreeItem *parent;
+ListTreeItem *item;
+{
+ ListTreeItem *next, *newnext;
+
+/* while (item) { */
+/* next=item->nextsibling; */
+/* InsertChild(w,parent,item); */
+/* item=next; */
+/* } */
+/* return; */
+
+
+/* Save the reference for the next item in the new list */
+ next = item->nextsibling;
+
+/* Insert the first item in the new list into the existing list */
+ InsertChild(w, parent, item);
+
+/* The first item is inserted, with its prev and next siblings updated */
+/* to fit into the existing list. So, save the existing list reference */
+ newnext = item->nextsibling;
+
+/* Now, mark the first item's next sibling to point back to the new list */
+ item->nextsibling = next;
+
+/* Mark the parents of the new list to the new parent. The order of the */
+/* rest of the new list should be OK, and the second item should still */
+/* point to the first, even though the first was reparented. */
+ while (item->nextsibling) {
+ item->parent = parent;
+ item = item->nextsibling;
+ }
+
+/* Fit the end of the new list back into the existing list */
+ item->nextsibling = newnext;
+ if (newnext)
+ newnext->prevsibling = item;
+}
+
+static int
+SearchChildren(w, item, y, findy, finditem)
+ListTreeWidget w;
+ListTreeItem *item;
+ListTreeItem **finditem;
+int y, findy;
+{
+ int height;
+ Pixinfo *pix;
+
+ while (item) {
+/* Select the pixmap to use, if any */
+ if (item->firstchild) {
+ if (item->open)
+ pix = &w->list.Open;
+ else
+ pix = &w->list.Closed;
+ }
+ else {
+ if (item->open)
+ pix = &w->list.LeafOpen;
+ else
+ pix = &w->list.Leaf;
+ }
+
+/* Compute the height of this line */
+ height = FontHeight(w->list.font);
+ if (pix && pix->height > height)
+ height = pix->height;
+
+ if (findy >= y && findy <= y + height) {
+ *finditem = item;
+ return -1;
+ }
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open)) {
+ y = SearchChildren(w, item->firstchild,
+ y, findy, finditem);
+ if (*finditem)
+ return -1;
+ }
+ item = item->nextsibling;
+ }
+ return y;
+}
+
+static ListTreeItem *
+GetItem(w, findy)
+ListTreeWidget w;
+int findy;
+{
+ int y, height;
+ ListTreeItem *item, *finditem;
+ Pixinfo *pix;
+
+ TreeCheck(w, "in GetItem");
+ y = (int) w->list.Margin;
+ item = w->list.first;
+ finditem = NULL;
+ while (item && !finditem) {
+/* Select the pixmap to use, if any */
+ if (item->firstchild) {
+ if (item->open)
+ pix = &w->list.Open;
+ else
+ pix = &w->list.Closed;
+ }
+ else {
+ if (item->open)
+ pix = &w->list.LeafOpen;
+ else
+ pix = &w->list.Leaf;
+ }
+
+/* Compute the height of this line */
+ height = FontHeight(w->list.font);
+ if (pix && pix->height > height)
+ height = pix->height;
+
+ if (findy >= y && findy <= y + height)
+ return item;
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open)) {
+ y = SearchChildren(w, item->firstchild,
+ y, findy, &finditem);
+/* if (finditem) return finditem; */
+ }
+ item = item->nextsibling;
+ }
+ TreeCheck(w, "exiting GetItem");
+ return finditem;
+}
+
+static int
+SearchPosition(w, item, y, finditem, found)
+ListTreeWidget w;
+ListTreeItem *item, *finditem;
+int y;
+Boolean *found;
+{
+ int height;
+ Pixinfo *pix;
+
+ while (item) {
+/* printf("Checking y=%d item=%s\n",y,item->text); */
+ if (item == finditem) {
+ *found = True;
+ return y;
+ }
+
+/* Select the pixmap to use, if any */
+ if (item->firstchild) {
+ if (item->open)
+ pix = &w->list.Open;
+ else
+ pix = &w->list.Closed;
+ }
+ else {
+ if (item->open)
+ pix = &w->list.LeafOpen;
+ else
+ pix = &w->list.Leaf;
+ }
+
+/* Compute the height of this line */
+ height = FontHeight(w->list.font);
+ if (pix && pix->height > height)
+ height = pix->height;
+
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open)) {
+ y = SearchPosition(w, item->firstchild, y, finditem, found);
+ if (*found)
+ return y;
+ }
+ item = item->nextsibling;
+ }
+ return y;
+}
+
+static Position
+GetPosition(w, finditem)
+ListTreeWidget w;
+ListTreeItem *finditem;
+{
+ int y, height;
+ ListTreeItem *item;
+ Pixinfo *pix;
+ Boolean found;
+
+ TreeCheck(w, "in GetPosition");
+ y = (int) w->list.Margin;
+ item = w->list.first;
+ found = False;
+ while (item && item != finditem) {
+
+/* printf("Checking y=%d item=%s\n",y,item->text); */
+/* Select the pixmap to use, if any */
+ if (item->firstchild) {
+ if (item->open)
+ pix = &w->list.Open;
+ else
+ pix = &w->list.Closed;
+ }
+ else {
+ if (item->open)
+ pix = &w->list.LeafOpen;
+ else
+ pix = &w->list.Leaf;
+ }
+
+/* Compute the height of this line */
+ height = FontHeight(w->list.font);
+ if (pix && pix->height > height)
+ height = pix->height;
+
+ y += height + (int) w->list.VSpacing;
+ if ((item->firstchild) && (item->open)) {
+ y = SearchPosition(w, item->firstchild, y, finditem, &found);
+ if (found)
+ return (Position) y;
+ }
+ item = item->nextsibling;
+ }
+ TreeCheck(w, "exiting GetPosition");
+ if (item != finditem)
+ y = 0;
+ return (Position) y;
+}
+
+
+#ifdef USE_RDD
+/* --------------------------------------------------------------------------
+ ** ListTree drag & drop operations
+ */
+
+/* ARGSUSED */
+static void
+StartDrag(w, event, params, num_params)
+Widget w;
+XButtonEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeItem *item;
+ ListTreeWidget lw = (ListTreeWidget) w;
+ static Pixmap pixmap;
+ Display *dpy = XtDisplay(w);
+ static Dimension wid = 40, hgt = 40;
+ static GC gc;
+
+ item = lw->list.highlighted;
+ if (item) {
+ printf("Drag %s\n", item->text);
+ }
+
+ rddStartAction(w, event, params, num_params); /* then use default action */
+}
+
+/* ARGSUSED */
+static void
+EndDrag(w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeItem *item;
+ ListTreeWidget lw = (ListTreeWidget) w;
+ ListTreeReturnStruct *ret;
+
+ item = lw->list.highlighted;
+ if (item) {
+ printf("Ending %s\n", item->text);
+
+ ret = MakeV1CallbackStruct(w, item);
+ rddSetDropDataType(ret, sizeof(ListTreeReturnStruct),
+ RDD_LISTTREE_TYPE);
+
+ /* then use default action */
+ rddDropAction(w, event, params, num_params);
+ }
+}
+
+/* ARGSUSED */
+void
+ListTreeHighlightDrop(w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ ListTreeItem *item;
+ ListTreeWidget lw = (ListTreeWidget) w;
+
+ if (event && event->xbutton.state) {
+ item = GetItem(lw, event->xbutton.y);
+ if (item) {
+ printf("highlighting %d,%d item=%s\n",
+ event->xbutton.x, event->xbutton.y, item->text);
+ if (lw->list.drop_highlighted)
+ XDrawRectangle(XtDisplay(w), XtWindow(w),
+ lw->list.eorGC,
+ lw->list.drop_highlighted->x,
+ lw->list.drop_highlighted->ytext,
+ FontTextWidth(lw->list.font, lw->list.drop_highlighted->text),
+ FontHeight(lw->list.font));
+ XDrawRectangle(XtDisplay(w), XtWindow(w),
+ lw->list.eorGC,
+ item->x, item->ytext,
+ FontTextWidth(lw->list.font, item->text),
+ FontHeight(lw->list.font));
+ lw->list.drop_highlighted = item;
+ }
+ }
+ else if (lw->list.drop_highlighted) {
+ XDrawRectangle(XtDisplay(w), XtWindow(w),
+ lw->list.eorGC,
+ lw->list.drop_highlighted->x,
+ lw->list.drop_highlighted->ytext,
+ FontTextWidth(lw->list.font, lw->list.drop_highlighted->text),
+ FontHeight(lw->list.font));
+ lw->list.drop_highlighted = NULL;
+ }
+}
+
+
+ListTreeReturnStruct *
+ListTreeGetDrop(Widget w)
+{
+ ListTreeWidget lw = (ListTreeWidget) w;
+ ListTreeReturnStruct *ret;
+
+ if (lw->list.drop_highlighted) {
+ ret = MakeV1CallbackStruct(w, lw->list.drop_highlighted);
+ ListTreeHighlightDrop(w, NULL, NULL, 0);
+ }
+ else
+ ret = NULL;
+ return ret;
+}
+#endif
+
+/* Public Functions --------------------------------------------------------- */
+
+void
+ListTreeRefresh(ListTreeWidget w)
+{
+ if (XtIsRealized((Widget) w) && w->list.Refresh)
+ DrawAll(w);
+}
+
+void
+ListTreeRefreshOff(ListTreeWidget w)
+{
+ w->list.Refresh = False;
+}
+
+void
+ListTreeRefreshOn(ListTreeWidget w)
+{
+ w->list.Refresh = True;
+ ListTreeRefresh(w);
+}
+
+ListTreeItem *
+ListTreeAdd(ListTreeWidget w,ListTreeItem *parent,char *string)
+{
+ ListTreeItem *item;
+ int len;
+ char *copy;
+
+ TreeCheck(w, "in ListTreeAdd");
+ len = strlen(string);
+ item = (ListTreeItem *) XtMalloc(sizeof(ListTreeItem));
+ copy = (char *) XtMalloc(len + 1);
+ strcpy(copy, string);
+ item->text = copy;
+ item->length = len;
+ item->parent = parent;
+ item->open = False;
+ item->highlighted = False;
+ item->firstchild = item->prevsibling = item->nextsibling = NULL;
+ InsertChild(w, parent, item);
+
+ ListTreeRefresh(w);
+
+ return item;
+}
+
+void
+ListTreeRenameItem(ListTreeWidget w,ListTreeItem *item,char *string)
+{
+ int len;
+ char *copy;
+
+ TreeCheck(w, "in ListTreeRename");
+ XtFree(item->text);
+ len = strlen(string);
+ copy = (char *) XtMalloc(len + 1);
+ strcpy(copy, string);
+ item->text = copy;
+ item->length = len;
+
+ ListTreeRefresh(w);
+}
+
+int
+ListTreeDelete(ListTreeWidget w,ListTreeItem *item)
+{
+ if (item->firstchild)
+ DeleteChildren(w, item->firstchild);
+ item->firstchild = NULL;
+
+ RemoveReference(w, item);
+
+ XtFree((char *) item->text);
+ XtFree((char *) item);
+
+ ListTreeRefresh(w);
+
+ return 1;
+}
+
+int
+ListTreeDeleteChildren(ListTreeWidget w,ListTreeItem *item)
+{
+ if (item->firstchild)
+ DeleteChildren(w, item->firstchild);
+ item->firstchild = NULL;
+
+ ListTreeRefresh(w);
+
+ return 1;
+}
+
+int
+ListTreeReparent(ListTreeWidget w, ListTreeItem *item,ListTreeItem *newparent)
+{
+ TreeCheck(w, "in ListTreeReparent");
+/* Remove the item from its old location. */
+ RemoveReference(w, item);
+
+/* The item is now unattached. Reparent it. */
+ InsertChild(w, newparent, item);
+
+ ListTreeRefresh(w);
+
+ return 1;
+}
+
+int
+ListTreeReparentChildren(ListTreeWidget w, ListTreeItem *item,ListTreeItem *newparent)
+{
+ ListTreeItem *first;
+
+ TreeCheck(w, "in ListTreeReparentChildren");
+ if (item->firstchild) {
+ first = item->firstchild;
+ item->firstchild = NULL;
+
+ InsertChildren(w, newparent, first);
+
+ ListTreeRefresh(w);
+ return 1;
+ }
+ return 0;
+}
+
+int
+AlphabetizeItems(const void *item1, const void *item2)
+{
+ return strcmp((*((ListTreeItem **) item1))->text,
+ (*((ListTreeItem **) item2))->text);
+}
+
+int
+ListTreeUserOrderSiblings(ListTreeWidget w, ListTreeItem *item,int (*func)())
+{
+ ListTreeItem *first, *parent, **list;
+ size_t i, count, size;
+
+ TreeCheck(w, "in ListTreeUserOrderSiblings");
+/* Get first child in list; */
+ while (item->prevsibling)
+ item = item->prevsibling;
+ first = item;
+ parent = first->parent;
+
+/* Count the children */
+ count = 1;
+ while (item->nextsibling)
+ item = item->nextsibling, count++;
+ if (count <= 1)
+ return 1;
+
+ size = sizeof(ListTreeItem *);
+ list = (ListTreeItem **) XtMalloc(size * count);
+ list[0] = first;
+ count = 1;
+ while (first->nextsibling) {
+ list[count] = first->nextsibling;
+ count++;
+ first = first->nextsibling;
+ }
+
+ qsort(list, count, size, func);
+
+ list[0]->prevsibling = NULL;
+ for (i = 0; i < count; i++) {
+ if (i < count - 1)
+ list[i]->nextsibling = list[i + 1];
+ if (i > 0)
+ list[i]->prevsibling = list[i - 1];
+ }
+ list[count - 1]->nextsibling = NULL;
+ if (parent)
+ parent->firstchild = list[0];
+ else
+ w->list.first = list[0];
+ XtFree((char *) list);
+
+ ListTreeRefresh(w);
+ TreeCheck(w, "exiting ListTreeOrderSiblings");
+
+ return 1;
+}
+
+int
+ListTreeOrderSiblings(ListTreeWidget w, ListTreeItem *item)
+{
+ TreeCheck(w, "in ListTreeOrderSiblings");
+ return ListTreeUserOrderSiblings(w, item, AlphabetizeItems);
+}
+
+int
+ListTreeUserOrderChildren(ListTreeWidget w, ListTreeItem *item,int (*func)())
+{
+ ListTreeItem *first;
+
+ TreeCheck(w, "in ListTreeUserOrderChildren");
+ if (item) {
+ first = item->firstchild;
+ if (first)
+ ListTreeUserOrderSiblings(w, first, func);
+ }
+ else {
+ if (w->list.first)
+ ListTreeUserOrderSiblings(w, w->list.first, func);
+ }
+ TreeCheck(w, "exiting ListTreeUserOrderChildren");
+ return 1;
+}
+
+int
+ListTreeOrderChildren(ListTreeWidget w, ListTreeItem *item)
+{
+ ListTreeItem *first;
+
+ TreeCheck(w, "in ListTreeOrderChildren");
+ if (item) {
+ first = item->firstchild;
+ if (first)
+ ListTreeOrderSiblings(w, first);
+ }
+ else {
+ if (w->list.first)
+ ListTreeOrderSiblings(w, w->list.first);
+ }
+ TreeCheck(w, "exiting ListTreeOrderChildren");
+ return 1;
+}
+
+ListTreeItem *
+ListTreeFindSiblingName(ListTreeWidget w, ListTreeItem *item, char *name)
+{
+ ListTreeItem *first;
+
+ TreeCheck(w, "in ListTreeFindSiblingName");
+/* Get first child in list; */
+ if (item) {
+ while (item->prevsibling)
+ item = item->prevsibling;
+ first = item;
+
+ while (item) {
+ if (strcmp(item->text, name) == 0)
+ return item;
+ item = item->nextsibling;
+ }
+ return item;
+ }
+ return NULL;
+}
+
+ListTreeOpen(ListTreeWidget w, ListTreeItem *item)
+{
+ item->open = True;
+ ListTreeRefresh(w);
+}
+
+ListTreeClose(ListTreeWidget w, ListTreeItem *item)
+{
+ item->open = False;
+ ListTreeRefresh(w);
+}
+
+ListTreeOpenAll(ListTreeWidget w, ListTreeItem *start, int child_only)
+{
+ ListTreeItem *item;
+
+ /* Get first child in list; */
+ if (start == (ListTreeItem *)NULL)
+ item = w->list.first;
+ else
+ item = start;
+
+ while (item) {
+ if (item->firstchild)
+ ChildrenOpen (w, item->firstchild);
+ item->open = True;
+ item = item->nextsibling;
+ if (child_only)
+ break;
+ }
+ ListTreeRefresh(w);
+}
+
+ChildrenOpen (ListTreeWidget w, ListTreeItem *item)
+{
+ while (item) {
+ if (item->firstchild)
+ ChildrenOpen(w, item->firstchild);
+ item->open = True;
+ item = item->nextsibling;
+ }
+}
+
+
+ListTreeCloseAll(ListTreeWidget w, ListTreeItem *start, int child_only)
+{
+ ListTreeItem *item;
+
+ /* Get first child in list; */
+ if (start == (ListTreeItem *)NULL)
+ item = w->list.first;
+ else
+ item = start;
+
+ while (item) {
+ if (item->firstchild)
+ ChildrenClose (w, item->firstchild);
+ item->open = False;
+ item = item->nextsibling;
+ if (child_only)
+ break;
+ }
+ ListTreeRefresh(w);
+}
+
+ChildrenClose (ListTreeWidget w, ListTreeItem *item)
+{
+ while (item) {
+ if (item->firstchild)
+ ChildrenClose(w, item->firstchild);
+ item->open = False;
+ item = item->nextsibling;
+ }
+}
+
+
+ListTreeItem *
+ListTreeFindChildName(ListTreeWidget w, ListTreeItem *item, char *name)
+{
+ TreeCheck(w, "in ListTreeFindChildName");
+/* Get first child in list; */
+ if (item && item->firstchild) {
+ item = item->firstchild;
+ }
+ else if (!item && w->list.first){
+ item =w->list.first;
+ }
+ else item=NULL;
+
+ while (item) {
+ if (strcmp(item->text, name) == 0)
+ return item;
+ item = item->nextsibling;
+ }
+ return NULL;
+}
+
+
+ListTreeItem *
+ListTreeFindChildNameInTree(ListTreeWidget w, ListTreeItem *item, char *name)
+{
+ ListTreeItem *found = (ListTreeItem *)NULL, *ChildFind();
+
+ TreeCheck(w, "in ListTreeFindChildName");
+/* Get first child in list; */
+ if (item && item->firstchild)
+ item = item->firstchild;
+ else if (!item && w->list.first)
+ item =w->list.first;
+ else
+ item=NULL;
+
+ while (item) {
+ if (item && strcmp(item->text, name) == 0)
+ return item;
+ if (item->firstchild) {
+ found = ChildFind(w, item->firstchild, name);
+ if (found)
+ return found;
+ }
+ item = item->nextsibling;
+ }
+ return NULL;
+}
+
+ListTreeItem *
+ChildFind (ListTreeWidget w, ListTreeItem *item, char*name)
+{
+ ListTreeItem *found = (ListTreeItem *)NULL, *ChildFind();
+
+ while (item) {
+ if (item && strcmp(item->text, name) == 0)
+ return item;
+ if (item->firstchild) {
+ found = ChildFind(w, item->firstchild, name);
+ if (found)
+ return found;
+ }
+ item = item->nextsibling;
+ }
+ return NULL;
+}
+
+
+void
+ListTreeHighlightItem(ListTreeWidget w, ListTreeItem *item)
+{
+ HighlightAll(w,False,False);
+ HighlightItem(w,item,True,False);
+ ListTreeRefresh(w);
+}
+
+void
+ListTreeHighlightAll(ListTreeWidget w)
+{
+ HighlightAllVisible(w,True,False);
+ ListTreeRefresh(w);
+}
+
+void
+ListTreeClearHighlighted(ListTreeWidget w)
+{
+ HighlightAll(w,False,False);
+ ListTreeRefresh(w);
+}
+
+void
+ListTreeGetHighlighted(ListTreeWidget w,ListTreeMultiReturnStruct *ret)
+{
+ if (ret) MakeMultiCallbackStruct(w,ret);
+}
+
+void
+ListTreeSetHighlighted(ListTreeWidget w,ListTreeItem **items,int count,Boolean clear)
+{
+ if (clear) HighlightAll(w,False,False);
+ if (count<0) {
+ while (*items) {
+ HighlightItem(w,*items,True,False);
+ items++;
+ }
+ }
+ else {
+ int i;
+
+ for (i=0; i<count; i++){
+ HighlightItem(w,items[i],True,False);
+ }
+ }
+ ListTreeRefresh(w);
+}
+
+ListTreeItem *
+ListTreeFirstItem(w)
+ListTreeWidget w;
+{
+ ListTreeItem *first;
+
+/* Get first child in widget */
+ first = w->list.first;
+ return first;
+}
+
+Position
+ListTreeGetItemPosition(ListTreeWidget w, ListTreeItem *item)
+{
+ return GetPosition(w, item);
+}
+
+void
+ListTreeGetPathname(ListTreeReturnStruct * ret, char *dir)
+{
+ int count;
+
+ if (*ret->path[0]->text != '/')
+ strcpy(dir, "/");
+ else
+ strcpy(dir, "");
+ strcat(dir, ret->path[0]->text);
+ count = 1;
+ while (count < ret->count) {
+ strcat(dir, "/");
+ strcat(dir, ret->path[count]->text);
+ count++;
+ }
+}
+
+void
+ListTreeGetPathnameFromItem(ListTreeItem *item, char *dir)
+{
+ char tmppath[1024];
+
+ *dir='\0';
+ while (item) {
+ sprintf(tmppath,"/%s%s",item->text,dir);
+ strcpy(dir,tmppath);
+ item=item->parent;
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/ListTree.h b/vendor/x11iraf/obm/ObmW/ListTree.h
new file mode 100644
index 00000000..833d6d57
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ListTree.h
@@ -0,0 +1,123 @@
+/*-----------------------------------------------------------------------------
+** ListTree.c A Specialized List widget
+**
+** Public header file
+**
+** Copyright (c) 1995 Robert W. McMullen
+**
+** Permission to use, copy, modify, distribute, and sell this software and its
+** documentation for any purpose is hereby granted without fee, provided that
+** the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. The author makes no representations about the suitability
+** of this software for any purpose. It is provided "as is" without express
+** or implied warranty.
+**
+** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+** ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+** THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+** ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+** SOFTWARE.
+*/
+
+#ifndef _ListTree_H
+#define _ListTree_H
+
+#include <X11/Core.h>
+
+#define _ListTree_WIDGET_VERSION 2.0
+
+#define XtNmargin "margin"
+#define XtNindent "indent"
+#define XtNhorizontalSpacing "horizontalSpacing"
+#define XtNverticalSpacing "verticalSpacing"
+#define XtNlineWidth "lineWidth"
+#define XtNbranchPixmap "branchPixmap"
+#define XtNbranchOpenPixmap "branchOpenPixmap"
+#define XtNleafPixmap "leafPixmap"
+#define XtNleafOpenPixmap "leafOpenPixmap"
+#define XtNbranchCallback "branchCallback"
+#define XtNleafCallback "leafCallback"
+#define XtNpathCallback "pathCallback"
+#define XtNhighlightCallback "highlightCallback"
+#define XtNactivateCallback "activateCallback"
+
+#define XtBRANCH 1
+#define XtLEAF 2
+
+extern WidgetClass listtreeWidgetClass;
+
+typedef struct _ListTreeClassRec *ListTreeWidgetClass;
+typedef struct _ListTreeRec *ListTreeWidget;
+
+typedef struct _ListTreeItem {
+ Boolean open;
+ Boolean highlighted;
+ char *text;
+ int length;
+ int x,y,ytext;
+ Dimension height;
+ struct _ListTreeItem *parent,
+ *firstchild,
+ *prevsibling,*nextsibling;
+ XtPointer user_data;
+} ListTreeItem;
+
+typedef struct _ListTreeReturnStruct {
+ int reason;
+ ListTreeItem *item;
+ ListTreeItem **path;
+ int count;
+ Boolean open;
+} ListTreeReturnStruct;
+
+typedef struct _ListTreeMultiReturnStruct {
+ ListTreeItem **items;
+ int count;
+} ListTreeMultiReturnStruct;
+
+typedef struct _ListTreeActivateStruct {
+ int reason;
+ ListTreeItem *item;
+ Boolean open;
+ ListTreeItem **path;
+ int count;
+} ListTreeActivateStruct;
+
+/*
+** Public function declarations
+*/
+#ifndef _ListTree_
+#if __STDC__ || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+
+/* ListTree.c */
+void ListTreeRefresh P_((Widget w));
+void ListTreeRefreshOff P_((Widget w));
+void ListTreeRefreshOn P_((Widget w));
+ListTreeItem *ListTreeAdd P_((Widget w, ListTreeItem *parent, char *string));
+void ListTreeRenameItem P_((Widget w, ListTreeItem *item, char *string));
+int ListTreeDelete P_((Widget w, ListTreeItem *item));
+int ListTreeDeleteChildren P_((Widget w, ListTreeItem *item));
+int ListTreeReparent P_((Widget w, ListTreeItem *item, ListTreeItem *newparent));
+int ListTreeReparentChildren P_((Widget w, ListTreeItem *item, ListTreeItem *newparent));
+int ListTreeOrderSiblings P_((Widget w, ListTreeItem *item));
+int ListTreeOrderChildren P_((Widget w, ListTreeItem *item));
+ListTreeItem *ListTreeFindSiblingName P_((Widget w, ListTreeItem *item, char *name));
+ListTreeItem *ListTreeFindChildName P_((Widget w, ListTreeItem *item, char *name));
+void ListTreeHighlightItem P_((Widget w, ListTreeItem *item));
+ListTreeItem *ListTreeFirstItem P_((Widget w));
+#ifdef USE_RDD
+void ListTreeHighlightDrop P_((Widget w, XEvent *event, String *params, Cardinal *num_params));
+ListTreeReturnStruct *ListTreeGetDrop P_((Widget w));
+#endif
+
+#undef P_
+#endif
+
+#endif /* _ListTree_H */
diff --git a/vendor/x11iraf/obm/ObmW/ListTreeP.h b/vendor/x11iraf/obm/ObmW/ListTreeP.h
new file mode 100644
index 00000000..a6e369fe
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ListTreeP.h
@@ -0,0 +1,109 @@
+/*-----------------------------------------------------------------------------
+** ListTree.c A Specialized List widget
+**
+** Private header file
+**
+** Copyright (c) 1995 Robert W. McMullen
+**
+** Permission to use, copy, modify, distribute, and sell this software and its
+** documentation for any purpose is hereby granted without fee, provided that
+** the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. The author makes no representations about the suitability
+** of this software for any purpose. It is provided "as is" without express
+** or implied warranty.
+**
+** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+** ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+** THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+** ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+** SOFTWARE.
+*/
+
+#ifndef _ListTreeP_H
+#define _ListTreeP_H
+
+#include <X11/Core.h>
+
+#include "ListTree.h"
+#define ListTreeRET_ALLOC 10
+
+#define TIMER_CLEAR 0
+#define TIMER_SINGLE 1
+#define TIMER_DOUBLE 2
+#define TIMER_WAITING 3
+
+typedef struct {
+ int dummy; /* keep compiler happy with dummy field */
+} ListTreeClassPart;
+
+typedef struct _ListTreeClassRec {
+ CoreClassPart core_class;
+ ListTreeClassPart ListTree_class;
+} ListTreeClassRec;
+
+extern ListTreeClassRec listtreeClassRec;
+
+typedef struct {
+ Pixmap bitmap;
+ Pixmap pix;
+ int width,height;
+ int xoff;
+} Pixinfo;
+
+typedef struct {
+ /* Public stuff ... */
+ long foreground_pixel;
+ XFontStruct *font;
+ int NumItems;
+ Dimension HSpacing;
+ Dimension VSpacing;
+/* Dimension LabelSpacing;*/
+ Dimension Margin;
+ Dimension Indent;
+ Pixinfo Open;
+ Pixinfo Closed;
+ Pixinfo Leaf;
+ Pixinfo LeafOpen;
+ Dimension LineWidth;
+ XtCallbackList BranchCallback;
+ XtCallbackList LeafCallback;
+ XtCallbackList PathCallback;
+ XtCallbackList HighlightCallback;
+ XtCallbackList ActivateCallback;
+
+ /* Private stuff ... */
+ GC drawGC;
+ GC eraseGC;
+ GC eorGC;
+ GC highlightGC;
+ int exposeTop,exposeBot;
+ int pixWidth;
+ int preferredWidth,preferredHeight;
+ ListTreeItem *first, /* always points to a top level entry */
+ *highlighted,
+ *drop_highlighted;
+
+ XtIntervalId timer_id; /* timer for double click test */
+ ListTreeItem *timer_item; /* item to make sure both clicks */
+ /* occurred on the same item */
+ int timer_type; /* flag for type of click that just happened */
+ int timer_y;
+ int timer_x;
+ int multi_click_time;
+
+ ListTreeItem **ret_item_list;
+ int ret_item_alloc;
+
+ Boolean Refresh;
+} ListTreePart;
+
+typedef struct _ListTreeRec {
+ CorePart core;
+ ListTreePart list;
+} ListTreeRec;
+
+
+#endif /* _ListTreeP_H */
diff --git a/vendor/x11iraf/obm/ObmW/Makefile b/vendor/x11iraf/obm/ObmW/Makefile
new file mode 100644
index 00000000..ce258853
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Makefile
@@ -0,0 +1,1192 @@
+# Makefile generated by imake - do not edit!
+# $Xorg: imake.c,v 1.6 2001/02/09 02:03:15 xorgcvs Exp $
+
+# ----------------------------------------------------------------------
+# Makefile generated from "Imake.tmpl" and </tmp/IIf.rEU2JZ>
+# $Xorg: Imake.tmpl,v 1.4 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# $XFree86: xc/config/cf/Imake.tmpl,v 3.138 2002/12/10 03:20:41 dawes Exp $
+# ----------------------------------------------------------------------
+
+all::
+
+.SUFFIXES: .i
+
+# $Xorg: Imake.cf,v 1.4 2000/08/17 19:41:45 cpqbld Exp $
+
+# $XFree86: xc/config/cf/Imake.cf,v 3.80 2003/01/15 02:52:12 dawes Exp $
+
+# Keep cpp from replacing path elements containing i486/i586/i686
+
+# -----------------------------------------------------------------------
+# site-specific configuration parameters that need to come before
+# the platform-specific parameters - edit site.def to change
+
+# site: $TOG: site.sample /main/r64_final/1 1998/02/05 16:28:49 kaleb $
+
+# site: $XFree86: xc/config/cf/site.def,v 3.24 2000/06/25 20:17:29 dawes Exp $
+
+# $XFree86: xc/config/cf/xf86site.def,v 3.181 2002/02/22 21:32:33 dawes Exp $
+
+# ----------------------------------------------------------------------
+# platform-specific configuration parameters - edit linux.cf to change
+
+# platform: $Xorg: linux.cf,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+
+# platform: $XFree86: xc/config/cf/linux.cf,v 3.201tsi Exp $
+
+# operating system: Linux 2.4.29-4aslsmp i686 [ELF] (2.4.29)
+# libc: (6.3.2)
+# binutils: (213)
+
+# $Xorg: lnxLib.rules,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+# $XFree86: xc/config/cf/lnxLib.rules,v 3.43 2002/04/04 14:05:33 eich Exp $
+
+# $XFree86: xc/config/cf/xfree86.cf,v 3.439.2.1 2003/03/13 04:10:40 tsi Exp $
+
+# $Xorg: xfree86.cf,v 1.4 2000/08/17 19:41:49 cpqbld Exp $
+
+VENDORMANNAME = XFree86
+VENDORMANVERSION = `echo 4 3 0 | sed -e 's/ /./g' -e 's/^/Version\\\ /'`
+
+AFB_DEFS = -DUSE_AFB
+
+DRIVERSDKDIR = $(USRLIBDIR)/Server
+DRIVERSDKMODULEDIR = $(USRLIBDIR)/Server/modules
+DRIVERSDKINCLUDEDIR = $(USRLIBDIR)/Server/include
+
+ XF86SRC = $(SERVERSRC)/hw/xfree86
+ XF86COMSRC = $(XF86SRC)/common
+ XF86PARSERSRC = $(XF86SRC)/parser
+ XF86OSSRC = $(XF86SRC)/os-support
+ XF86DRIVERSRC = $(XF86SRC)/drivers
+ DRIVERSRC = $(XF86DRIVERSRC)
+
+ XFREE86DOCDIR = $(DOCDIR)
+ XFREE86PSDOCDIR = $(DOCPSDIR)
+ XFREE86HTMLDOCDIR = $(DOCHTMLDIR)
+XFREE86JAPANESEDOCDIR = $(DOCDIR)/Japanese
+
+# $Xorg: xf86.rules,v 1.3 2000/08/17 19:41:48 cpqbld Exp $
+
+# $XFree86: xc/config/cf/xf86.rules,v 3.33 2001/01/17 16:38:51 dawes Exp $
+
+# ----------------------------------------------------------------------
+# site-specific configuration parameters that go after
+# the platform-specific parameters - edit site.def to change
+
+# site: $TOG: site.sample /main/r64_final/1 1998/02/05 16:28:49 kaleb $
+
+# site: $XFree86: xc/config/cf/site.def,v 3.24 2000/06/25 20:17:29 dawes Exp $
+
+# ---------------------------------------------------------------------
+# Imake rules for building libraries, programs, scripts, and data files
+# rules: $Xorg: Imake.rules,v 1.3 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# rules: $XFree86: xc/config/cf/Imake.rules,v 3.112 2002/11/14 21:01:13 tsi Exp $
+
+ _NULLCMD_ = @ echo -n
+
+GLIDE2INCDIR = /usr/include/glide
+
+GLIDE3INCDIR = /usr/include/glide3
+
+GLIDE3LIBNAME = glide3
+
+TKLIBNAME =
+
+TKLIBDIR =
+
+TCLLIBNAME =
+
+TCLIBDIR =
+
+ PATHSEP = /
+ SHELL = /bin/sh -e
+
+ TOP = ../..
+ CURRENT_DIR = obm/ObmW
+
+ IMAKE = imake
+ DEPEND = gccmakedep
+ MKDIRHIER = mkdir -p
+ REVPATH = revpath
+ EXPORTLISTGEN =
+ RMAN = rman
+ RMANBASENAME = rman
+ RMANOPTIONS = -f HTML
+ CONFIGSRC = $(TOP)/config
+ IMAKESRC = $(CONFIGSRC)/imake
+ DEPENDSRC = $(CONFIGSRC)/util
+
+ INCROOT = /usr/X11R6/include
+ USRLIBDIR = /usr/X11R6/lib
+ VARDIR = /var
+ VARLIBDIR = $(VARDIR)/lib
+ SYSTEMUSRLIBDIR = /usr/lib
+ SYSTEMUSRINCDIR = /usr/include
+ SHLIBDIR = /usr/X11R6/lib
+ LINTLIBDIR = $(USRLIBDIR)/lint
+ MANPATH = /usr/X11R6/man
+ MANSOURCEPATH = $(MANPATH)/man
+ MANDIR = $(MANSOURCEPATH)1
+ LIBMANDIR = $(MANSOURCEPATH)3
+ FILEMANDIR = $(MANSOURCEPATH)5
+ MISCMANDIR = $(MANSOURCEPATH)7
+ DRIVERMANDIR = $(MANSOURCEPATH)4
+ ICONDIR = /usr/share/icons
+ XCURSORPATH = "~/.icons:/usr/share/icons:/usr/share/pixmaps"
+ LOGDIRECTORY = $(VARDIR)/log
+
+ VARRUNDIR = $(VARDIR)/run
+
+ VARDBDIR = $(VARDIR)/lib
+
+ AR = ar clq
+
+# Nice try but useless: make will inherit BOOTSTRAPCFLAGS
+# from top Makefile
+ BOOTSTRAPCFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -pipe
+
+ CC = gcc -m32
+ AS = gcc -m32 -c -x assembler
+
+.SUFFIXES: .cc
+
+ CXX = c++ -m32
+
+ CXXFILT = c++filt
+ CXXLIB =
+ CXXDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+CXXDEPENDINCLUDES =
+ CXXEXTRA_DEFINES =
+CXXEXTRA_INCLUDES =
+ CXXSTD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(CXXPROJECT_DEFINES)
+ CXXOPTIONS =
+ CXXINCLUDES = $(INCLUDES) $(TOP_INCLUDES) $(CXXEXTRA_INCLUDES)
+ CXXDEFINES = $(CXXINCLUDES) $(CXXSTD_DEFINES) $(THREADS_CXXDEFINES) $(DEFINES) $(CXXEXTRA_DEFINES)
+ CXXFLAGS = $(CXXDEBUGFLAGS) $(CXXOPTIONS) $(THREADS_CXXFLAGS) $(CXXDEFINES)
+
+ COMPRESS = compress
+ GZIPCMD = gzip
+
+ CPP = /usr/bin/cpp $(STD_CPP_DEFINES)
+ RAWCPP = /usr/bin/cpp -undef $(STD_CPP_OPTIONS)
+ PREPROCESSCMD = gcc -m32 -E $(STD_CPP_DEFINES)
+
+ INSTALL = install
+ INSTALLFLAGS = -c
+
+ LD = gcc -m32 -nostdlib
+
+ LEX = flex -l
+ M4 = m4
+ M4FLAGS =
+ LEXLIB = -lfl
+ YACC = bison -y
+ CCYACC = bison -y
+
+ LINT = lint
+
+ LINTLIBFLAG = -C
+ LINTOPTS = -axz
+ LN = ln -s
+ MAKE = make
+ MV = mv -f
+ CP = cp
+
+ RANLIB = ranlib
+
+ RANLIBINSTFLAGS =
+
+ RM = rm -f
+ PERL = perl
+ PERLOPTS =
+ MANSUFFIX = 1x
+ LIBMANSUFFIX = 3x
+ FILEMANSUFFIX = 5x
+ MISCMANSUFFIX = 7x
+ DRIVERMANSUFFIX = 4x
+ MANSRCSUFFIX = man
+ MANNEWSUFFIX = _man
+ MANDEFS = -D__apploaddir__=$(XAPPLOADDIR) -D__filemansuffix__=$(FILEMANSUFFIX) -D__libmansuffix__=$(LIBMANSUFFIX) -D__miscmansuffix__=$(MISCMANSUFFIX) -D__drivermansuffix__=$(DRIVERMANSUFFIX) -D__projectroot__=$(PROJECTROOT) $(XORGMANDEFS) $(VENDORMANDEFS)
+
+ COMPRESSMANCMD = gzip -n
+
+ TROFF = groff -Tps
+ NROFF = nroff
+ MSMACROS = -ms
+ MANMACROS = -man
+ TBL = tbl
+ EQN = eqn
+ NEQN = neqn
+ COL = col
+ COLFLAGS = -b
+
+ MODCC = gcc -m32
+
+ MODCPP = /usr/bin/cpp
+ MODCFLAGS = $(CFLAGS)
+ MODAS = gcc -m32 -c -x assembler
+ MODASFLAGS =
+
+ MODLD = gcc -m32 -nostdlib
+
+ MODLDFLAGS =
+MODLDCOMBINEFLAGS = -r
+ MODAR = ar clq
+
+ MODRANLIB = ranlib
+
+ STD_INCLUDES =
+ STD_CPP_OPTIONS = -traditional
+ STD_CPP_DEFINES = -traditional -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+ STD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+ EXTRA_LOAD_FLAGS =
+ EXTRA_LDOPTIONS =
+ EXTRA_LIBRARIES =
+ TAGS = ctags
+
+ PARALLELMFLAGS =
+
+ SHAREDCODEDEF =
+ SHLIBDEF =
+
+ SHLIBLDFLAGS = -shared $(SHLIBGLOBALSFLAGS)
+
+ PICFLAGS = -fPIC
+
+ CXXPICFLAGS = -fPIC
+
+ PROTO_DEFINES = -DFUNCPROTO=15 -DNARROWPROTO
+
+ INSTPGMFLAGS =
+
+ INSTBINFLAGS = -m 0755
+ INSTUIDFLAGS = -m 4711
+ INSTLIBFLAGS = -m 0644
+ INSTINCFLAGS = -m 0444
+ INSTMANFLAGS = -m 0444
+ INSTDATFLAGS = -m 0444
+ INSTKMEMFLAGS = -m 4711
+
+ PROJECTROOT = /usr/X11R6
+
+ CDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+ CCOPTIONS =
+
+ ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(INSTALLED_INCLUDES) $(STD_INCLUDES)
+ ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(THREADS_DEFINES) $(MODULE_DEFINES) $(DEFINES) $(EXTRA_DEFINES)
+ CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(THREADS_CFLAGS) $(MODULE_CFLAGS) $(ALLDEFINES)
+ LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) $(DEPEND_DEFINES)
+ LDPRELIB = -L$(USRLIBDIR) $(INSTALLED_LIBS)
+ LDPOSTLIB =
+ LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_LDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIBS)
+ CXXLDOPTIONS = $(CXXDEBUGFLAGS) $(CXXOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_CXXLDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIBS)
+
+ LDLIBS = $(LDPOSTLIBS) $(THREADS_LIBS) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
+
+ CCLINK = $(CC)
+
+ CXXLINK = $(CXX)
+
+ LDSTRIPFLAGS = -x
+ LDCOMBINEFLAGS = -r
+ DEPENDFLAGS =
+ DEPEND_DEFINES =
+
+# Not sure this belongs here
+ TKLIBDIR =
+ TKINCDIR =
+ TKLIBNAME =
+ TKLIBRARY = -L$(TKLIBDIR) -l$(TKLIBNAME)
+ TCLLIBDIR =
+ TCLINCDIR =
+ TCLLIBNAME =
+ TCLLIBRARY = -L$(TCLLIBDIR) -l$(TCLLIBNAME)
+
+ MACROFILE = linux.cf
+ RM_CMD = $(RM)
+
+ IMAKE_DEFINES =
+ IMAKE_WARNINGS = -Wundef
+
+ IRULESRC = $(CONFIGDIR)
+ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) $(IMAKE_WARNINGS)
+
+ ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/X11.tmpl $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) $(IRULESRC)/xfree86.cf $(IRULESRC)/xf86.rules $(IRULESRC)/xf86site.def $(IRULESRC)/host.def $(EXTRA_ICONFIGFILES)
+
+# $Xorg: X11.rules,v 1.4 2000/08/17 19:41:46 cpqbld Exp $
+
+# $XFree86: xc/config/cf/X11.rules,v 1.5 2000/11/06 19:24:00 dawes Exp $
+
+# ----------------------------------------------------------------------
+# X Window System Build Parameters and Rules
+# $Xorg: X11.tmpl,v 1.6 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# $XFree86: xc/config/cf/X11.tmpl,v 1.196.2.2 2003/09/17 05:58:15 herrb Exp $
+
+XORGRELSTRING = Release 6.6
+XORGMANNAME = X Version 11
+
+VENDORMANNAME = XFree86
+VENDORMANVERSION = `echo 4 3 0 | sed -e 's/ /./g' -e 's/^/Version\\\ /'`
+
+STICKY_DEFINES = -DHAS_STICKY_DIR_BIT
+
+FCHOWN_DEFINES = -DHAS_FCHOWN
+
+# -----------------------------------------------------------------------
+# X Window System make variables; these need to be coordinated with rules
+
+ XTOP = $(TOP)
+ BINDIR = /usr/X11R6/bin
+ BUILDINCROOT = $(TOP)/exports
+ BUILDINCDIR = $(BUILDINCROOT)/include
+ BUILDINCTOP = ../..
+ BUILDLIBDIR = $(TOP)/exports/lib
+ BUILDLIBTOP = ../..
+ BUILDBINDIR = $(TOP)/exports/bin
+ BUILDBINTOP = ../..
+ BUILDMODULEDIR = $(BUILDLIBDIR)/modules
+ BUILDMODULETOP = $(BUILDLIBTOP)/..
+ XBUILDINCROOT = $(XTOP)/exports
+ XBUILDINCDIR = $(XBUILDINCROOT)/include/X11
+ XBUILDINCTOP = ../../..
+ XBUILDBINDIR = $(XBUILDINCROOT)/bin
+ INCDIR = $(INCROOT)
+ ADMDIR = /var/log
+ LIBDIR = /usr/X11R6/lib/X11
+ LIBEXECDIR = /usr/X11R6/libexec
+ MODULEDIR = $(USRLIBDIR)/modules
+ TOP_X_INCLUDES =
+
+ ETCX11DIR = /etc/X11
+
+ CONFDIR = $(ETCX11DIR)
+
+ DOCDIR = $(LIBDIR)/doc
+ DOCHTMLDIR = $(DOCDIR)/html
+ DOCPSDIR = $(DOCDIR)/PostScript
+ FONTDIR = $(LIBDIR)/fonts
+ ENCODINGSDIR = $(FONTDIR)/encodings
+ XINITDIR = /etc/X11/xinit
+ XDMDIR = /etc/X11/xdm
+ XDMVARDIR = $(VARLIBDIR)/xdm
+ TWMDIR = $(LIBDIR)/twm
+ XSMDIR = $(LIBDIR)/xsm
+ NLSDIR = $(LIBDIR)/nls
+ XLOCALEDIR = $(LIBDIR)/locale
+ PEXAPIDIR = $(LIBDIR)/PEX
+ LBXPROXYDIR = /etc/X11/lbxproxy
+ PROXYMANAGERDIR = /etc/X11/proxymngr
+ XPRINTDIR = /etc/X11/xserver
+ XAPPLOADDIR = $(LIBDIR)/app-defaults
+ FONTCFLAGS = -t
+
+ INSTAPPFLAGS = $(INSTDATFLAGS)
+
+ RGB = $(BINDIR)/rgb
+ FONTC = $(BINDIR)/bdftopcf
+ MKFONTDIR = $(BINDIR)/mkfontdir
+ MKHTMLINDEX = $(BINDIR)/mkhtmlindex
+ UCS2ANY = $(BINDIR)/ucs2any
+ BDFTRUNCATE = $(BINDIR)/bdftruncate
+ UCSMAPPREFIX = $(FONTDIR)/util/map-
+ XCURSORGEN = $(BINDIR)/xcursorgen
+
+ HTMLINDEXCMD = HtmlIndexCmd
+
+ DOCUTILSRC = $(XTOP)/doc/util
+ CLIENTSRC = $(TOP)/clients
+ DEMOSRC = $(TOP)/demos
+ XDOCMACROS = $(DOCUTILSRC)/macros.t
+ XIDXMACROS = $(DOCUTILSRC)/indexmacros.t
+ PROGRAMSRC = $(TOP)/programs
+ LIBSRC = $(XTOP)/lib
+ FONTSRC = $(XTOP)/fonts
+ ENCODINGSSRC = $(FONTSRC)/encodings
+ INCLUDESRC = $(BUILDINCROOT)/include
+ XINCLUDESRC = $(INCLUDESRC)/X11
+ SERVERSRC = $(XTOP)/programs/Xserver
+ CONTRIBSRC = $(XTOP)/../contrib
+ UNSUPPORTEDSRC = $(XTOP)/unsupported
+ DOCSRC = $(XTOP)/doc
+ RGBSRC = $(XTOP)/programs/rgb
+ BDFTOPCFSRC = $(PROGRAMSRC)/bdftopcf
+ MKFONTDIRSRC = $(PROGRAMSRC)/mkfontdir
+ FONTSERVERSRC = $(PROGRAMSRC)/xfs
+ FONTINCSRC = $(XTOP)/include/fonts
+ EXTINCSRC = $(XTOP)/include/extensions
+ FTSOURCEDIR = $(TOP)/extras/FreeType
+ XTTSOURCEDIR = $(TOP)/extras/X-TrueType
+ MESASRCDIR = $(TOP)/extras/Mesa
+ OGLSAMPLESRCDIR = $(TOP)/extras/ogl-sample
+ PSWRAPSRC = $(XTOP)/config/pswrap
+ TRANSCOMMSRC = $(LIBSRC)/xtrans
+ TRANS_INCLUDES = -I$(TRANSCOMMSRC)
+ CONNECTION_FLAGS = -DUNIXCONN -DTCPCONN $(STICKY_DEFINES) $(FCHOWN_DEFINES)
+
+ XORGMANDEFS = -D__xorgversion__='"$(XORGRELSTRING)" "$(XORGMANNAME)"'
+ VENDORMANDEFS = -D__vendorversion__="\"Version $(VENDORMANVERSION)\" $(VENDORMANNAME)"
+
+ XENVLIBDIR = $(USRLIBDIR)
+ CLIENTENVSETUP = LD_LIBRARY_PATH=$(XENVLIBDIR)
+
+# $Xorg: lnxLib.tmpl,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+# $XFree86: xc/config/cf/lnxLib.tmpl,v 3.13 2001/01/17 16:22:32 dawes Exp $
+
+ XLIBSRC = $(LIBSRC)/X11
+
+SOXLIBREV = 6.2
+DEPXONLYLIB =
+XONLYLIB = -lX11
+
+LINTXONLY = $(LINTLIBDIR)/llib-lX11.ln
+
+ XLIBONLY = $(XONLYLIB)
+
+ XEXTLIBSRC = $(LIBSRC)/Xext
+
+SOXEXTREV = 6.4
+DEPEXTENSIONLIB =
+EXTENSIONLIB = -lXext
+
+LINTEXTENSION = $(LINTLIBDIR)/llib-lXext.ln
+
+LINTEXTENSIONLIB = $(LINTEXTENSION)
+ DEPXLIB = $(DEPEXTENSIONLIB) $(DEPXONLYLIB)
+ XLIB = $(EXTENSIONLIB) $(XONLYLIB)
+ LINTXLIB = $(LINTXONLYLIB)
+
+ XSSLIBSRC = $(LIBSRC)/Xss
+
+DEPXSSLIB = $(USRLIBDIR)/libXss.a
+XSSLIB = -lXss
+
+LINTXSS = $(LINTLIBDIR)/llib-lXss.ln
+
+ XXF86MISCLIBSRC = $(LIBSRC)/Xxf86misc
+
+DEPXXF86MISCLIB = $(USRLIBDIR)/libXxf86misc.a
+XXF86MISCLIB = -lXxf86misc
+
+LINTXXF86MISC = $(LINTLIBDIR)/llib-lXxf86misc.ln
+
+ XXF86VMLIBSRC = $(LIBSRC)/Xxf86vm
+
+DEPXXF86VMLIB = $(USRLIBDIR)/libXxf86vm.a
+XXF86VMLIB = -lXxf86vm
+
+LINTXXF86VM = $(LINTLIBDIR)/llib-lXxf86vm.ln
+
+ XXF86DGALIBSRC = $(LIBSRC)/Xxf86dga
+
+DEPXXF86DGALIB = $(USRLIBDIR)/libXxf86dga.a
+XXF86DGALIB = -lXxf86dga
+
+LINTXXF86DGA = $(LINTLIBDIR)/llib-lXxf86dga.ln
+
+ XXF86RUSHLIBSRC = $(LIBSRC)/Xxf86rush
+
+DEPXXF86RUSHLIB = $(USRLIBDIR)/libXxf86rush.a
+XXF86RUSHLIB = -lXxf86rush
+
+LINTXXF86RUSH = $(LINTLIBDIR)/llib-lXxf86rush.ln
+
+ XVLIBSRC = $(LIBSRC)/Xv
+
+SOXVREV = 1.0
+DEPXVLIB =
+XVLIB = -lXv
+
+LINTXV = $(LINTLIBDIR)/llib-lXv.ln
+
+ XVMCLIBSRC = $(LIBSRC)/XvMC
+
+DEPXVMCLIB = $(USRLIBDIR)/libXvMC.a
+XVMCLIB = -lXvMC
+
+LINTXVMC = $(LINTLIBDIR)/llib-lXvMC.ln
+
+ XINERAMALIBSRC = $(LIBSRC)/Xinerama
+
+DEPXINERAMALIB = $(USRLIBDIR)/libXinerama.a
+XINERAMALIB = -lXinerama
+
+LINTXINERAMA = $(LINTLIBDIR)/llib-lXinerama.ln
+
+ XRESLIBSRC = $(LIBSRC)/XRes
+
+DEPXRESLIB = $(USRLIBDIR)/libXRes.a
+XRESLIB = -lXRes
+
+LINTXRES = $(LINTLIBDIR)/llib-lXRes.ln
+
+ DPSLIBSRC = $(LIBSRC)/dps
+
+SODPSREV = 1.0
+DEPDPSLIB =
+DPSLIB = -ldps
+
+LINTDPS = $(LINTLIBDIR)/llib-ldps.ln
+
+ DPSTKLIBSRC = $(LIBSRC)/dpstk
+
+SODPSTKREV = 1.0
+DEPDPSTKLIB =
+DPSTKLIB = -ldpstk
+
+LINTDPSTK = $(LINTLIBDIR)/llib-ldpstk.ln
+
+ PSRESLIBSRC = $(LIBSRC)/psres
+
+SOPSRESREV = 1.0
+DEPPSRESLIB =
+PSRESLIB = -lpsres
+
+LINTPSRES = $(LINTLIBDIR)/llib-lpsres.ln
+
+ GLULIBSRC = $(LIBSRC)/GLU
+
+SOGLUREV = 1.3
+DEPGLULIB =
+GLULIB = -lGLU
+
+LINTGLU = $(LINTLIBDIR)/llib-lGLU.ln
+
+ GLXLIBSRC = $(LIBSRC)/GL
+
+SOGLREV = 1.2
+DEPGLXLIB =
+GLXLIB = -lGL
+
+LINTGLX = $(LINTLIBDIR)/llib-lGL.ln
+
+ GLWIDGETSRC = $(LIBSRC)/GLw
+
+DEPGLWLIB = $(USRLIBDIR)/libGLw.a
+GLWLIB = -lGLw
+
+LINTGLW = $(LINTLIBDIR)/llib-lGLw.ln
+
+ XRENDERLIBSRC = $(LIBSRC)/Xrender
+
+SOXRENDERREV = 1.2
+DEPXRENDERLIB =
+XRENDERLIB = -lXrender
+
+LINTXRENDER = $(LINTLIBDIR)/llib-lXrender.ln
+
+ XRANDRRLIBSRC = $(LIBSRC)/Xrandr
+
+SOXRANDRREV = 2.0
+DEPXRANDRLIB =
+XRANDRLIB = -lXrandr
+
+LINTXRANDR = $(LINTLIBDIR)/llib-lXrandr.ln
+
+ XCURSORRLIBSRC = $(LIBSRC)/Xcursor
+
+SOXCURSORREV = 1.0
+DEPXCURSORLIB =
+XCURSORLIB = -lXcursor
+
+LINTXCURSOR = $(LINTLIBDIR)/llib-lXcursor.ln
+
+ XFONTCACHELIBSRC = $(LIBSRC)/Xfontcache
+
+DEPXFONTCACHELIB = $(USRLIBDIR)/libXfontcache.a
+XFONTCACHELIB = -lXfontcache
+
+LINTXFONTCACHE = $(LINTLIBDIR)/llib-lXfontcache.ln
+
+ XAUTHSRC = $(LIBSRC)/Xau
+
+DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
+XAUTHLIB = -lXau
+
+LINTXAUTH = $(LINTLIBDIR)/llib-lXau.ln
+
+ XDMCPLIBSRC = $(LIBSRC)/Xdmcp
+
+DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a
+XDMCPLIB = -lXdmcp
+
+LINTXDMCP = $(LINTLIBDIR)/llib-lXdmcp.ln
+
+ XMUSRC = $(LIBSRC)/Xmu
+
+SOXMUREV = 6.2
+DEPXMULIB =
+XMULIB = -lXmu
+
+LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln
+
+ XMUUSRC = $(LIBSRC)/Xmuu
+
+SOXMUUREV = 1.0
+DEPXMUULIB =
+XMUULIB = -lXmuu
+
+LINTXMUU = $(LINTLIBDIR)/llib-lXmuu.ln
+
+ OLDXLIBSRC = $(LIBSRC)/oldX
+
+DEPOLDXLIB = $(USRLIBDIR)/liboldX.a
+OLDXLIB = -loldX
+
+LINTOLDX = $(LINTLIBDIR)/llib-loldX.ln
+
+ XPLIBSRC = $(LIBSRC)/Xp
+
+SOXPREV = 6.2
+DEPXPLIB =
+XPLIB = -lXp
+
+LINTXP = $(LINTLIBDIR)/llib-lXp.ln
+
+ TOOLKITSRC = $(LIBSRC)/Xt
+
+SOXTREV = 6.0
+DEPXTOOLONLYLIB =
+XTOOLONLYLIB = -lXt
+
+LINTXTOOLONLY = $(LINTLIBDIR)/llib-lXt.ln
+
+ DEPXTOOLLIB = $(DEPXTOOLONLYLIB) $(DEPSMLIB) $(DEPICELIB)
+ XTOOLLIB = $(XTOOLONLYLIB) $(SMLIB) $(ICELIB)
+ LINTXTOOLLIB = $(LINTXTOOLONLYLIB)
+
+ XALIBSRC = $(LIBSRC)/Xa
+
+SOXAREV = 1.0
+DEPXALIB =
+XALIB = -lXa
+
+LINTXA = $(LINTLIBDIR)/llib-lXa.ln
+
+ AWIDGETSRC = $(LIBSRC)/Xaw
+
+SOXAWREV = 7.0
+DEPXAWLIB =
+XAWLIB = -lXaw
+
+LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln
+
+ AWIDGET6SRC = $(LIBSRC)/Xaw6
+
+SOXAW6REV = 6.1
+DEPXAW6LIB =
+XAW6LIB = -lXaw
+
+LINTXAW6 = $(LINTLIBDIR)/llib-lXaw.ln
+
+ XILIBSRC = $(LIBSRC)/Xi
+
+SOXINPUTREV = 6.0
+DEPXILIB =
+XILIB = -lXi
+
+LINTXI = $(LINTLIBDIR)/llib-lXi.ln
+
+ XTESTLIBSRC = $(LIBSRC)/Xtst
+
+SOXTESTREV = 6.1
+DEPXTESTLIB =
+XTESTLIB = -lXtst
+
+LINTXTEST = $(LINTLIBDIR)/llib-lXtst.ln
+
+ PEXLIBSRC = $(LIBSRC)/PEX5
+
+SOPEXREV = 6.0
+DEPPEXLIB =
+PEXLIB = -lPEX5
+
+LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln
+
+ XIELIBSRC = $(LIBSRC)/XIE
+
+SOXIEREV = 6.0
+DEPXIELIB =
+XIELIB = -lXIE
+
+LINTXIE = $(LINTLIBDIR)/llib-lXIE.ln
+
+ PHIGSLIBSRC = $(LIBSRC)/PHIGS
+
+DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a
+PHIGSLIB = -lphigs
+
+LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln
+
+DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a
+XBSDLIB = -lXbsd
+
+LINTXBSD = $(LINTLIBDIR)/llib-lXbsd.ln
+
+ ICESRC = $(LIBSRC)/ICE
+
+SOICEREV = 6.3
+DEPICELIB =
+ICELIB = -lICE
+
+LINTICE = $(LINTLIBDIR)/llib-lICE.ln
+
+ SMSRC = $(LIBSRC)/SM
+
+SOSMREV = 6.0
+DEPSMLIB =
+SMLIB = -lSM
+
+LINTSM = $(LINTLIBDIR)/llib-lSM.ln
+
+ XKEYSRC = $(LIBSRC)/Xkey
+
+SOXKEYREV = 6.0
+DEPXKEYLIB =
+XKEYLIB = -lXkey
+
+LINTXKEY = $(LINTLIBDIR)/llib-lXkey.ln
+
+ FSLIBSRC = $(LIBSRC)/FS
+
+DEPFSLIB = $(USRLIBDIR)/libFS.a
+FSLIB = -lFS
+
+LINTFS = $(LINTLIBDIR)/llib-lFS.ln
+
+ FONTLIBSRC = $(LIBSRC)/font
+
+SOFONTREV = 1.4
+DEPFONTLIB =
+FONTLIB = -L$(FREETYPELIBDIR) -L$(FONTLIBSRC) -lXfont
+
+LINTXFONT = $(LINTLIBDIR)/llib-lXfont.ln
+#
+SOFONTREV = 1.4
+DEPXFONTLIB =
+XFONTLIB = -lXfont
+
+LINTXFONT = $(LINTLIBDIR)/llib-lXfont.ln
+
+ FONTSTUBLIBSRC = $(FONTLIBSRC)/stubs
+
+DEPFONTSTUBLIB = $(USRLIBDIR)/libfntstubs.a
+FONTSTUBLIB = -lfntstubs
+
+LINTFONTSTUB = $(LINTLIBDIR)/llib-lfntstubs.ln
+ DEPFONTLIB = $(DEPXFONTLIB) $(DEPFONTSTUBLIB)
+ FONTLIB = $(XFONTLIB) $(FONTSTUBLIB) $(FONTFT2LIB)
+
+ FONTENCLIBSRC = $(LIBSRC)/fontenc
+
+DEPXFONTENCLIB = $(USRLIBDIR)/libfontenc.a
+XFONTENCLIB = -lfontenc
+
+LINTXFONTENC = $(LINTLIBDIR)/llib-lfontenc.ln
+
+ XPMLIBSRC = $(LIBSRC)/Xpm
+
+SOXPMREV = 4.11
+DEPXPMLIB =
+XPMLIB = -lXpm
+
+LINTXPM = $(LINTLIBDIR)/llib-lXpm.ln
+
+FREETYPE2DIR = /usr
+FREETYPE2LIBDIR = /usr/lib
+FREETYPE2INCDIR = /usr/include/freetype2
+
+FREETYPE2LIB = -lfreetype
+
+FREETYPE2INCLUDES = -I$(FREETYPE2INCDIR)
+FREETYPE2DEFINES = -DFREETYPE2
+
+ EXPATLIBSRC = $(LIBSRC)/expat
+
+SOEXPATREV = 1.0
+DEPEXPATLIB =
+EXPATLIB = -lexpat
+
+LINTEXPAT = $(LINTLIBDIR)/llib-lexpat.ln
+
+EXPATDIR = /usr
+EXPATLIBDIR = /usr/lib
+EXPATINCDIR = /usr/include
+
+EXPATINCLUDES =
+
+EXPATLIB = -lexpat
+
+EXPATDEFINES = -DEXPAT
+
+ XFT1LIBSRC = $(LIBSRC)/Xft1
+
+SOXFT1REV = 1.1
+DEPXFT1LIB =
+XFT1LIB = -lXft
+
+LINTXFT1 = $(LINTLIBDIR)/llib-lXft.ln
+
+ XFTLIBSRC = $(LIBSRC)/Xft
+
+SOXFTREV = 2.1
+DEPXFTLIB =
+XFTLIB = -lXft
+
+LINTXFT = $(LINTLIBDIR)/llib-lXft.ln
+
+XFTINCLUDES=$(FONTCONFIGINCLUDES) $(FREETYPE2INCLUDES)
+
+FONTCONFIGDIR = /usr
+FONTCONFIGLIBDIR = /usr/lib
+FONTCONFIGINCDIR = /usr/include
+FONTCONFIGBINDIR = /usr/bin
+
+FONTCONFIGLIB = -lfontconfig
+
+FONTCONFIGINCLUDES =
+
+FCCACHE = $(FONTCONFIGBINDIR)/fc-cache
+
+FONTCONFIGDEFINES = -DFONTCONFIG
+
+LIBPNGINCDIR = /usr/include
+
+LIBPNGINC=
+
+LIBPNGDIR = /usr
+LIBPNGLIBDIR = /usr/lib
+LIBPNGINCDIR = /usr/include
+
+LIBPNGLIB = -lpng
+
+ XKBFILELIBSRC = $(LIBSRC)/xkbfile
+
+DEPXKBFILELIB = $(USRLIBDIR)/libxkbfile.a
+XKBFILELIB = -lxkbfile
+
+LINTXKBFILE = $(LINTLIBDIR)/llib-lxkbfile.ln
+
+ XKBCOMPCMD = $(BINDIR)/xkbcomp
+
+ XKBUILIBSRC = $(LIBSRC)/xkbui
+
+DEPXKBUILIB = $(USRLIBDIR)/libxkbui.a
+XKBUILIB = -lxkbui
+
+LINTXKBUI = $(LINTLIBDIR)/llib-lxkbui.ln
+
+ XTRAPLIBSRC = $(LIBSRC)/XTrap
+
+SOXTRAPREV = 6.4
+DEPXTRAPLIB =
+XTRAPLIB = -lXTrap
+
+LINTXTRAP = $(LINTLIBDIR)/llib-lXTrap.ln
+
+ DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
+
+ DEPLIBS1 = $(DEPLIBS)
+ DEPLIBS2 = $(DEPLIBS)
+ DEPLIBS3 = $(DEPLIBS)
+ DEPLIBS4 = $(DEPLIBS)
+ DEPLIBS5 = $(DEPLIBS)
+ DEPLIBS6 = $(DEPLIBS)
+ DEPLIBS7 = $(DEPLIBS)
+ DEPLIBS8 = $(DEPLIBS)
+ DEPLIBS9 = $(DEPLIBS)
+ DEPLIBS10 = $(DEPLIBS)
+
+XMULIBONLY = -lXmu
+XMULIB = $(XMULIBONLY) $(XTOOLLIB) $(XLIB)
+
+ CONFIGDIR = $(LIBDIR)/config
+
+ USRLIBDIRPATH = $(USRLIBDIR)
+ LDPRELIBS = -L$(USRLIBDIR) $(INSTALLED_LIBS)
+ LDPOSTLIBS =
+ TOP_INCLUDES = -I$(INCROOT) $(TOP_X_INCLUDES)
+ PROJECT_DEFINES =
+
+CXXPROJECT_DEFINES =
+
+# ----------------------------------------------------------------------
+# start of Imakefile
+
+# Imakefile for the Object Manager special widget library.
+# 05-Sep-93, Doug Tody NOAO/IRAF.
+
+X11IRAFDIR = ../../
+
+# $Xorg: Library.tmpl,v 1.3 2000/08/17 19:41:46 cpqbld Exp $
+
+# $XFree86: xc/config/cf/Library.tmpl,v 3.20 2002/11/25 14:04:47 eich Exp $
+
+ CC = gcc -m32
+
+ CCOPTIONS =
+STD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+CDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+CLIBDEBUGFLAGS =
+ CFLAGS = $(CDEBUGFLAGS) $(CLIBDEBUGFLAGS) $(CCOPTIONS) $(THREADS_CFLAGS) $(ALLDEFINES)
+
+LIB_MT_DEFINES = LibraryMTDefines
+
+SOSYMLINK = true
+
+ X11IRAFBINDIR = $(X11IRAFDIR)/bin
+ X11IRAFMANDIR = $(X11IRAFDIR)/man
+ X11IRAFLIBDIR = $(X11IRAFDIR)/lib
+ X11IRAFINCDIR = $(X11IRAFDIR)/include
+
+ XGTERMDIR = $(X11IRAFDIR)/xgterm
+ XIMTOOLDIR = $(X11IRAFDIR)/ximtool
+ XTAPEMONDIR = $(X11IRAFDIR)/xtapemon
+ OBMSHDIR = $(X11IRAFDIR)/obmsh
+ OBMDIR = $(X11IRAFDIR)/obm
+ XPMDIR = $(X11IRAFDIR)/xpm
+ XAW3DDIR = $(X11IRAFDIR)/xaw3d
+ CDLDIR = $(X11IRAFDIR)/cdl
+
+ DEPLIBOBM = $(OBMDIR)/libobm.a
+ LIBOBM = -lobm
+ DEPLIBXPM = $(XPMDIR)/libXpm.a
+ LIBXPM = -lXpm
+ DEPLIBXAW3D = $(XAW3DDIR)/libXaw3d.a
+ LIBXAW3D = -lXaw3d
+ LIBCDL = -lcdl
+
+ X11IRAF_LDFLAGS = -L$(X11IRAFDIR)/lib -L../lib
+ X11IRAF_INCLUDES = -I$(X11IRAFDIR)/include -I../include
+
+ CP = cp -p
+
+ EXTRA_INCLUDES = -I../../include
+ EXTRA_DEFINES = -D_NO_PROTO
+
+# Hack to compile under SunPRO V4 on Solaris
+
+ CCOPTIONS = -DUSE_STDARG
+
+HEADERS = Arrow.h ArrowP.h Board.h BoardP.h Button.h ButtonP.h Common.h CommonP.h Converters.h DrawingArea.h DrawingAreaP.h Frame.h FrameP.h Group.h GroupP.h Gterm.h GtermP.h HTML.h HTMLP.h HTMLamp.h Icon.h IconP.h Label.h LabelP.h Layout.h LayoutP.h MenuBar.h MenuBarP.h MultiList.h MultiListP.h RadioGrp.h RadioGrpP.h RowCol.h RowColP.h Scrollbar.h ScrollbarP.h Slider2.h Slider2P.h TabString.h Toggle.h ToggleP.h done.h inkstore.h laygram.h scroll.h Tabs.h TabsP.h Gcs.h ListTree.h ListTreeP.h
+
+XRAW_HEADERS = 3d.h AllWidgets.h Arrow.h ArrowP.h AsciiSink.h AsciiSinkP.h AsciiSrc.h AsciiSrcP.h AsciiText.h AsciiTextP.h Box.h BoxP.h Cardinals.h Clock.h ClockP.h Command.h CommandP.h Container.h ContainerP.h Dialog.h DialogP.h Form.h FormP.h Frame.h FrameP.h Grip.h GripP.h Label.h LabelP.h List.h ListP.h Logo.h LogoP.h Mailbox.h MailboxP.h MenuButtoP.h MenuButton.h Object.h Paned.h PanedP.h Panner.h PannerP.h Porthole.h PortholeP.h Repeater.h RepeaterP.h Reports.h Scrollbar.h ScrollbarP.h ScrolledTable.h ScrolledTableP.h Separator.h SeparatorP.h Simple.h SimpleMenP.h SimpleMenu.h SimpleP.h Sme.h SmeBSB.h SmeBSBP.h SmeLine.h SmeLineP.h SmeP.h StripCharP.h StripChart.h Table.h Table3d.h TableP.h TableUtil.h Template.h TemplateP.h Text.h TextP.h TextSink.h TextSinkP.h TextSrc.h TextSrcP.h Toggle.h ToggleP.h Tree.h TreeP.h Viewport.h ViewportP.h XawAll.h XawInit.h Xosdefs.h XrawInit.h color.h xraw_table.h
+
+SRCS = Arrow.c Board.c Button.c Common.c DrawIString.c DrawString.c DrawingArea.c Frame.c Group.c Gterm.c HTML-PSformat.c HTML.c HTMLformat.c HTMLimages.c HTMLjot.c HTMLlists.c HTMLparse.c HTMLwidgets.c Icon.c Label.c Layout.c MenuBar.c MultiList.c RadioGrp.c RowCol.c Scrollbar.c Slider2.c Tablist2Tabs.c TextWidth.c Toggle.c cvtLong.c iconutil.c laygram.c laylex.c scroll.c strnchr.c Tabs.c Gcs.c ListTree.c Separator.c Table.c Table3d.c TableUtil.c Container.c color.c
+
+OBJS = Arrow.o Board.o Button.o Common.o DrawIString.o DrawString.o DrawingArea.o Frame.o Group.o Gterm.o HTML-PSformat.o HTML.o HTMLformat.o HTMLimages.o HTMLjot.o HTMLlists.o HTMLparse.o HTMLwidgets.o Icon.o Label.o Layout.o MenuBar.o MultiList.o RadioGrp.o RowCol.o Scrollbar.o Slider2.o Tablist2Tabs.o TextWidth.o Toggle.o cvtLong.o iconutil.o laygram.o laylex.o scroll.o strnchr.o Tabs.o Gcs.o ListTree.o Separator.o Table.o Table3d.o TableUtil.o Container.o color.o
+
+LEX=flex -l
+
+YACC=bison -y
+
+depend:: laygram.c laylex.c
+all:: laygram.c laylex.c
+
+all:: DONE
+
+DONE: $(OBJS)
+ $(RM) $@
+ touch $@
+
+cleandir::
+ $(RM) DONE
+
+lint:
+ $(LINT) $(LINTFLAGS) $(SRCS) $(LINTLIBS)
+lint1:
+ $(LINT) $(LINTFLAGS) $(FILE) $(LINTLIBS)
+
+lintlib:: llib-lar.ln
+
+llib-lar.ln: $(SRCS) $(EXTRALIBRARYDEPS)
+ $(RM) $@
+ $(LINT) $(LINTLIBFLAG)ar $(LINTFLAGS) $(SRCS)
+
+# Turn off compiler warnings for the HTML and FWF widgets.
+ FWFCFLAGS = $(CFLAGS) -c -w
+
+HTML.o: HTML.c
+ $(CC) $(FWFCFLAGS) HTML.c
+HTML-PSformat.o: HTML-PSformat.c
+ $(CC) $(FWFCFLAGS) HTML-PSformat.c
+HTMLformat.o: HTMLformat.c
+ $(CC) $(FWFCFLAGS) HTMLformat.c
+HTMLimages.o: HTMLimages.c
+ $(CC) $(FWFCFLAGS) HTMLimages.c
+HTMLjot.o: HTMLjot.c
+ $(CC) $(FWFCFLAGS) HTMLjot.c
+HTMLlists.o: HTMLlists.c
+ $(CC) $(FWFCFLAGS) HTMLlists.c
+HTMLparse.o: HTMLparse.c
+ $(CC) $(FWFCFLAGS) HTMLparse.c
+HTMLwidgets.o: HTMLwidgets.c
+ $(CC) $(FWFCFLAGS) HTMLwidgets.c
+
+Arrow.o:
+ $(CC) $(FWFCFLAGS) Arrow.c
+Board.o:
+ $(CC) $(FWFCFLAGS) Board.c
+Button.o:
+ $(CC) $(FWFCFLAGS) Button.c
+Common.o:
+ $(CC) $(FWFCFLAGS) Common.c
+DrawIString.o:
+ $(CC) $(FWFCFLAGS) DrawIString.c
+DrawString.o:
+ $(CC) $(FWFCFLAGS) DrawString.c
+Frame.o:
+ $(CC) $(FWFCFLAGS) Frame.c
+Group.o:
+ $(CC) $(FWFCFLAGS) Group.c
+Icon.o:
+ $(CC) $(FWFCFLAGS) Icon.c
+Label.o:
+ $(CC) $(FWFCFLAGS) Label.c
+MenuBar.o:
+ $(CC) $(FWFCFLAGS) MenuBar.c
+MultiList.o:
+ $(CC) $(FWFCFLAGS) MultiList.c
+RadioGrp.o:
+ $(CC) $(FWFCFLAGS) RadioGrp.c
+RowCol.o:
+ $(CC) $(FWFCFLAGS) RowCol.c
+Scrollbar.o:
+ $(CC) $(FWFCFLAGS) Scrollbar.c
+Slider2.o:
+ $(CC) $(FWFCFLAGS) Slider2.c
+Tablist2Tabs.o:
+ $(CC) $(FWFCFLAGS) Tablist2Tabs.c
+TextWidth.o:
+ $(CC) $(FWFCFLAGS) TextWidth.c
+Toggle.o:
+ $(CC) $(FWFCFLAGS) Toggle.c
+cvtLong.o:
+ $(CC) $(FWFCFLAGS) cvtLong.c
+iconutil.o:
+ $(CC) $(FWFCFLAGS) iconutil.c
+laylex.o:
+ $(CC) $(FWFCFLAGS) laylex.c
+
+laygram.c laygram.h : laygram.y
+ yacc -d laygram.y
+ sed 's/yy/LayYY/g' y.tab.c > laygram.c
+ sed 's/yy/LayYY/g' y.tab.h > laygram.h
+ rm y.tab.c y.tab.h
+
+# Hack to compile under systems which don't have strict ANSI compilers.
+
+# Hack to compile under SunPRO V4 on Solaris
+
+cleandir::
+ -rm -f laygram.c laygram.h
+
+laylex.c: laylex.l
+ $(LEX) laylex.l
+ sed 's/yy/LayYY/g' lex.yy.c > laylex.c
+ rm lex.yy.c
+
+cleandir::
+ -rm -f laylex.c
+
+includes:: laygram.h
+ @if [ -d $(X11IRAFDIR)/include/ObmW ]; then \
+ set +x; \
+ else \
+ if [ -h $(X11IRAFDIR)/include/ObmW ]; then \
+ (set -x; rm -f $(X11IRAFDIR)/include/ObmW); \
+ fi; \
+ (set -x; $(MKDIRHIER) $(X11IRAFDIR)/include/ObmW); \
+ fi
+ @(set -x; for i in $(HEADERS); do $(RM) $(X11IRAFDIR)/include/ObmW/$$i; $(CP) -p $$i $(X11IRAFDIR)/include/ObmW/$$i; done)
+
+ @if [ -d $(X11IRAFDIR)/include/X11/Xraw ]; then \
+ set +x; \
+ else \
+ if [ -h $(X11IRAFDIR)/include/X11/Xraw ]; then \
+ (set -x; rm -f $(X11IRAFDIR)/include/X11/Xraw); \
+ fi; \
+ (set -x; $(MKDIRHIER) $(X11IRAFDIR)/include/X11/Xraw); \
+ fi
+ @(set -x; for i in $(XRAW_HEADERS); do $(RM) $(X11IRAFDIR)/include/X11/Xraw/$$i; $(CP) -p Xraw/$$i $(X11IRAFDIR)/include/X11/Xraw/$$i; done)
+
+install::
+ @(set -x; for i in $(HEADERS); do $(RM) $(X11IRAFDIR)/include/ObmW/$$i; done)
+
+ for i in $(HEADERS); do (set -x; $(CP) -p $$i $(X11IRAFDIR)/include/ObmW); done
+
+depend::
+ $(DEPEND) $(DEPENDFLAGS) -- $(ALLDEFINES) $(DEPEND_DEFINES) -- $(SRCS)
+
+# ----------------------------------------------------------------------
+# common rules for all Makefiles - do not edit
+
+.c.i:
+ $(RM) $@
+ $(CC) -E $(CFLAGS) $(_NOOP_) $*.c > $@
+
+.SUFFIXES: .s
+
+.c.s:
+ $(RM) $@
+ $(CC) -S $(CFLAGS) $(_NOOP_) $*.c
+
+emptyrule::
+
+cleandir::
+ $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"*
+
+Makefile::
+ -@if [ -f Makefile ]; then set -x; \
+ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
+ else exit 0; fi
+ $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
+
+tags::
+ $(TAGS) -w *.[ch]
+ $(TAGS) -xw *.[ch] > TAGS
+
+man_keywords::
+
+html_index::
+
+clean:: cleandir
+
+distclean:: cleandir
+
+# ----------------------------------------------------------------------
+# empty rules for directories that do not have SUBDIRS - do not edit
+
+install::
+ @echo "install in $(CURRENT_DIR) done"
+
+install.man::
+ @echo "install.man in $(CURRENT_DIR) done"
+
+install.sdk::
+ @echo "install.sdk in $(CURRENT_DIR) done"
+
+Makefiles::
+
+includes::
+
+depend::
+
+distclean::
+ $(RM) Makefile Makefile.dep
+
+# ----------------------------------------------------------------------
+# dependencies generated by makedepend
+
diff --git a/vendor/x11iraf/obm/ObmW/MenuBar.c b/vendor/x11iraf/obm/ObmW/MenuBar.c
new file mode 100644
index 00000000..f13a1d13
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MenuBar.c
@@ -0,0 +1,183 @@
+/* Generated by wbuild from "MenuBar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+/* #include "PullDown.h" */
+#include <X11/Shell.h>
+#include <stdio.h>
+#include "MenuBarP.h"
+static void menu_popdown(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"menu_popdown", menu_popdown},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Up>: menu_popdown() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void process_menu(
+#if NeedFunctionPrototypes
+Widget,Widget ,Cursor
+#endif
+);
+static void popdown_cb(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+/*ARGSUSED*/static void popdown_cb(menu,client_data,call_data)Widget menu;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+
+ XtRemoveCallback(menu, XtNpopdownCallback, popdown_cb, self);
+/*
+ XtUngrabKey(menu, AnyKey, AnyModifier);
+ XtUngrabButton(menu, AnyButton, AnyModifier);
+ XtRemoveGrab($);
+*/
+ ((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu = NULL;
+}
+
+static XtResource resources[] = {
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfMenuBarRec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfMenuBarRec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfRaised },
+{XtNtraversalOn,XtCTraversalOn,XtRBoolean,sizeof(((XfwfMenuBarRec*)NULL)->xfwfCommon.traversalOn),XtOffsetOf(XfwfMenuBarRec,xfwfCommon.traversalOn),XtRImmediate,(XtPointer)False },
+};
+
+XfwfMenuBarClassRec xfwfMenuBarClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfRowColClassRec,
+"XfwfMenuBar",
+sizeof(XfwfMenuBarRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+1,
+resources,
+2,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+XtInheritExpose,
+NULL,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfRowCol_class part */
+XtInherit_layout,
+},
+{ /* XfwfMenuBar_class part */
+process_menu,
+},
+};
+WidgetClass xfwfMenuBarWidgetClass = (WidgetClass) &xfwfMenuBarClassRec;
+/*ARGSUSED*/
+static void menu_popdown(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu != NULL) {
+ XtPopdown(((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu);
+ ((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu = NULL;
+ }
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfMenuBarWidgetClass c = (XfwfMenuBarWidgetClass) class;
+ XfwfMenuBarWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfMenuBarWidgetClass) return;
+ super = (XfwfMenuBarWidgetClass)class->core_class.superclass;
+ if (c->xfwfMenuBar_class.process_menu == XtInherit_process_menu)
+ c->xfwfMenuBar_class.process_menu = super->xfwfMenuBar_class.process_menu;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu = NULL;
+}
+/*ARGSUSED*/static void process_menu(self,menu,cursor)Widget self;Widget menu;Cursor cursor;
+{
+ if (menu == ((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu) return;
+ if (((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu) XtPopdown(((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu);
+ XtAddGrab(self, True, False);
+/*
+ XtGrabButton(menu, AnyButton, AnyModifier, True, ButtonPressMask |
+ ButtonReleaseMask | EnterWindowMask | LeaveWindowMask
+ | PointerMotionMask, GrabModeAsync, GrabModeAsync,
+ None, cursor);
+ XtGrabKey(menu, AnyKey, AnyModifier, True, GrabModeAsync,
+ GrabModeAsync);
+*/
+ XtAddCallback(menu, XtNpopdownCallback, popdown_cb, self);
+ ((XfwfMenuBarWidget)self)->xfwfMenuBar.current_menu = menu;
+ XtPopup(menu, XtGrabNonexclusive);
+}
+/*ARGSUSED*/Boolean XfwfCallProcessMenu(self,menu,cursor)Widget self;Widget menu;Cursor cursor;
+{
+ if (XtIsSubclass(self, xfwfMenuBarWidgetClass) && ((XfwfMenuBarWidgetClass)self->core.widget_class)->xfwfMenuBar_class.process_menu) {
+ ((XfwfMenuBarWidgetClass)self->core.widget_class)->xfwfMenuBar_class.process_menu(self, menu, cursor);
+ return True;
+ } else
+ return False;
+}
diff --git a/vendor/x11iraf/obm/ObmW/MenuBar.h b/vendor/x11iraf/obm/ObmW/MenuBar.h
new file mode 100644
index 00000000..a9c9c847
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MenuBar.h
@@ -0,0 +1,15 @@
+/* Generated by wbuild from "MenuBar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfMenuBar_H_
+#define _XfwfMenuBar_H_
+#include "RowCol.h"
+Boolean XfwfCallProcessMenu(
+#if NeedFunctionPrototypes
+Widget,Widget ,Cursor
+#endif
+);
+typedef struct _XfwfMenuBarClassRec *XfwfMenuBarWidgetClass;
+typedef struct _XfwfMenuBarRec *XfwfMenuBarWidget;
+externalref WidgetClass xfwfMenuBarWidgetClass;
+#endif /*_XfwfMenuBar_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/MenuBar.man b/vendor/x11iraf/obm/ObmW/MenuBar.man
new file mode 100644
index 00000000..3ee2018f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MenuBar.man
@@ -0,0 +1,365 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfMenuBar
+.SH DESCRIPTION
+The MenuBar widget is a special kind of RowCol widget. It assumes
+that all its children are PullDown buttons or other widgets that pop
+up a menu. (But nothing will break if they are not.) By default, the
+children are arranged in a row, wrapping to the next row if the width
+is not enough for all of them. But other arrangements are possible,
+see the resources of the XfwfRowCol(3) widget.
+
+The MenuBar attaches itself to the \fIpopup\fP callback of the menu shell
+that is popped up by the children, and inserts itself in the list of
+pointer grabs that Xt maintains. This is necessary to be able to drag
+the mouse from one menu into another, popping down the first one and
+popping up the second. If you use a RowCol widget instead of a
+MenuBar, you will find that switching from one menu to the next
+involves releasing the mouse and then pressing it again.
+
+To find the menu shell, the children are asked for their \fIpopup\fP
+resource. PullDown buttons have this resource, others may not.
+
+The MenuBar widget introduces no new resources.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfMenuBar
+Name Class Type Default
+
+.TE
+.ps
+
+.TP
+.I "XtNframeType"
+
+.hi
+
+.nf
+ frameType = XfwfRaised
+.fi
+
+.eh
+
+.TP
+.I "XtNtraversalOn"
+
+.hi
+
+.nf
+ traversalOn = False
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfRowCol
+Name Class Type Default
+XtNstoreByRow XtCStoreByRow Boolean True
+XtNrows XtCRows Int 0
+XtNcolumns XtCColumns Int 0
+XtNalignment XtCAlignment Alignment XfwfTopLeft
+XtNshrinkToFit XtCShrinkToFit Boolean False
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The MenuBar widget has a method \fIprocess_menu\fP that can be used by
+children (usually PullDown buttons) to pop up a menu and to register
+it with the menu bar. If they do so, the menu bar is able to process
+events elsewhere in the menu bar and pop down the menu in favour of
+another one, when the user moves the mouse to another button in the
+menu bar. A menu or a button is unable to do this by itself, since
+they do not know what other menus are present.
+
+To call the \fIprocess_menu\fP method, widgets should use the
+\fIXfwfCallProcessMenu\fP function, which will check that the receiver of
+the call is indeed a MenuBar widget. It returns \fITrue\fP if the
+\fIprocess_menu\fP method could be called, otherwise \fIFalse\fP.
+
+The value for \fIcursor\fP can also be \fINone\fP, in which case the cursor
+from the menu's parent (the root window, usually) will be used
+instead.
+
+.nf
+Boolean XfwfCallProcessMenu( $, Widget menu, Cursor cursor)
+.fi
+
+.hi
+{
+ if (XtIsSubclass($, xfwfMenuBarWidgetClass) $process_menu) {
+ $process_menu($, menu, cursor);
+ return True;
+ } else
+ return False;
+}
+.eh
+
+.SS "Translations"
+
+Since the MenuBar widget adds itself to the list of cascaded popups
+that is maintained by Xt, it will receive pointer events when a menu
+is popped up. If the event is a button release, the current menu will
+have to be popped down.
+
+
+
+.nf
+<Btn1Up>: menu_popdown()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "menu_popdown
+
+The \fImenu_popdown\fP action calls \fIXtPopdown\fP for the current menu,
+if there is one.
+
+.hi
+
+.nf
+void menu_popdown($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if ($current_menu != NULL) {
+ XtPopdown($current_menu);
+ $current_menu = NULL;
+ }
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <Xfwf/PullDown.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Shell.h>
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+A pointer to the currently popped up menu is kept in a private
+variable \fIcurrent_menu\fP. The variable is set in the \fIprocess_menu\fP
+method.
+
+
+
+.nf
+Widget current_menu
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $current_menu = NULL;
+}
+.fi
+
+The \fIprocess_menu\fP method is provided for use by children (usually
+PullDown buttons) to pop up their menus. If they call this method
+instead of popping up the menu themselves, the menu bar has a chance
+to intercept events for other buttons in the menu bar and pop down the
+menu when the user clicks on another button in the menubar.
+
+The method adds the appropriate (passive) global grabs, establishes an
+Xt local grab and adds a callback to the menu, so that the menu bar
+will be informed when the menu is popped down again.
+
+.nf
+process_menu($, Widget menu, Cursor cursor)
+{
+ if (menu == $current_menu) return;
+ if ($current_menu) XtPopdown($current_menu);
+ XtAddGrab($, True, False);
+/*
+ XtGrabButton(menu, AnyButton, AnyModifier, True, ButtonPressMask |
+ ButtonReleaseMask | EnterWindowMask | LeaveWindowMask
+ | PointerMotionMask, GrabModeAsync, GrabModeAsync,
+ None, cursor);
+ XtGrabKey(menu, AnyKey, AnyModifier, True, GrabModeAsync,
+ GrabModeAsync);
+*/
+ XtAddCallback(menu, XtNpopdownCallback, popdown_cb, $);
+ $current_menu = menu;
+ XtPopup(menu, XtGrabNonexclusive);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The \fIpopdown_cb\fP routine is a callback that is attached to the
+currently popped up menu. When the menu pops down, the routine removes
+the grabs and resets \fIcurrent_menu\fP to \fINULL\fP.
+
+.nf
+popdown_cb(Widget menu, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = (Widget) client_data;
+
+ XtRemoveCallback(menu, XtNpopdownCallback, popdown_cb, $);
+/*
+ XtUngrabKey(menu, AnyKey, AnyModifier);
+ XtUngrabButton(menu, AnyButton, AnyModifier);
+ XtRemoveGrab($);
+*/
+ $current_menu = NULL;
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/MenuBarP.h b/vendor/x11iraf/obm/ObmW/MenuBarP.h
new file mode 100644
index 00000000..9b74d5e1
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MenuBarP.h
@@ -0,0 +1,47 @@
+/* Generated by wbuild from "MenuBar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfMenuBarP_H_
+#define _XfwfMenuBarP_H_
+#include "RowColP.h"
+#include "MenuBar.h"
+typedef void (*process_menu_Proc)(
+#if NeedFunctionPrototypes
+Widget,Widget ,Cursor
+#endif
+);
+#define XtInherit_process_menu ((process_menu_Proc) _XtInherit)
+typedef struct {
+/* methods */
+process_menu_Proc process_menu;
+/* class variables */
+} XfwfMenuBarClassPart;
+typedef struct _XfwfMenuBarClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfRowColClassPart xfwfRowCol_class;
+XfwfMenuBarClassPart xfwfMenuBar_class;
+} XfwfMenuBarClassRec;
+
+typedef struct {
+/* resources */
+/* private state */
+Widget current_menu;
+} XfwfMenuBarPart;
+
+typedef struct _XfwfMenuBarRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfRowColPart xfwfRowCol;
+XfwfMenuBarPart xfwfMenuBar;
+} XfwfMenuBarRec;
+
+externalref XfwfMenuBarClassRec xfwfMenuBarClassRec;
+
+#endif /* _XfwfMenuBarP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/MultiList.c b/vendor/x11iraf/obm/ObmW/MultiList.c
new file mode 100644
index 00000000..1c67b2de
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MultiList.c
@@ -0,0 +1,1793 @@
+/****************************************************************************
+
+ MultiList.c
+
+ This file contains the implementation of the Picasso List
+ widget. Its functionality is intended to be similar to
+ The Athena List widget, with some extra features added.
+
+ This code is loosely based on the Athena List source which
+ is why the MIT copyright notice appears below.
+
+ The code was changed substantially in V3.4 to change the
+ action/callback interface which was unnecessarily ugly. Code
+ using some features of the old interface may need to be changed.
+ Hope the changes don't make people's lives too miserable.
+
+ ****************************************************************************/
+
+/*
+ * Author:
+ * Brian Totty
+ * Department of Computer Science
+ * University Of Illinois at Urbana-Champaign
+ * 1304 West Springfield Avenue
+ * Urbana, IL 61801
+ *
+ * totty@cs.uiuc.edu
+ *
+ */
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Original Athena Author: Chris D. Peterson, MIT X Consortium
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include "MultiListP.h"
+#include "TabString.h"
+
+/*===========================================================================*
+
+ D E C L A R A T I O N S A N D D E F I N I T I O N S
+
+ *===========================================================================*/
+
+Pixmap XmuCreateStippledPixmap();
+extern void XawInitializeWidgetSet();
+
+#define SUPERCLASS &(simpleClassRec)
+
+#define FontAscent(f) ((f)->max_bounds.ascent)
+#define FontDescent(f) ((f)->max_bounds.descent)
+#define FontH(f) (FontAscent(f) + FontDescent(f) + 2)
+#define FontW(f,s,w) (XfwfTextWidth(f,s,strlen(s), MultiListTabs(w)) + 1)
+#define FontMaxCharW(f) ((f)->max_bounds.rbearing-(f)->min_bounds.lbearing+1)
+
+#ifndef abs
+#define abs(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define XtStrlen(s) ((s) ? strlen(s) : 0)
+
+#define TypeAlloc(t,n) (t *)malloc(sizeof(t) * n)
+#define StrCopy(s) strcpy(TypeAlloc(char,strlen(s)+1),s)
+#define StrCopyRetLength(s,lp) strcpy(TypeAlloc(char,(*lp=(strlen(s)+1))),s)
+
+#define CoreFieldOffset(f) XtOffset(Widget,core.f)
+#define SimpleFieldOffset(f) XtOffset(XfwfMultiListWidget,simple.f)
+#define MultiListFieldOffset(f) XtOffset(XfwfMultiListWidget,multiList.f)
+
+/*===========================================================================*
+
+ I N T E R N A L P R O C E D U R E D E C L A R A T I O N S
+
+ *===========================================================================*/
+
+#if (!NeedFunctionPrototypes)
+
+static void Initialize();
+static void Redisplay();
+static XtGeometryResult PreferredGeometry();
+static void Resize();
+static Boolean SetValues();
+
+static void DestroyOldData();
+static void InitializeNewData();
+static void CreateNewGCs();
+
+static void RecalcCoords();
+static void NegotiateSizeChange();
+static Boolean Layout();
+
+static void RedrawAll();
+static void RedrawItem();
+static void RedrawRowColumn();
+
+static void PixelToRowColumn();
+static void RowColumnToPixels();
+static Boolean RowColumnToItem();
+static Boolean ItemToRowColumn();
+
+static void Select();
+static void Unselect();
+static void Toggle();
+static void Extend();
+static void Notify();
+
+#else
+
+static void Initialize(Widget request, Widget new);
+static void Redisplay(XfwfMultiListWidget mlw,
+ XEvent *event, Region rectangle_union);
+static XtGeometryResult PreferredGeometry(XfwfMultiListWidget mlw,
+ XtWidgetGeometry *parent_idea,
+ XtWidgetGeometry *our_idea);
+static void Resize(XfwfMultiListWidget mlw);
+static Boolean SetValues(XfwfMultiListWidget cpl,
+ XfwfMultiListWidget rpl,
+ XfwfMultiListWidget npl);
+static void DestroyOldData(XfwfMultiListWidget mlw);
+static void InitializeNewData(XfwfMultiListWidget mlw);
+static void CreateNewGCs(XfwfMultiListWidget mlw);
+static void RecalcCoords(XfwfMultiListWidget mlw,
+ Boolean width_changeable,
+ Boolean height_changeable);
+static void NegotiateSizeChange(XfwfMultiListWidget mlw,
+ Dimension width, Dimension height);
+static Boolean Layout(XfwfMultiListWidget mlw,
+ Boolean w_changeable, Boolean h_changeable,
+ Dimension *w_ptr, Dimension *h_ptr);
+static void RedrawAll(XfwfMultiListWidget mlw);
+static void RedrawItem(XfwfMultiListWidget mlw, int item_index);
+static void RedrawRowColumn(XfwfMultiListWidget mlw,
+ int row, int column);
+static void PixelToRowColumn(XfwfMultiListWidget mlw,
+ int x, int y, int *row_ptr, int *column_ptr);
+static void RowColumnToPixels(XfwfMultiListWidget mlw,
+ int row, int col, int *x_ptr, int *y_ptr,
+ int *w_ptr, int *h_ptr);
+static Boolean RowColumnToItem(XfwfMultiListWidget mlw,
+ int row, int column, int *item_ptr);
+static Boolean ItemToRowColumn(XfwfMultiListWidget mlw,
+ int item_index, int *row_ptr, int *column_ptr);
+static void Select(XfwfMultiListWidget mlw, XEvent *event,
+ String *params, Cardinal *num_params);
+static void Unselect(XfwfMultiListWidget mlw, XEvent *event,
+ String *params, Cardinal *num_params);
+static void Toggle(XfwfMultiListWidget mlw, XEvent *event,
+ String *params, Cardinal *num_params);
+static void Extend(XfwfMultiListWidget mlw, XEvent *event,
+ String *params, Cardinal *num_params);
+static void Notify(XfwfMultiListWidget mlw, XEvent *event,
+ String *params, Cardinal *num_params);
+#endif
+
+/*===========================================================================*
+
+ R E S O U R C E I N I T I A L I Z A T I O N
+
+ *===========================================================================*/
+
+static XtResource resources[] =
+{
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ CoreFieldOffset(width), XtRString, "0"},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ CoreFieldOffset(height), XtRString, "0"},
+ {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
+ CoreFieldOffset(background_pixel),XtRString,"XtDefaultBackground"},
+
+ {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ SimpleFieldOffset(cursor), XtRString, "left_ptr"},
+
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ MultiListFieldOffset(foreground), XtRString,"XtDefaultForeground"},
+ {XtNhighlightForeground, XtCHForeground, XtRPixel, sizeof(Pixel),
+ MultiListFieldOffset(highlight_fg), XtRString, "XtDefaultBackground"},
+ {XtNhighlightBackground, XtCHBackground, XtRPixel, sizeof(Pixel),
+ MultiListFieldOffset(highlight_bg), XtRString, "XtDefaultForeground"},
+ {XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
+ MultiListFieldOffset(column_space), XtRImmediate, (caddr_t)8},
+ {XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
+ MultiListFieldOffset(row_space), XtRImmediate, (caddr_t)0},
+ {XtNdefaultColumns, XtCColumns, XtRInt, sizeof(int),
+ MultiListFieldOffset(default_cols), XtRImmediate, (caddr_t)1},
+ {XtNforceColumns, XtCColumns, XtRBoolean, sizeof(Boolean),
+ MultiListFieldOffset(force_cols), XtRString, (caddr_t) "False"},
+ {XtNpasteBuffer, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ MultiListFieldOffset(paste), XtRString, (caddr_t) "False"},
+ {XtNverticalList, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ MultiListFieldOffset(row_major), XtRString, (caddr_t) "False"},
+ {XtNlongest, XtCLongest, XtRInt, sizeof(int),
+ MultiListFieldOffset(longest), XtRImmediate, (caddr_t)0},
+ {XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int),
+ MultiListFieldOffset(nitems), XtRImmediate, (caddr_t)0},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ MultiListFieldOffset(font),XtRString, "XtDefaultFont"},
+ {XtNlist, XtCList, XtRPointer, sizeof(char **),
+ MultiListFieldOffset(list), XtRString, NULL},
+ {XtNsensitiveArray, XtCList, XtRPointer, sizeof(Boolean *),
+ MultiListFieldOffset(sensitive_array), XtRString, NULL},
+ {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
+ MultiListFieldOffset(callback), XtRCallback, NULL},
+ {XtNmaxSelectable, XtCValue, XtRInt, sizeof(int),
+ MultiListFieldOffset(max_selectable), XtRImmediate, (caddr_t) 1},
+
+ {XtNshadeSurplus, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ MultiListFieldOffset(shade_surplus), XtRString, "True"},
+
+ {XtNcolumnWidth, XtCValue, XtRDimension, sizeof(Dimension),
+ MultiListFieldOffset(col_width), XtRImmediate, (caddr_t)0},
+ {XtNrowHeight, XtCValue, XtRDimension, sizeof(Dimension),
+ MultiListFieldOffset(row_height), XtRImmediate, (caddr_t)0},
+
+ {XtNtablist, XtCTablist, XtRString, sizeof(int *),
+ MultiListFieldOffset(tablist), XtRImmediate, (XtPointer)NULL },
+
+};
+
+/*===========================================================================*
+
+ A C T I O N A N D T R A N S L A T I O N T A B L E S
+
+ *===========================================================================*/
+
+
+static char defaultTranslations[] =
+" Shift <Btn1Down>: Toggle()\n\
+ Ctrl <Btn1Down>: Unselect()\n\
+ <Btn1Down>: Select()\n\
+ Button1 <Btn1Motion>: Extend()\n\
+ <Btn1Up>: Notify()";
+
+static XtActionsRec actions[] =
+{
+ {"Select", (XtActionProc)Select},
+ {"Unselect", (XtActionProc)Unselect},
+ {"Toggle", (XtActionProc)Toggle},
+ {"Extend", (XtActionProc)Extend},
+ {"Notify", (XtActionProc)Notify},
+ {NULL, (XtActionProc)NULL}
+};
+
+/*===========================================================================*
+
+ C L A S S A L L O C A T I O N
+
+ *===========================================================================*/
+
+XfwfMultiListClassRec xfwfMultiListClassRec =
+{
+ {
+ /* superclass */ (WidgetClass)SUPERCLASS,
+ /* class_name */ "MultiList",
+ /* widget_size */ sizeof(XfwfMultiListRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize*/ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ (XtInitProc)Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ FALSE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ (XtWidgetProc)Resize,
+ /* expose */ (XtExposeProc)Redisplay,
+ /* set_values */ (XtSetValuesFunc)SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ (XtGeometryHandler)
+ PreferredGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }, /* Core Part */
+ {
+ /* change_sensitive */ XtInheritChangeSensitive
+ }
+};
+
+WidgetClass xfwfMultiListWidgetClass = (WidgetClass)&xfwfMultiListClassRec;
+
+/*===========================================================================*
+
+ T O O L K I T M E T H O D S
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ Initialize()
+
+ This procedure is called by the X toolkit to initialize
+ the widget instance. The hook to this routine is in the
+ initialize part of the core part of the class.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Initialize(request,new)
+Widget request,new;
+{
+ XfwfMultiListWidget mlw;
+
+ mlw = (XfwfMultiListWidget)new;
+ CreateNewGCs(mlw);
+ InitializeNewData(mlw);
+ MultiListTabs(mlw) = XfwfTablist2Tabs(MultiListTabList(mlw));
+ RecalcCoords(mlw,(MultiListWidth(mlw) == 0),
+ (MultiListHeight(mlw) == 0));
+} /* Initialize */
+
+
+/*---------------------------------------------------------------------------*
+
+ Redisplay(mlw,event,rectangle_union)
+
+ This routine redraws the MultiList widget <mlw> based on the exposure
+ region requested in <event>.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Redisplay(mlw,event,rectangle_union)
+XfwfMultiListWidget mlw;
+XEvent *event;
+Region rectangle_union;
+{
+ GC shade_gc;
+ int i,x1,y1,w,h,x2,y2,row,col,ul_row,ul_col,lr_row,lr_col;
+
+ if (MultiListShadeSurplus(mlw))
+ shade_gc = MultiListGrayGC(mlw);
+ else
+ shade_gc = MultiListEraseGC(mlw);
+ if (event == NULL)
+ {
+ XFillRectangle(XtDisplay(mlw),XtWindow(mlw),shade_gc,0,0,
+ MultiListWidth(mlw),MultiListHeight(mlw));
+ for (i = 0; i < MultiListNumItems(mlw); i++) RedrawItem(mlw,i);
+ }
+ else
+ {
+ x1 = event->xexpose.x;
+ y1 = event->xexpose.y;
+ w = event->xexpose.width;
+ h = event->xexpose.height;
+ x2 = x1 + w;
+ y2 = y1 + h;
+ XFillRectangle(XtDisplay(mlw),XtWindow(mlw),
+ shade_gc,x1,y1,w,h);
+ PixelToRowColumn(mlw,x1,y1,&ul_row,&ul_col);
+ PixelToRowColumn(mlw,x2,y2,&lr_row,&lr_col);
+ lr_row = min(lr_row,MultiListNumRows(mlw) - 1);
+ lr_col = min(lr_col,MultiListNumCols(mlw) - 1);
+ for (col = ul_col; col <= lr_col; col++)
+ {
+ for (row = ul_row; row <= lr_row; row++)
+ {
+ RedrawRowColumn(mlw,row,col);
+ }
+ }
+ }
+} /* End Redisplay */
+
+
+/*---------------------------------------------------------------------------*
+
+ PreferredGeometry(mlw,parent_idea,our_idea)
+
+ This routine is called by the parent to tell us about the
+ parent's idea of our width and/or height. We then suggest
+ our preference through <our_idea> and return the information
+ to the parent.
+
+ *---------------------------------------------------------------------------*/
+
+static XtGeometryResult PreferredGeometry(mlw,parent_idea,our_idea)
+XfwfMultiListWidget mlw;
+XtWidgetGeometry *parent_idea,*our_idea;
+{
+ Dimension nw,nh;
+ Boolean parent_wants_w,parent_wants_h,we_changed_size;
+
+ parent_wants_w = (parent_idea->request_mode) & CWWidth;
+ parent_wants_h = (parent_idea->request_mode) & CWHeight;
+
+ if (parent_wants_w)
+ nw = parent_idea->width;
+ else
+ nw = MultiListWidth(mlw);
+
+ if (parent_wants_h)
+ nh = parent_idea->height;
+ else
+ nh = MultiListHeight(mlw);
+
+ our_idea->request_mode = 0;
+ if (!parent_wants_w && !parent_wants_h) return(XtGeometryYes);
+
+ we_changed_size = Layout(mlw,!parent_wants_w,!parent_wants_h,&nw,&nh);
+ our_idea->request_mode |= (CWWidth | CWHeight);
+ our_idea->width = nw;
+ our_idea->height = nh;
+
+ if (we_changed_size)
+ return(XtGeometryAlmost);
+ else
+ return(XtGeometryYes);
+} /* End PreferredGeometry */
+
+
+/*---------------------------------------------------------------------------*
+
+ Resize(mlw)
+
+ This function is called when the widget is being resized. It
+ recalculates the layout of the widget.
+
+ *---------------------------------------------------------------------------*/
+
+static void Resize(mlw)
+XfwfMultiListWidget mlw;
+{
+ Dimension width,height;
+
+ width = MultiListWidth(mlw);
+ height = MultiListHeight(mlw);
+ Layout(mlw,False,False,&width,&height);
+} /* End Resize */
+
+
+/*---------------------------------------------------------------------------*
+
+ SetValues(cpl,rpl,npl)
+
+ This routine is called when the user is changing resources. <cpl>
+ is the current widget before the user's changes have been instituted.
+ <rpl> includes the original changes as requested by the user. <npl>
+ is the new resulting widget with the requested changes and with all
+ superclass changes already made.
+
+ *---------------------------------------------------------------------------*/
+
+/*ARGSUSED*/
+static Boolean SetValues(cpl,rpl,npl)
+XfwfMultiListWidget cpl,rpl,npl;
+{
+ Boolean redraw,recalc;
+
+ redraw = False;
+ recalc = False;
+
+ /* Graphic Context Changes */
+
+ if ((MultiListFG(cpl) != MultiListFG(npl)) ||
+ (MultiListBG(cpl) != MultiListBG(npl)) ||
+ (MultiListHighlightFG(cpl) != MultiListHighlightFG(npl)) ||
+ (MultiListHighlightBG(cpl) != MultiListHighlightBG(npl)) ||
+ (MultiListFont(cpl) != MultiListFont(npl)))
+ {
+ XtDestroyGC(MultiListEraseGC(cpl));
+ XtDestroyGC(MultiListDrawGC(cpl));
+ XtDestroyGC(MultiListHighlightForeGC(cpl));
+ XtDestroyGC(MultiListHighlightBackGC(cpl));
+ XtDestroyGC(MultiListGrayGC(cpl));
+ CreateNewGCs(npl);
+ redraw = True;
+ }
+
+ /* Changes That Require Redraw */
+
+ if ((MultiListSensitive(cpl) != MultiListSensitive(npl)) ||
+ (MultiListAncesSensitive(cpl) != MultiListAncesSensitive(npl)))
+ {
+ redraw = True;
+ }
+
+ /* Changes That Require Selection Changes */
+
+ if ((MultiListMaxSelectable(cpl) != MultiListMaxSelectable(npl)))
+ {
+ XtWarning("Dynamic change to maxSelectable unimplemented");
+ }
+
+ /* Changes That Require Data Initialization */
+
+ if ((MultiListList(cpl) != MultiListList(npl)) ||
+ (MultiListNumItems(cpl) != MultiListNumItems(npl)) ||
+ (MultiListSensitiveArray(cpl) != MultiListSensitiveArray(npl)))
+ {
+ DestroyOldData(cpl);
+ InitializeNewData(npl);
+ recalc = True;
+ redraw = True;
+ }
+
+ if (MultiListTabList(cpl) != MultiListTabList(npl))
+ {
+ if (MultiListTabs(cpl))
+ XtFree( (char *) MultiListTabs(cpl));
+ MultiListTabs(npl) = XfwfTablist2Tabs(MultiListTabList(npl));
+ }
+
+ /* Changes That Require Recalculating Coordinates */
+
+ if ((MultiListWidth(cpl) != MultiListWidth(npl)) ||
+ (MultiListHeight(cpl) != MultiListHeight(npl)) ||
+ (MultiListColumnSpace(cpl) != MultiListColumnSpace(npl)) ||
+ (MultiListRowSpace(cpl) != MultiListRowSpace(npl)) ||
+ (MultiListDefaultCols(cpl) != MultiListDefaultCols(npl)) ||
+ ((MultiListForceCols(cpl) != MultiListForceCols(npl)) &&
+ (MultiListNumCols(cpl) != MultiListNumCols(npl))) ||
+ (MultiListRowMajor(cpl) != MultiListRowMajor(npl)) ||
+ (MultiListFont(cpl) != MultiListFont(npl)) ||
+ (MultiListLongest(cpl) != MultiListLongest(npl)))
+ {
+ recalc = True;
+ redraw = True;
+ }
+
+ if (MultiListColWidth(cpl) != MultiListColWidth(npl))
+ {
+ XtWarning("columnWidth Resource Is Read-Only");
+ MultiListColWidth(npl) = MultiListColWidth(cpl);
+ }
+ if (MultiListRowHeight(cpl) != MultiListRowHeight(npl))
+ {
+ XtWarning("rowHeight Resource Is Read-Only");
+ MultiListRowHeight(npl) = MultiListRowHeight(cpl);
+ }
+
+ if (recalc)
+ {
+ RecalcCoords(npl,!MultiListWidth(npl),!MultiListHeight(npl));
+ }
+
+ if (!XtIsRealized((Widget)cpl))
+ return(False);
+ else
+ return(redraw);
+} /* End SetValues */
+
+/*===========================================================================*
+
+ D A T A I N I T I A L I Z A T I O N
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ DestroyOldData(mlw)
+
+ This routine frees the internal list item array and sets the
+ item count to 0. This is normally done immediately before
+ calling InitializeNewData() to rebuild the internal item
+ array from new user specified arrays.
+
+ *---------------------------------------------------------------------------*/
+
+static void DestroyOldData(mlw)
+XfwfMultiListWidget mlw;
+{
+ int i;
+
+ if (MultiListItemArray(mlw) != NULL) /* Free Old List */
+ {
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ free(MultiListItemString(MultiListNthItem(mlw,i)));
+ }
+ free((char *)MultiListItemArray(mlw));
+ }
+ if (MultiListSelArray(mlw) != NULL)
+ free((char *)MultiListSelArray(mlw));
+ MultiListSelArray(mlw) = NULL;
+ MultiListNumSelected(mlw) = 0;
+ MultiListItemArray(mlw) = NULL;
+ MultiListNumItems(mlw) = 0;
+} /* End DestroyOldData */
+
+
+/*---------------------------------------------------------------------------*
+
+ InitializeNewData(mlw)
+
+ This routine takes a MultiList widget <mlw> and builds up new
+ data item tables based on the string list and the sensitivity array.
+ All previous data should have already been freed. If the number
+ of items is 0, they will be counted, so the array must be NULL
+ terminated. If the list of strings is NULL, this is treated as
+ a list of 0 elements. If the sensitivity array is NULL, all
+ items are treated as sensitive.
+
+ When this routine is done, the string list and sensitivity array
+ fields will all be set to NULL, and the widget will not reference
+ them again.
+
+ *---------------------------------------------------------------------------*/
+
+static void InitializeNewData(mlw)
+XfwfMultiListWidget mlw;
+{
+ int i;
+ XfwfMultiListItem *item;
+ String *string_array;
+
+ string_array = MultiListList(mlw);
+ if (string_array == NULL) MultiListNumItems(mlw) = 0;
+
+ if (MultiListNumItems(mlw) == 0) /* Count Elements */
+ {
+ if (string_array == NULL) /* No elements */
+ {
+ MultiListNumItems(mlw) = 0;
+ }
+ else
+ {
+ for (i = 0; string_array[i] != NULL; i++);
+ MultiListNumItems(mlw) = i;
+ }
+ }
+ if (MultiListNumItems(mlw) == 0) /* No Items */
+ {
+ MultiListItemArray(mlw) = NULL;
+ }
+ else
+ {
+ MultiListItemArray(mlw) =
+ TypeAlloc(XfwfMultiListItem,MultiListNumItems(mlw));
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ item = MultiListNthItem(mlw,i);
+ if (MultiListSensitiveArray(mlw) == NULL ||
+ (MultiListSensitiveArray(mlw)[i] == True))
+ {
+ MultiListItemSensitive(item) = True;
+ }
+ else
+ {
+ MultiListItemSensitive(item) = False;
+ }
+ MultiListItemString(item) = StrCopy(string_array[i]);
+ MultiListItemHighlighted(item) = False;
+ }
+ }
+ if (MultiListMaxSelectable(mlw) == 0)
+ {
+ MultiListSelArray(mlw) = NULL;
+ MultiListNumSelected(mlw) = 0;
+ }
+ else
+ {
+ MultiListSelArray(mlw) =
+ TypeAlloc(int,MultiListMaxSelectable(mlw));
+ MultiListNumSelected(mlw) = 0;
+ }
+
+ MultiListList(mlw) = NULL;
+ MultiListSensitiveArray(mlw) = NULL;
+} /* End InitializeNewData */
+
+
+/*---------------------------------------------------------------------------*
+
+ CreateNewGCs(mlw)
+
+ This routine takes a MultiList widget <mlw> and creates a new set of
+ graphic contexts for the widget based on the colors, fonts, etc.
+ in the widget. Any previous GCs are assumed to have already been
+ destroyed.
+
+ *---------------------------------------------------------------------------*/
+
+static void CreateNewGCs(mlw)
+XfwfMultiListWidget mlw;
+{
+ XGCValues values;
+ unsigned int attribs;
+#ifndef USE_XMU_STIPPLE
+ Screen *screen = XtScreen((Widget)mlw);
+ Display *display = XtDisplay((Widget)mlw);
+ int pixmap_width = 2, pixmap_height = 2;
+ static unsigned char pixmap_bits[] = {
+ 0x02, 0x01,
+ };
+#endif
+
+ attribs = GCForeground | GCBackground | GCFont;
+ values.foreground = MultiListFG(mlw);
+ values.background = MultiListBG(mlw);
+ values.font = MultiListFont(mlw)->fid;
+ MultiListDrawGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
+
+ values.foreground = MultiListBG(mlw);
+ MultiListEraseGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
+
+ values.foreground = MultiListHighlightFG(mlw);
+ values.background = MultiListHighlightBG(mlw);
+ MultiListHighlightForeGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
+
+ values.foreground = MultiListHighlightBG(mlw);
+ values.background = MultiListHighlightBG(mlw);
+ MultiListHighlightBackGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
+
+ attribs |= GCTile | GCFillStyle;
+ values.foreground = MultiListFG(mlw);
+ values.background = MultiListBG(mlw);
+ values.fill_style = FillTiled;
+#ifdef USE_XMU_STIPPLE
+ values.tile = XmuCreateStippledPixmap(XtScreen(mlw),
+ MultiListFG(mlw),
+ MultiListBG(mlw),
+ MultiListDepth(mlw));
+#else
+ values.tile = XCreatePixmapFromBitmapData (display,
+ RootWindowOfScreen(screen),
+ (char *)pixmap_bits,
+ pixmap_width, pixmap_height,
+ MultiListFG(mlw),
+ MultiListBG(mlw),
+ MultiListDepth(mlw));
+#endif
+ MultiListGrayGC(mlw) = XtGetGC((Widget)mlw,attribs,&values);
+} /* End CreateNewGCs */
+
+/*===========================================================================*
+
+ L A Y O U T A N D G E O M E T R Y M A N A G E M E N T
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ RecalcCoords(mlw,width_changeable,height_changeable)
+
+ This routine takes a MultiList widget <mlw> and recalculates
+ the coordinates, and item placement based on the current
+ width, height, and list of items. The <width_changeable> and
+ <height_changeable> indicate if the width and/or height can
+ be arbitrarily set.
+
+ This routine requires that the internal list data be initialized.
+
+ *---------------------------------------------------------------------------*/
+
+#if NeedFunctionPrototypes
+static void
+RecalcCoords(XfwfMultiListWidget mlw,
+ Boolean width_changeable, Boolean height_changeable)
+#else
+static void
+RecalcCoords(mlw,width_changeable,height_changeable)
+XfwfMultiListWidget mlw;
+Boolean width_changeable,height_changeable;
+#endif
+{
+ String str;
+ Dimension width,height;
+ register int i,text_width;
+
+ width = MultiListWidth(mlw);
+ height = MultiListHeight(mlw);
+ if (MultiListNumItems(mlw) != 0 && MultiListLongest(mlw) == 0)
+ {
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ str = MultiListItemString(MultiListNthItem(mlw,i));
+ text_width = FontW(MultiListFont(mlw),str,mlw);
+ MultiListLongest(mlw) = max(MultiListLongest(mlw),
+ text_width);
+ }
+ }
+ if (Layout(mlw,width_changeable,height_changeable,&width,&height))
+ {
+ NegotiateSizeChange(mlw,width,height);
+ }
+} /* End RecalcCoords */
+
+
+/*---------------------------------------------------------------------------*
+
+ NegotiateSizeChange(mlw,width,height)
+
+ This routine tries to change the MultiList widget <mlw> to have the
+ new size <width> by <height>. A negotiation will takes place
+ to try to change the size. The resulting size is not necessarily
+ the requested size.
+
+ *---------------------------------------------------------------------------*/
+
+#if NeedFunctionPrototypes
+static void
+NegotiateSizeChange(XfwfMultiListWidget mlw, Dimension width, Dimension height)
+#else
+static void
+NegotiateSizeChange(mlw,width,height)
+XfwfMultiListWidget mlw;
+Dimension width,height;
+#endif
+{
+ int attempt_number;
+ Boolean w_fixed,h_fixed;
+ Dimension *w_ptr,*h_ptr;
+
+ XtWidgetGeometry request,reply;
+
+ request.request_mode = CWWidth | CWHeight;
+ request.width = width;
+ request.height = height;
+
+ for (attempt_number = 1; attempt_number <= 3; attempt_number++)
+ {
+ switch (XtMakeGeometryRequest((Widget)mlw,&request,&reply))
+ {
+ case XtGeometryYes:
+ case XtGeometryNo:
+ return;
+ case XtGeometryAlmost:
+ switch (attempt_number)
+ {
+ case 1:
+ w_fixed = (request.width != reply.width);
+ h_fixed = (request.height != reply.height);
+ w_ptr = &(reply.width);
+ h_ptr = &(reply.height);
+ Layout(mlw,!w_fixed,!h_fixed,w_ptr,h_ptr);
+ break;
+ case 2:
+ w_ptr = &(reply.width);
+ h_ptr = &(reply.height);
+ Layout(mlw,False,False,w_ptr,h_ptr);
+ break;
+ case 3:
+ return;
+ }
+ break;
+ default:
+ XtAppWarning(XtWidgetToApplicationContext((Widget)mlw),
+ "MultiList Widget: Unknown geometry return.");
+ break;
+ }
+ request = reply;
+ }
+} /* End NegotiateSizeChange */
+
+
+/*---------------------------------------------------------------------------*
+
+ Boolean Layout(mlw,w_changeable,h_changeable,w_ptr,h_ptr)
+
+ This routine tries to generate a layout for the MultiList widget
+ <mlw>. The Layout routine is free to arbitrarily set the width
+ or height if the corresponding variables <w_changeable> and
+ <h_changeable> are set True. Otherwise the original width or
+ height in <w_ptr> and <h_ptr> are used as fixed values. The
+ resulting new width and height are stored back through the
+ <w_ptr> and <h_ptr> pointers. False is returned if no size
+ change was done, True is returned otherwise.
+
+ *---------------------------------------------------------------------------*/
+
+#if NeedFunctionPrototypes
+static Boolean
+Layout(XfwfMultiListWidget mlw, Boolean w_changeable, Boolean h_changeable,
+ Dimension *w_ptr, Dimension *h_ptr)
+#else
+static Boolean
+Layout(mlw,w_changeable,h_changeable,w_ptr,h_ptr)
+XfwfMultiListWidget mlw;
+Boolean w_changeable,h_changeable;
+Dimension *w_ptr,*h_ptr;
+#endif
+{
+ Boolean size_changed = False;
+
+ /*
+ * If force columns is set, then always use the number
+ * of columns specified by default_cols.
+ */
+
+ MultiListColWidth(mlw) = MultiListLongest(mlw) +
+ MultiListColumnSpace(mlw);
+ MultiListRowHeight(mlw) = FontH(MultiListFont(mlw)) +
+ MultiListRowSpace(mlw);
+ if (MultiListForceCols(mlw))
+ {
+ MultiListNumCols(mlw) = max(MultiListDefaultCols(mlw),1);
+ if (MultiListNumItems(mlw) == 0)
+ MultiListNumRows(mlw) = 1;
+ else
+ MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) /
+ MultiListNumCols(mlw) + 1;
+ if (w_changeable)
+ {
+ *w_ptr = MultiListNumCols(mlw) *
+ MultiListColWidth(mlw);
+ size_changed = True;
+ }
+ else
+ {
+ MultiListColWidth(mlw) = *w_ptr /
+ (Dimension)MultiListNumCols(mlw);
+ }
+ if (h_changeable)
+ {
+ *h_ptr = MultiListNumRows(mlw) *
+ MultiListRowHeight(mlw);
+ size_changed = True;
+ }
+ return(size_changed);
+ }
+
+ /*
+ * If both width and height are free to change then use
+ * default_cols to determine the number of columns and set
+ * the new width and height to just fit the window.
+ */
+
+ if (w_changeable && h_changeable)
+ {
+ MultiListNumCols(mlw) = max(MultiListDefaultCols(mlw),1);
+ if (MultiListNumItems(mlw) == 0)
+ MultiListNumRows(mlw) = 1;
+ else
+ MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) /
+ MultiListNumCols(mlw) + 1;
+ *w_ptr = MultiListNumCols(mlw) * MultiListColWidth(mlw);
+ *h_ptr = MultiListNumRows(mlw) * MultiListRowHeight(mlw);
+ return(True);
+ }
+
+ /*
+ * If the width is fixed then use it to determine the
+ * number of columns. If the height is free to move
+ * (width still fixed) then resize the height of the
+ * widget to fit the current MultiList exactly.
+ */
+
+ if (!w_changeable)
+ {
+ MultiListNumCols(mlw) = *w_ptr / MultiListColWidth(mlw);
+ MultiListNumCols(mlw) = max(MultiListNumCols(mlw),1);
+ MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) /
+ MultiListNumCols(mlw) + 1;
+ MultiListColWidth(mlw) = *w_ptr / (Dimension)MultiListNumCols(mlw);
+ if (h_changeable)
+ {
+ *h_ptr = MultiListNumRows(mlw) * MultiListRowHeight(mlw);
+ size_changed = True;
+ }
+ return(size_changed);
+ }
+
+ /*
+ * The last case is xfree and !yfree we use the height to
+ * determine the number of rows and then set the width to
+ * just fit the resulting number of columns.
+ */
+
+ MultiListNumRows(mlw) = *h_ptr / MultiListRowHeight(mlw);
+ MultiListNumRows(mlw) = max(MultiListNumRows(mlw),1);
+ MultiListNumCols(mlw) = (MultiListNumItems(mlw) - 1) /
+ MultiListNumRows(mlw) + 1;
+ *w_ptr = MultiListNumCols(mlw) * MultiListColWidth(mlw);
+ return(True);
+} /* End Layout */
+
+/*===========================================================================*
+
+ R E D R A W R O U T I N E S
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ RedrawAll(mlw)
+
+ This routine simple calls Redisplay to redraw the entire
+ MultiList widget <mlw>.
+
+ *---------------------------------------------------------------------------*/
+
+static void RedrawAll(mlw)
+XfwfMultiListWidget mlw;
+{
+ Redisplay(mlw,NULL,NULL);
+} /* End RedrawAll */
+
+
+/*---------------------------------------------------------------------------*
+
+ RedrawItem(mlw,item_index)
+
+ This routine redraws the item with index <item_index> in the
+ MultiList widget <mlw>. If the item number is bad, nothing is drawn.
+
+ *---------------------------------------------------------------------------*/
+
+static void RedrawItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+{
+ int row,column;
+
+ if (ItemToRowColumn(mlw,item_index,&row,&column))
+ {
+ RedrawRowColumn(mlw,row,column);
+ }
+} /* End RedrawItem */
+
+
+/*---------------------------------------------------------------------------*
+
+ RedrawRowColumn(mlw,row,column)
+
+ This routine paints the item in row/column position <row>,<column>
+ on the MultiList widget <mlw>. If the row/column coordinates are
+ outside the widget, nothing is drawn. If the position is empty,
+ blank space is drawn.
+
+ *---------------------------------------------------------------------------*/
+
+static void RedrawRowColumn(mlw,row,column)
+XfwfMultiListWidget mlw;
+int row,column;
+{
+ GC bg_gc,fg_gc;
+ XfwfMultiListItem *item;
+ int ul_x,ul_y,str_x,str_y,w,h,item_index,has_item,text_h;
+
+ if (!XtIsRealized((Widget)mlw)) return;
+ has_item = RowColumnToItem(mlw,row,column,&item_index);
+ RowColumnToPixels(mlw,row,column,&ul_x,&ul_y,&w,&h);
+
+ if (has_item == False) /* No Item */
+ {
+ if (MultiListShadeSurplus(mlw))
+ bg_gc = MultiListGrayGC(mlw);
+ else
+ bg_gc = MultiListEraseGC(mlw);
+ }
+ else
+ {
+ item = MultiListNthItem(mlw,item_index);
+ if ((!MultiListSensitive(mlw)) ||
+ (!MultiListItemSensitive(item))) /* Insensitive */
+ {
+ if (MultiListItemHighlighted(item)) /* Selected */
+ {
+ bg_gc = MultiListGrayGC(mlw);
+ fg_gc = MultiListEraseGC(mlw);
+ }
+ else /* !Selected */
+ {
+ bg_gc = MultiListEraseGC(mlw);
+ fg_gc = MultiListGrayGC(mlw);
+ }
+ }
+ else /* Sensitive */
+ {
+ if (MultiListItemHighlighted(item)) /* Selected */
+ {
+ bg_gc = MultiListHighlightBackGC(mlw);
+ fg_gc = MultiListHighlightForeGC(mlw);
+ }
+ else /* !Selected */
+ {
+ bg_gc = MultiListEraseGC(mlw);
+ fg_gc = MultiListDrawGC(mlw);
+ }
+ }
+ }
+ XFillRectangle(XtDisplay(mlw),XtWindow(mlw),bg_gc,ul_x,ul_y,w,h);
+ if (has_item == True)
+ {
+ text_h = min(FontH(MultiListFont(mlw)) +
+ (int)MultiListRowSpace(mlw),(int)MultiListRowHeight(mlw));
+ str_x = ul_x + MultiListColumnSpace(mlw) / 2;
+ str_y = ul_y + FontAscent(MultiListFont(mlw)) +
+ ((int)MultiListRowHeight(mlw) - text_h) / 2;
+ XfwfDrawString(XtDisplay(mlw),XtWindow(mlw),fg_gc,
+ str_x,str_y,MultiListItemString(item),
+ strlen(MultiListItemString(item)),
+ MultiListTabs(mlw));
+ }
+} /* End RedrawRowColumn */
+
+/*===========================================================================*
+
+ I T E M L O C A T I O N R O U T I N E S
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr)
+
+ This routine takes pixel coordinates <x>, <y> and converts
+ the pixel coordinate into a row/column coordinate. This row/column
+ coordinate can then easily be converted into the specific item
+ in the list via the function RowColumnToItem().
+
+ If the pixel lies in blank space outside of the items, the
+ row & column numbers will be outside of the range of normal
+ row & columns numbers, but will correspond to the row & column
+ of the item, if an item was actually there.
+
+ *---------------------------------------------------------------------------*/
+
+static void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr)
+XfwfMultiListWidget mlw;
+int x,y,*row_ptr,*column_ptr;
+{
+ *row_ptr = y / (int)MultiListRowHeight(mlw);
+ *column_ptr = x / (int)MultiListColWidth(mlw);
+} /* End PixelToRowColumn */
+
+/*---------------------------------------------------------------------------*
+
+ void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr)
+
+ This routine takes a row/column coordinate <row>,<col> and
+ converts it into the bounding pixel rectangle which is returned.
+
+ *---------------------------------------------------------------------------*/
+
+static void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr)
+XfwfMultiListWidget mlw;
+int row,col,*x_ptr,*y_ptr,*w_ptr,*h_ptr;
+{
+ *x_ptr = col * MultiListColWidth(mlw);
+ *y_ptr = row * MultiListRowHeight(mlw);
+ *w_ptr = MultiListColWidth(mlw);
+ *h_ptr = MultiListRowHeight(mlw);
+} /* End RowColumnToPixels */
+
+/*---------------------------------------------------------------------------*
+
+ Boolean RowColumnToItem(mlw,row,column,item_ptr)
+
+ This routine takes a row number <row> and a column number <column>
+ and tries to resolve this row and column into the index of the
+ item in this position of the MultiList widget <mlw>. The resulting
+ item index is placed through <item_ptr>. If there is no item at
+ this location, False is returned, else True is returned.
+
+ *---------------------------------------------------------------------------*/
+
+static Boolean RowColumnToItem(mlw,row,column,item_ptr)
+XfwfMultiListWidget mlw;
+int row,column,*item_ptr;
+{
+ register int x_stride,y_stride;
+
+ if (row < 0 || row >= MultiListNumRows(mlw) ||
+ column < 0 || column >= MultiListNumCols(mlw))
+ {
+ return(False);
+ }
+ if (MultiListRowMajor(mlw))
+ {
+ x_stride = 1;
+ y_stride = MultiListNumCols(mlw);
+ }
+ else
+ {
+ x_stride = MultiListNumRows(mlw);
+ y_stride = 1;
+ }
+ *item_ptr = row * y_stride + column * x_stride;
+ if (*item_ptr >= MultiListNumItems(mlw))
+ return(False);
+ else
+ return(True);
+} /* End RowColumnToItem */
+
+
+/*---------------------------------------------------------------------------*
+
+ Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr)
+
+ This routine takes an item number <item_index> and attempts
+ to convert the index into row and column numbers stored through
+ <row_ptr> and <column_ptr>. If the item number does not
+ corespond to a valid item, False is returned, else True is
+ returned.
+
+ *---------------------------------------------------------------------------*/
+
+static Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr)
+XfwfMultiListWidget mlw;
+int item_index,*row_ptr,*column_ptr;
+{
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw))
+ {
+ return(False);
+ }
+ if (MultiListRowMajor(mlw))
+ {
+ *row_ptr = item_index / MultiListNumCols(mlw);
+ *column_ptr = item_index % MultiListNumCols(mlw);
+ }
+ else
+ {
+ *row_ptr = item_index % MultiListNumRows(mlw);
+ *column_ptr = item_index / MultiListNumRows(mlw);
+ }
+ return(True);
+} /* End ItemToRowColumn */
+
+/*===========================================================================*
+
+ E V E N T A C T I O N H A N D L E R S
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ Select(mlw,event,params,num_params)
+
+ This action handler is called when a user selects an item in the
+ MultiList. This action first unselects all previously selected
+ items, then selects the item under the mouse, if it is not a
+ background gap, and if it is sensitive.
+
+ The MultiListMostRecentItem(mlw) variable will be set to the
+ item clicked on, or -1 if the item is background or insensitive.
+ The MultiListMostRecentAct(mlw) variable will be set to
+ XfwfMultiListActionHighlight, in case the selection region is extended.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Select(mlw,event,params,num_params)
+XfwfMultiListWidget mlw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ int click_x,click_y;
+ int status,item_index,row,column;
+
+ click_x = event->xbutton.x;
+ click_y = event->xbutton.y;
+ PixelToRowColumn(mlw,click_x,click_y,&row,&column);
+ XfwfMultiListUnhighlightAll(mlw);
+ MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight;
+ status = RowColumnToItem(mlw,row,column,&item_index);
+ if ((status == False) ||
+ (!MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
+ {
+ MultiListMostRecentItem(mlw) = -1;
+ }
+ else
+ {
+ MultiListMostRecentItem(mlw) = item_index;
+ XfwfMultiListHighlightItem(mlw,item_index);
+ }
+} /* End Select */
+
+
+/*---------------------------------------------------------------------------*
+
+ Unselect(mlw,event,params,num_params)
+
+ This function unselects the single text item pointed to by the
+ mouse, if any. Any remaining selected entries are left selected.
+
+ The MultiListMostRecentItem(mlw) variable will be set to -1, and
+ the MultiListMostRecentAct(mlw) variable will be set to
+ XfwfMultiListActionUnhighlight, in case the deselection region is
+ extended.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Unselect(mlw,event,params,num_params)
+XfwfMultiListWidget mlw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ int click_x,click_y;
+ int status,item_index,row,column;
+
+ click_x = event->xbutton.x;
+ click_y = event->xbutton.y;
+ PixelToRowColumn(mlw,click_x,click_y,&row,&column);
+ MultiListMostRecentItem(mlw) = -1;
+ MultiListMostRecentAct(mlw) = XfwfMultiListActionUnhighlight;
+ status = RowColumnToItem(mlw,row,column,&item_index);
+ if ((status == True) &&
+ (MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
+ /* ### NOAO #### (was ListHighlight) */
+ XfwfMultiListUnhighlightItem(mlw,item_index);
+} /* End Unselect */
+
+
+/*---------------------------------------------------------------------------*
+
+ Toggle(mlw,event,params,num_params)
+
+ This action handler implements the toggling of selection status
+ for a single item. Any remaining selected entries are left selected.
+
+ If the mouse is not over a selectable text item, the
+ MultiListMostRecentAct(mlw) variable is set to
+ XfwfMultiListActionHighlight, in case the region is extended into
+ selectable items later. MultiListMostRecentItem(mlw) is set to -1.
+
+ If the mouse is over a selectable text item, the item highlight is
+ toggled. If the item is currently selected, it becomes deselected.
+ If unselected, the item becomes selected. At the same time, the
+ MultiListMostRecentAct(mlw) variable is set to
+ XfwfMultiListActionHighlight if the item was not previously selected,
+ or XfwfMultiListActionUnhighlight if the item was previously selected.
+ MultiListMostRecentItem(mlw) is set to the index of the item clicked
+ on if the item is selected, or -1 if it is unselected.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Toggle(mlw,event,params,num_params)
+XfwfMultiListWidget mlw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ int click_x,click_y;
+ int status,item_index,row,column;
+
+ click_x = event->xbutton.x;
+ click_y = event->xbutton.y;
+ PixelToRowColumn(mlw,click_x,click_y,&row,&column);
+ status = RowColumnToItem(mlw,row,column,&item_index);
+ if ((status == False) ||
+ (!MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
+ {
+ MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight;
+ MultiListMostRecentItem(mlw) = -1;
+ }
+ else
+ {
+ MultiListMostRecentAct(mlw) =
+ XfwfMultiListToggleItem(mlw,item_index);
+ MultiListMostRecentItem(mlw) = item_index;
+ }
+} /* End Toggle */
+
+
+/*---------------------------------------------------------------------------*
+
+ Extend(mlw,event,params,num_params)
+
+ This action handler implements the extension of a selection/
+ deselection region.
+
+ The MultiListMostRecentAct(mlw) variable is used to determine
+ if items are to be selected or unselected. This routine performs
+ select or unselect actions on each item it is called on.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Extend(mlw,event,params,num_params)
+XfwfMultiListWidget mlw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ int click_x,click_y;
+ int status,item_index,row,column;
+
+ click_x = ((XMotionEvent*)event)->x;
+ click_y = ((XMotionEvent*)event)->y;
+ PixelToRowColumn(mlw,click_x,click_y,&row,&column);
+ status = RowColumnToItem(mlw,row,column,&item_index);
+ if ((status == True) &&
+ (MultiListItemSensitive(MultiListNthItem(mlw,item_index))))
+ {
+ MultiListMostRecentItem(mlw) = item_index;
+ if (MultiListMostRecentAct(mlw) == XfwfMultiListActionHighlight)
+ XfwfMultiListHighlightItem(mlw,item_index);
+ else
+ XfwfMultiListUnhighlightItem(mlw,item_index);
+ }
+} /* End Extend */
+
+
+/*---------------------------------------------------------------------------*
+
+ Notify(mlw,event,params,num_params)
+
+ This function performs the Notify action, which issues a callback
+ after a selection/unselection has completed. All callbacks on the
+ callback list are invoked, and a XfxfMultiListReturnStruct describing
+ the selection state is returned.
+
+ In addition, if the XtNpasteBuffer resource is true and at least one
+ text item is selected, all the selected items are placed in the X
+ cut buffer (buf(0)) separated by newlines.
+
+ *---------------------------------------------------------------------------*/
+
+/* ARGSUSED */
+static void Notify(mlw,event,params,num_params)
+XfwfMultiListWidget mlw;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ char *buffer;
+ String string;
+ int i,byte_count,item_index;
+ XfwfMultiListReturnStruct ret_value;
+
+ if ((MultiListNumSelected(mlw) != 0) && MultiListPaste(mlw))
+ {
+ byte_count = 0;
+ for (i = 0; i < MultiListNumSelected(mlw); i++)
+ {
+ item_index = MultiListSelArray(mlw)[i];
+ string = MultiListItemString(MultiListNthItem(mlw,
+ item_index));
+ byte_count = byte_count + strlen(string) + 1;
+ }
+ buffer = (char *)malloc(byte_count);
+ buffer[0] = '\0';
+ for (i = 0; i < MultiListNumSelected(mlw); i++)
+ {
+ if (i != 0) strcat(buffer,"\n");
+ item_index = MultiListSelArray(mlw)[i];
+ string = MultiListItemString(MultiListNthItem(mlw,
+ item_index));
+ strcat(buffer,string);
+ }
+ XStoreBytes(XtDisplay(mlw),buffer,byte_count);
+ free(buffer);
+ }
+
+ ret_value.action = MultiListMostRecentAct(mlw);
+ ret_value.item = MultiListMostRecentItem(mlw);
+ if (ret_value.item == -1)
+ ret_value.string = NULL;
+ else
+ ret_value.string = MultiListItemString(MultiListNthItem(mlw,
+ ret_value.item));
+ ret_value.num_selected = MultiListNumSelected(mlw);
+ ret_value.selected_items = MultiListSelArray(mlw);
+ XtCallCallbacks((Widget)mlw,XtNcallback,(caddr_t)&ret_value);
+} /* End Notify */
+
+/*===========================================================================*
+
+ U S E R C A L L A B L E U T I L I T Y R O U T I N E S
+
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+
+ Boolean XfwfMultiListHighlightItem(mlw,item_index)
+
+ This routine selects an item with index <item_index> in the
+ MultiList widget <mlw>. If a maximum number of selections is specified
+ and exceeded, the earliest selection will be unselected. If
+ <item_index> doesn't correspond to an item the most recently
+ clicked item will be set to -1 and this routine will immediately
+ return, otherwise the most recently clicked item will be set to the
+ current item. If the clicked on item is not sensitive, or if the
+ click is not on an item, False is returned, else True is returned.
+
+ *---------------------------------------------------------------------------*/
+
+Boolean XfwfMultiListHighlightItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+{
+ XfwfMultiListItem *item;
+
+ if (MultiListMaxSelectable(mlw) == 0) return(False);
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw))
+ {
+ MultiListMostRecentItem(mlw) = -1;
+ return(False);
+ }
+ item = MultiListNthItem(mlw,item_index);
+ if (MultiListItemSensitive(item) == False) return(False);
+ MultiListMostRecentItem(mlw) = item_index;
+ if (MultiListItemHighlighted(item) == True) return(True);
+ if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw))
+ {
+ XfwfMultiListUnhighlightItem(mlw,MultiListSelArray(mlw)[0]);
+ }
+ MultiListItemHighlighted(item) = True;
+ MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = item_index;
+ ++ MultiListNumSelected(mlw);
+ RedrawItem(mlw,item_index);
+ return(True);
+} /* End XfwfMultiListHighlightItem */
+
+
+/*---------------------------------------------------------------------------*
+
+ XfwfMultiListHighlightAll(mlw)
+
+ This routine highlights all highlightable items in the MultiList
+ widget <mlw>, up to the maximum number of allowed highlightable
+ items;
+
+ *---------------------------------------------------------------------------*/
+
+void XfwfMultiListHighlightAll(mlw)
+XfwfMultiListWidget mlw;
+{
+ int i;
+ XfwfMultiListItem *item;
+
+ MultiListNumSelected(mlw) = 0;
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ item = MultiListNthItem(mlw,i);
+ MultiListItemHighlighted(item) = False;
+ }
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw))
+ break;
+ item = MultiListNthItem(mlw,i);
+ if (MultiListItemSensitive(item) == False) continue;
+ MultiListItemHighlighted(item) = True;
+ MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = i;
+ ++ MultiListNumSelected(mlw);
+ }
+ RedrawAll(mlw);
+} /* End XfwfMultiListHighlightAll */
+
+
+/*---------------------------------------------------------------------------*
+
+ XfwfMultiListUnhighlightItem(mlw,item_index)
+
+ This routine unselects the item with index <item_index> in the
+ MultiList widget <mlw>. If <item_index> doesn't correspond to a
+ selected item, then nothing will happen. Otherwise, the item
+ is unselected and the selection array and count are updated.
+
+ *---------------------------------------------------------------------------*/
+
+void XfwfMultiListUnhighlightItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+{
+ int i;
+ XfwfMultiListItem *item;
+
+ if (MultiListMaxSelectable(mlw) == 0) return;
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return;
+ item = MultiListNthItem(mlw,item_index);
+ if (MultiListItemHighlighted(item) == False) return;
+ MultiListItemHighlighted(item) = False;
+
+ for (i = 0; i < MultiListNumSelected(mlw); i++)
+ if (MultiListSelArray(mlw)[i] == item_index) break;
+ for (i = i + 1; i < MultiListNumSelected(mlw); i++)
+ MultiListSelArray(mlw)[i - 1] = MultiListSelArray(mlw)[i];
+ -- MultiListNumSelected(mlw);
+
+ RedrawItem(mlw,item_index);
+} /* End XfwfMultiListUnhighlightItem */
+
+
+/*---------------------------------------------------------------------------*
+
+ XfwfMultiListUnhighlightAll(mlw)
+
+ This routine unhighlights all items in the MultiList widget <mlw>.
+
+ *---------------------------------------------------------------------------*/
+
+void XfwfMultiListUnhighlightAll(mlw)
+XfwfMultiListWidget mlw;
+{
+ int i;
+ XfwfMultiListItem *item;
+
+ for (i = 0; i < MultiListNumItems(mlw); i++)
+ {
+ item = MultiListNthItem(mlw,i);
+ if (MultiListItemHighlighted(item))
+ XfwfMultiListUnhighlightItem(mlw,i);
+ }
+ MultiListNumSelected(mlw) = 0;
+} /* End XfwfMultiListUnhighlightAll */
+
+
+/*---------------------------------------------------------------------------*
+
+ int XfwfMultiListToggleItem(mlw,item_index)
+
+ This routine highlights the item with index <item_index>
+ if it is unhighlighted and unhighlights it if it is already
+ highlighted. The action performed by the toggle is returned
+ (XfwfMultiListActionHighlight or XfwfMultiListActionUnhighlight).
+
+ *---------------------------------------------------------------------------*/
+
+int XfwfMultiListToggleItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+{
+ XfwfMultiListItem *item;
+
+ if (MultiListMaxSelectable(mlw) == 0)
+ return(XfwfMultiListActionNothing);
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw))
+ return(XfwfMultiListActionNothing);
+ item = MultiListNthItem(mlw,item_index);
+ if (MultiListItemSensitive(item) == False)
+ return(XfwfMultiListActionNothing);
+ if (MultiListItemHighlighted(item))
+ {
+ XfwfMultiListUnhighlightItem(mlw,item_index);
+ return(XfwfMultiListActionUnhighlight);
+ }
+ else
+ {
+ XfwfMultiListHighlightItem(mlw,item_index);
+ return(XfwfMultiListActionHighlight);
+ }
+} /* End XfwfMultiListToggleItem */
+
+
+/*---------------------------------------------------------------------------*
+
+ XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw)
+
+ This routine takes a MultiList widget <mlw> and returns a
+ XfwfMultiListReturnStruct whose num_selected and selected_items
+ fields contain the highlight information. The action field
+ is set to MULTILIST_ACTION_STATUS, and the item_index and string
+ fields are invalid.
+
+ *---------------------------------------------------------------------------*/
+
+XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw)
+XfwfMultiListWidget mlw;
+{
+ XfwfMultiListItem *item;
+ static XfwfMultiListReturnStruct ret_value;
+
+ ret_value.action = XfwfMultiListActionStatus;
+ if (MultiListNumSelected(mlw) == 0)
+ {
+ ret_value.item = -1;
+ ret_value.string = NULL;
+ }
+ else
+ {
+ ret_value.item = MultiListSelArray(mlw)
+ [MultiListNumSelected(mlw) - 1];
+ item = MultiListNthItem(mlw,ret_value.item);
+ ret_value.string = MultiListItemString(item);
+ }
+ ret_value.num_selected = MultiListNumSelected(mlw);
+ ret_value.selected_items = MultiListSelArray(mlw);
+ return(&ret_value);
+} /* End XfwfMultiListGetHighlighted */
+
+
+/*---------------------------------------------------------------------------*
+
+ Boolean XfwfMultiListIsHighlighted(mlw,item_index)
+
+ This routine checks if the item with index <item_index>
+ is highlighted and returns True or False depending. If
+ <item_index> is invalid, False is returned.
+
+ *---------------------------------------------------------------------------*/
+
+Boolean XfwfMultiListIsHighlighted(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+{
+ XfwfMultiListItem *item;
+
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw))
+ return(False);
+ item = MultiListNthItem(mlw,item_index);
+ return(MultiListItemHighlighted(item));
+} /* End XfwfMultiListIsHighlighted */
+
+
+/*---------------------------------------------------------------------------*
+
+ Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr)
+
+ This routine returns the string, highlight status and
+ sensitivity information for the item with index <item_index>
+ via the pointers <str_ptr>, <h_ptr> and <s_ptr>. If the item
+ index is invalid, False is returned, else True is returned.
+
+ *---------------------------------------------------------------------------*/
+
+Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr)
+XfwfMultiListWidget mlw;
+int item_index;
+String *str_ptr;
+Boolean *h_ptr,*s_ptr;
+{
+ XfwfMultiListItem *item;
+
+ if (item_index < 0 || item_index >= MultiListNumItems(mlw))
+ return(False);
+ item = MultiListNthItem(mlw,item_index);
+ *str_ptr = MultiListItemString(item);
+ *h_ptr = MultiListItemHighlighted(item);
+ *s_ptr = MultiListItemSensitive(item);
+ return(True);
+} /* End XfwfMultiListGetItemInfo */
+
+
+/*---------------------------------------------------------------------------*
+
+ XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,
+ sensitivity_array)
+
+ This routine will set a new set of strings <list> into the
+ MultiList widget <mlw>. If <resize> is True, the MultiList widget will
+ try to resize itself.
+
+ *---------------------------------------------------------------------------*/
+
+#if NeedFunctionPrototypes
+void
+XfwfMultiListSetNewData(XfwfMultiListWidget mlw, String *list,
+ int nitems, int longest, Boolean resize,
+ Boolean *sensitivity_array)
+#else
+void
+XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,sensitivity_array)
+XfwfMultiListWidget mlw;
+String *list;
+int nitems,longest;
+int resize;
+Boolean *sensitivity_array;
+#endif
+{
+ DestroyOldData(mlw);
+ MultiListList(mlw) = list;
+ MultiListNumItems(mlw) = max(nitems,0);
+ MultiListLongest(mlw) = max(longest,0);
+ MultiListSensitiveArray(mlw) = sensitivity_array;
+ InitializeNewData(mlw);
+ RecalcCoords(mlw,resize,resize);
+ if (XtIsRealized((Widget)mlw)) Redisplay(mlw,NULL,NULL);
+} /* End XfwfMultiListSetNewData */
diff --git a/vendor/x11iraf/obm/ObmW/MultiList.h b/vendor/x11iraf/obm/ObmW/MultiList.h
new file mode 100644
index 00000000..1727a454
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MultiList.h
@@ -0,0 +1,279 @@
+/****************************************************************************
+
+ MultiList.h
+
+ This file is the public header file for the MultiList widget, an
+ extension to the Athena List widget.
+
+ This code is loosely based on the Athena List source which
+ is why the MIT copyright notice appears below.
+
+ The code was changed substantially in V3.4 to change the
+ action/callback interface which was unnecessarily ugly. Code
+ using some features of the old interface may need to be changed.
+ Hope the changes don't make people's lives too miserable.
+
+ ****************************************************************************/
+
+/*
+ * Author:
+ * Brian Totty
+ * Department of Computer Science
+ * University Of Illinois at Urbana-Champaign
+ * 1304 West Springfield Avenue
+ * Urbana, IL 61801
+ *
+ * totty@cs.uiuc.edu
+ *
+ */
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Original Athena Author: Chris D. Peterson, MIT X Consortium
+ */
+
+#ifndef _MULTILIST_H_
+#define _MULTILIST_H_
+
+#include <X11/Xaw/Simple.h>
+
+/*---------------------------------------------------------------------------*
+
+ R E S O U R C E D E S C R I P T I O N S A N D N O T E S
+
+ *---------------------------------------------------------------------------*/
+
+/*
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback XtCallbackList NULL *1
+ columnWidth Width Dimension 0 *9
+ columnSpacing Spacing Dimension 8
+ cursor Cursor Cursor left_ptr
+ defaultColumns Columns int 1 *2
+ destroyCallback Callback Pointer NULL
+ font Font XFontStruct* XtDefaultFont
+ forceColumns Columns Boolean False *2
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension 0 *3
+ highlightBackground HBackground Pixel XtDefaultForeground *4
+ highlightForeground HForeground Pixel XtDefaultBackground *4
+ insensitiveBorder Insensitive Pixmap Gray
+ list List String * NULL *5
+ longest Longest int 0 *6
+ mappedWhenManaged MappedWhenManaged Boolean True
+ maxSelectable Value int 1 *7
+ numberStrings NumberStrings int 0 *5
+ pasteBuffer Boolean Boolean False
+ rowHeight Height Dimension 0 *9
+ rowSpacing Spacing Dimension 2
+ sensitive Sensitive Boolean True
+ sensitiveArray List Boolean * NULL *8
+ shadeSurplus Boolean Boolean True *10
+ verticalList Boolean Boolean False
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+ *1 - The callback functions are called whenever a highlight or unhighlight
+ takes place. More precisely, a callback occurs whenever the Notify()
+ action is triggered. By default, this occurs when the mouse button is
+ lifted after a selection or deselection occurred. The callback returns
+ an XfwfMultiListReturnStruct data structure which contains numerous
+ fields describing the selection state. The most important fields
+ indicate the total number of items selected, and a list of those items.
+
+ *2 - The defaultColumns resource is used in two cases. If forceColumns
+ is true, the widget will set the number of columns to the value of
+ default columns. If the widget width is unconstrained by the parent
+ widgets, the defaultColumns is also used to determine the number of
+ columns and the resulting width. Otherwise, the number of columns
+ will be calcultaed based on the current width and will be changed to
+ an appropriate value.
+
+ *3 - If the width or height is set to zero (0), which is the default case,
+ then the widget will calculate the size of that dimension to be just
+ large enough to hold the contents of the widget.
+
+ *4 - The highlightForeground and highlightBackground colors specify the
+ colors used to highlight the text (foreground) and the surrounding
+ background space of a list item when it is selected (highlighted).
+ The default is the reverse of the default foreground and background
+ colors.
+
+ *5 - The list resource is an array of strings (char * array) which tell
+ the names of each item of the list. The number of elements of this
+ array are indicated by the resource numberStrings. If numberStrings
+ is set to 0 (the default), then the MultiList widget will count the
+ number of strings in the list. This requires that the list be
+ NULL terminated. If list is NULL, then the widget treats it as an
+ empty list. Once the list is set the list resource is set to NULL,
+ so you won't be able to read back the list after it has been set. The
+ widgets copies the strings internally, so the user can free the list
+ storage after setting it.
+
+ *6 - This resource represent the longest string in pixels. If this
+ resource is zero (0), which is the default and probably the value
+ most people should use, the longest string length is calculated
+ and the resource is updated.
+
+ *7 - The maxSelectable resource indicates the maximum number of items
+ which can be selected at any one time. In the original Athena
+ widget, you could have at most one item selected at a time. In
+ this widget, you can choose how many will be selected at a time.
+
+ *8 - Each item in the MultiList can be made insensitive, so it is printed in
+ gray shading and can not be highlighted. This can be done by
+ setting the sensitivity list, which is an array of Booleans which
+ indicate whether or not the corresponding item is sensitive (can be
+ selected). If sensitivity list is NULL, all items are sensitive. The
+ widget copies the sensitivity information, so the user can delete the
+ sensitivity array storage after setting it. The widget sets the
+ resource to NULL after it has been set, so the user cannot read the
+ old list back.
+
+ *9 - These values are intended for reading only. They indicate the pixel
+ width/height of the column/row.
+
+ *10 - If the list height is made larger than the sum of the list entry
+ heights, the surplus space is shaded in the background color if
+ shadeSurplus is False, or in a gray stipple pattern if shadeSurplus
+ is True.
+
+*/
+
+/*---------------------------------------------------------------------------*
+
+ S T R I N G D E F I N I T I O N S
+
+ *---------------------------------------------------------------------------*/
+
+#define XtCList "List"
+#define XtCSpacing "Spacing"
+#define XtCColumns "Columns"
+#define XtCLongest "Longest"
+#define XtCNumberStrings "NumberStrings"
+#define XtCHForeground "HForeground"
+#define XtCHBackground "HBackground"
+
+#ifndef XtNcursor
+#define XtNcursor "cursor"
+#endif
+
+#define XtNhighlightForeground "highlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtNcolumnSpacing "columnSpacing"
+#define XtNrowSpacing "rowSpacing"
+#define XtNdefaultColumns "defaultColumns"
+#define XtNforceColumns "forceColumns"
+#define XtNpasteBuffer "pasteBuffer"
+#define XtNverticalList "verticalList"
+#define XtNlongest "longest"
+#define XtNnumberStrings "numberStrings"
+#define XtNlist "list"
+#define XtNsensitiveArray "sensitiveArray"
+#define XtNmaxSelectable "maxSelectable"
+#define XtNshadeSurplus "shadeSurplus"
+
+#define XtNrowHeight "rowHeight"
+#define XtNcolumnWidth "columnWidth"
+
+#ifndef XtNtablist
+#define XtNtablist "tablist"
+#endif
+#ifndef XtCTablist
+#define XtCTablist "Tablist"
+#endif
+
+ /* Class Record Constants */
+
+extern WidgetClass xfwfMultiListWidgetClass;
+
+typedef struct _XfwfMultiListClassRec *XfwfMultiListWidgetClass;
+typedef struct _XfwfMultiListRec *XfwfMultiListWidget;
+
+/*---------------------------------------------------------------------------*
+
+ R E T U R N S T R U C T U R E
+
+ *---------------------------------------------------------------------------*/
+
+#define XfwfMultiListActionNothing 0
+#define XfwfMultiListActionHighlight 1
+#define XfwfMultiListActionUnhighlight 2
+#define XfwfMultiListActionStatus 3
+
+typedef struct _XfwfMultiListReturnStruct
+{
+ int num_selected; /* Number Of Items Now Selected */
+ int *selected_items; /* Indexes Of Selected Items */
+
+ int action; /* Last Action Performed */
+ int item; /* Last Item Index Modified */
+ String string; /* String Of Last Index Modified */
+} XfwfMultiListReturnStruct;
+
+/*---------------------------------------------------------------------------*
+
+ U T I L I T Y R O U T I N E S
+
+ *---------------------------------------------------------------------------*/
+
+#if (!NeedFunctionPrototypes)
+
+extern Boolean XfwfMultiListHighlightItem();
+extern void XfwfMultiListHighlightAll();
+extern void XfwfMultiListUnhighlightItem();
+extern void XfwfMultiListUnhighlightAll();
+extern int XfwfMultiListToggleItem();
+extern XfwfMultiListReturnStruct *
+ XfwfMultiListGetHighlighted();
+extern Boolean XfwfMultiListIsHighlighted();
+extern Boolean XfwfMultiListGetItemInfo();
+extern void XfwfMultiListSetNewData();
+
+#else
+
+extern Boolean XfwfMultiListHighlightItem(XfwfMultiListWidget mlw,
+ int item_index);
+extern void XfwfMultiListHighlightAll(XfwfMultiListWidget mlw);
+extern void XfwfMultiListUnhighlightItem(XfwfMultiListWidget mlw,
+ int item_index);
+extern void XfwfMultiListUnhighlightAll(XfwfMultiListWidget mlw);
+extern int XfwfMultiListToggleItem(XfwfMultiListWidget mlw,
+ int item_index);
+extern XfwfMultiListReturnStruct *
+ XfwfMultiListGetHighlighted(XfwfMultiListWidget mlw);
+extern Boolean XfwfMultiListIsHighlighted(XfwfMultiListWidget mlw,
+ int item_index);
+extern Boolean XfwfMultiListGetItemInfo(XfwfMultiListWidget mlw,
+ int item_index, String *str_ptr,
+ Boolean *h_ptr, Boolean *s_ptr);
+extern void XfwfMultiListSetNewData(XfwfMultiListWidget mlw,
+ String *list, int nitems, int longest,
+ Boolean resize, Boolean *sensitivity_array);
+
+#endif
+#endif
diff --git a/vendor/x11iraf/obm/ObmW/MultiList.man b/vendor/x11iraf/obm/ObmW/MultiList.man
new file mode 100644
index 00000000..ee8f532a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MultiList.man
@@ -0,0 +1,207 @@
+'\" t
+.TH "MultiList" "3" "19 May 1992" "Version 3.4" "Free Widget Foundation"
+.SH Name
+MultiList \- list from which multiple entries can be selected
+.SH Synopsis
+#include <X11/Intrinsic.h>
+#include <X11/MultiList.h>
+
+widget = XtCreateManagedWidget(name, multiListWidgetClass, ...);
+.SH Class Hierarchy
+Core-->Simple-->MultiList
+.SH Description
+
+MultiList is a replacement for the Athena List widget, which allows
+multiple selections to be made. The aesthetics have also been
+slightly improved: the highlight colors can now be selected, and the
+selection extends across the entire width of the column rather than
+just the length of the string.
+
+The maximum number of multiple selections can be specified. Items are
+selected and unselected by an action interface. By default, mouse
+button 1 is used to select, unselect, and toggle items. When the
+mouse button is lifted, any callbacks in the callback list are called
+with a data structure which describes the count of select items, and
+lists the indices of the selected items. The return structure
+contains some additional information describing the last item modified
+and the last action performed, which will probably not be of general
+use, and I'd love to delete if I was sure that people didn't use them.
+(The behavior of these fields has changed slightly in V3.4).
+
+.SH Resources
+In addition to the resources defined by superclasses, this widget
+defines the following:
+.TS
+tab(/) ;
+lB lB lB lB.
+Name/Class/Type/Default
+.T&
+lB l l l.
+XtNbackground/Background/Pixel/XtDefaultBackground
+XtNborder/BorderColor/Pixel/XtDefaultForeground
+XtNborderWidth/BorderWidth/Dimension/1
+XtNcallback/Callback/XtCallbackList/NULL
+XtNcolumnWidth/Width/Dimension/0
+XtNcolumnSpacing/Spacing/Dimension/8
+XtNcursor/Cursor/Cursor/left_ptr
+XtNdefaultColumns/Columns/int/1
+XtNdestroyCallback/Callback/Pointer/NULL
+XtNfont/Font/XFontStruct/XtDefaultFont
+XtNforceColumns/Columns/Boolean/False
+XtNforeground/Foreground/Pixel/XtDefaultForeground
+XtNheight/Height/Dimension/0
+XtNhighlightBackground/HBackground/Pixel/XtDefaultForeground
+XtNhighlightForeground/HForeground/Pixel/XtDefaultBackground
+XtNinsensitiveBorder/Insensitive/Pixmap/Gray
+XtNlist/List/String/NULL
+XtNlongest/Longest/int/0
+XtNmappedWhenManaged/MappedWhenManaged/Boolean/True
+XtNmaxSelectable/Value/int/1
+XtNnumberStrings/NumberStrings/int/0
+XtNpasteBuffer/Boolean/Boolean/False
+XtNrowHeight/Height/Dimension/0
+XtNrowSpacing/Spacing/Dimension/2
+XtNsensitive/Sensitive/Boolean/True
+XtNsensitiveArray/List/Boolean/NULL
+XtNtablist/String/String/NULL
+XtNtabs/List/int/NULL
+XtNverticalList/Boolean/Boolean/False
+XtNwidth/Width/Dimension/0
+XtNx/Position/Position/0
+XtNy/Position/Position/0
+.TE
+.ne 4
+.SH Public Functions
+.nf
+.ta 3i
+void XfwfMultiListHighlightItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+.fi
+.sp
+.RS 5
+This routine selects an item with index <item_index> in the MultiList
+widget <mlw>. If a maximum number of selections is specified and
+exceeded, the earliest selection will be unselected. If <item_index>
+doesn't correspond to an item the most recently clicked item will be
+set to -1 and this routine will immediately return, otherwise the most
+recently clicked item will be set to the current item.
+.RE
+.sp
+.nf
+void XfwfMultiListHighlightAll(mlw)
+XfwfMultiListWidget mlw;
+.fi
+.sp
+.RS 5
+This routine highlights all highlightable items in the MultiList
+widget <mlw>, up to the maximum number of allowed highlightable items;
+.RE
+.sp
+.nf
+void XfwfMultiListUnhighlightItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+.fi
+.sp
+.RS 5
+This routine unselects the item with index <item_index> in the
+MultiList widget <mlw>. If <item_index> doesn't correspond to a
+selected item, then nothing will happen. Otherwise, the item is
+unselected and the selection array and count are updated.
+.RE
+.sp
+.nf
+void XfwfMultiListUnhighlightAll(mlw)
+XfwfMultiListWidget mlw;
+.fi
+.sp
+.RS 5
+This routine unhighlights all items in the MultiList widget <mlw>.
+.RE
+.sp
+.nf
+int XfwfMultiListToggleItem(mlw,item_index)
+XfwfMultiListWidget mlw;
+.fi
+.sp
+.RS 5
+This routine highlights the item with index <item_index> if it is
+unhighlighted and unhighlights it if it is already highlighted. The
+action performed by the toggle is returned (XfwfMultiListActionHighlight
+or XfwfMultiListActionUnhighlight).
+.RE
+.sp
+.nf
+XfwfMultiListReturnStruct *MultiListGetHighlighted(mlw)
+XfwfMultiListWidget mlw;
+.fi
+.sp
+.RS 5
+This routine takes a MultiList widget <mlw> and returns a
+MultiListReturnStruct whose num_selected and selected_items fields
+contain the highlight information. The action field is set to
+XfwfMultiListActionStatus, and the item_index and string fields are
+invalid.
+.RE
+.sp
+.nf
+Boolean XfwfMultiListIsHighlighted(plw,item_index)
+XfwfMultiListWidget mlw;
+int item_index;
+.fi
+.sp
+.RS 5
+This routine checks if the item with index <item_index> is highlighted
+and returns True or False depending. If <item_index> is invalid,
+False is returned.
+.RE
+.sp
+.nf
+Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr)
+XfwfMultiListWidget mlw;
+int item_index;
+String *str_ptr;
+Boolean *h_ptr,*s_ptr;
+.fi
+.sp
+.RS 5
+This routine returns the string, highlight status and sensitivity
+information for the item with index <item_index> via the pointers
+<str_ptr>, <h_ptr> and <s_ptr>. If the item index is invalid, False
+is returned, else True is returned.
+.RE
+.sp
+.nf
+void XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,sensitivity_array)
+MultiListWidget mlw;
+String *list;
+int nitems,longest;
+Boolean resize;
+Boolean *sensitivity_array;
+.fi
+.sp
+.RS 5
+This routine will set a new set of strings <list> into the MultiList
+widget <mlw>. If <resize> is True, the MultiList widget will try to
+resize itself.
+.RE
+.sp
+.nf
+.ne 4
+.SH Restrictions
+.LP
+There are likely to be inadequacies in this code. Specifically, I am
+not sure what the callback interface should look like when you can
+select and unselect multiple items. This is the reason for the
+confusing return structure fields. Please send bug reports and
+feature requests to the email address below.
+.SH Author
+.sp
+.nf
+Brian Totty, \fItotty@cs.uiuc.edu\fR
+Department of Computer Science,
+University of Illinois at Urbana-Champaign
+1304 W. Springfield Avenue
+Urbana, IL 61801
+.fi
diff --git a/vendor/x11iraf/obm/ObmW/MultiListP.h b/vendor/x11iraf/obm/ObmW/MultiListP.h
new file mode 100644
index 00000000..5e3982e8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/MultiListP.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+
+ MultiListP.h
+
+ This file is the private header file for the MultiList widget, an
+ extension to the Athena List widget.
+
+ This code is loosely based on the Athena List source which
+ is why the MIT copyright notice appears below.
+
+ The code was changed substantially in V3.4 to change the
+ action/callback interface which was unnecessarily ugly. Code
+ using some features of the old interface may need to be changed.
+ Hope the changes don't make people's lives too miserable.
+
+ ****************************************************************************/
+
+/*
+ * Author:
+ * Brian Totty
+ * Department of Computer Science
+ * University Of Illinois at Urbana-Champaign
+ * 1304 West Springfield Avenue
+ * Urbana, IL 61801
+ *
+ * totty@cs.uiuc.edu
+ *
+ */
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Original Athena Author: Chris D. Peterson, MIT X Consortium
+ */
+
+#ifndef _MULTILISTP_H_
+#define _MULTILISTP_H_
+
+#include <X11/Xaw/SimpleP.h>
+#include "MultiList.h"
+
+/*---------------------------------------------------------------------------*
+
+ L O C A L D A T A S T R U C T U R E D E F I N I T I O N S
+
+ *---------------------------------------------------------------------------*/
+
+typedef struct
+{
+ Boolean sensitive;
+ Boolean highlighted;
+ String string;
+} XfwfMultiListItem;
+
+/*---------------------------------------------------------------------------*
+
+ W I D G E T D A T A S T R U C T U R E D E F I N I T I O N S
+
+ *---------------------------------------------------------------------------*/
+
+typedef struct
+{
+ int foo;
+} XfwfMultiListClassPart;
+
+typedef struct _XfwfMultiListClassRec
+{
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ XfwfMultiListClassPart multiList_class;
+} XfwfMultiListClassRec;
+
+extern XfwfMultiListClassRec xfwfMultiListClassRec;
+
+typedef struct
+{
+ Pixel foreground;
+ Pixel highlight_fg;
+ Pixel highlight_bg;
+ Dimension column_space;
+ Dimension row_space;
+ int default_cols;
+ Boolean force_cols;
+ Boolean paste;
+ Boolean row_major;
+ int longest;
+ int nitems;
+ XFontStruct *font;
+ String *list;
+ Boolean *sensitive_array;
+ XtCallbackList callback;
+ int max_selectable;
+ Boolean shade_surplus;
+ Dimension col_width;
+ Dimension row_height;
+
+ int right_padding;
+ int bottom_padding;
+ int nrows;
+ int ncols;
+ int most_recent_clicked_item;
+ int most_recent_action;
+ GC erase_gc;
+ GC draw_gc;
+ GC highlight_bg_gc;
+ GC highlight_fg_gc;
+ GC gray_gc;
+ XfwfMultiListItem *item_array;
+ int num_selected;
+ int *sel_array;
+
+ char *tablist;
+ int *tabs;
+} XfwfMultiListPart;
+
+typedef struct _XfwfMultiListRec
+{
+ CorePart core;
+ SimplePart simple;
+ XfwfMultiListPart multiList;
+} XfwfMultiListRec;
+
+/*---------------------------------------------------------------------------*
+
+ D A T A S T R U C T U R E A C C E S S M A C R O S
+
+ *---------------------------------------------------------------------------*/
+
+#define MultiListItemSensitive(i) ((i)->sensitive)
+#define MultiListItemHighlighted(i) ((i)->highlighted)
+#define MultiListItemString(i) ((i)->string)
+
+#define InstanceCore(w) (&((w)->core))
+#define InstanceSimple(w) (&((w)->simple))
+#define InstanceMultiList(w) (&((w)->multiList))
+
+#define MultiListWidth(w) (InstanceCore(w)->width)
+#define MultiListHeight(w) (InstanceCore(w)->height)
+#define MultiListBG(w) (InstanceCore(w)->background_pixel)
+#define MultiListSensitive(w) (InstanceCore(w)->sensitive)
+#define MultiListAncesSensitive(w) (InstanceCore(w)->ancestor_sensitive)
+#define MultiListDepth(w) (InstanceCore(w)->depth)
+
+#define MultiListFG(w) (InstanceMultiList(w)->foreground)
+#define MultiListHighlightFG(w) (InstanceMultiList(w)->highlight_fg)
+#define MultiListHighlightBG(w) (InstanceMultiList(w)->highlight_bg)
+#define MultiListColumnSpace(w) (InstanceMultiList(w)->column_space)
+#define MultiListRowSpace(w) (InstanceMultiList(w)->row_space)
+#define MultiListDefaultCols(w) (InstanceMultiList(w)->default_cols)
+#define MultiListForceCols(w) (InstanceMultiList(w)->default_cols)
+#define MultiListPaste(w) (InstanceMultiList(w)->paste)
+#define MultiListRowMajor(w) (InstanceMultiList(w)->row_major)
+#define MultiListLongest(w) (InstanceMultiList(w)->longest)
+#define MultiListNumItems(w) (InstanceMultiList(w)->nitems)
+#define MultiListFont(w) (InstanceMultiList(w)->font)
+#define MultiListList(w) (InstanceMultiList(w)->list)
+#define MultiListSensitiveArray(w) (InstanceMultiList(w)->sensitive_array)
+#define MultiListCallback(w) (InstanceMultiList(w)->callback)
+#define MultiListMaxSelectable(w) (InstanceMultiList(w)->max_selectable)
+#define MultiListShadeSurplus(w) (InstanceMultiList(w)->shade_surplus)
+
+#define MultiListColWidth(w) (InstanceMultiList(w)->col_width)
+#define MultiListRowHeight(w) (InstanceMultiList(w)->row_height)
+#define MultiListRightPadding(w) (InstanceMultiList(w)->right_padding)
+#define MultiListBottomPadding(w) (InstanceMultiList(w)->bottom_padding)
+#define MultiListNumRows(w) (InstanceMultiList(w)->nrows)
+#define MultiListNumCols(w) (InstanceMultiList(w)->ncols)
+#define MultiListMostRecentItem(w) (InstanceMultiList(w)->most_recent_clicked_item)
+#define MultiListMostRecentAct(w) (InstanceMultiList(w)->most_recent_action)
+#define MultiListEraseGC(w) (InstanceMultiList(w)->erase_gc)
+#define MultiListDrawGC(w) (InstanceMultiList(w)->draw_gc)
+#define MultiListHighlightForeGC(w) (InstanceMultiList(w)->highlight_fg_gc)
+#define MultiListHighlightBackGC(w) (InstanceMultiList(w)->highlight_bg_gc)
+#define MultiListGrayGC(w) (InstanceMultiList(w)->gray_gc)
+#define MultiListItemArray(w) (InstanceMultiList(w)->item_array)
+#define MultiListNthItem(w,n) (&(MultiListItemArray(w)[n]))
+#define MultiListSelArray(w) (InstanceMultiList(w)->sel_array)
+#define MultiListNumSelected(w) (InstanceMultiList(w)->num_selected)
+
+#define MultiListTabList(w) (InstanceMultiList(w)->tablist)
+#define MultiListTabs(w) (InstanceMultiList(w)->tabs)
+
+#endif
diff --git a/vendor/x11iraf/obm/ObmW/Notes b/vendor/x11iraf/obm/ObmW/Notes
new file mode 100644
index 00000000..fe635b21
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Notes
@@ -0,0 +1,191 @@
+ GUI WORK NOTES - November 1993
+
+TODO
+
+ enhance mapping code in Gterm widget (see below)
+ ximtool enhancements
+ locator, magnifier, control panel, socket support, etc.
+ clean up xgterm
+ - beta release -
+ obm enhancements
+ more gui bindings, new widgets
+ imbrowse, movie demos
+ obm documentation
+
+
+1. MAPPINGS
+
+ src rect -> dst rect
+
+ construct pixel level mappings for each axis
+ this source pixel maps to these destination pixels
+ this destination pixel maps to these source pixels
+
+ in general (zoom/dezoom) the mapping is not one-to-one
+ when one source pixel maps to several destination pixels, pixel replication
+ is used to draw the destination pixels
+ when one destination pixel maps to several source pixels the destination
+ pixel value may be computed by any of several different techniques
+
+ major cases
+
+ mapping is one-to-one
+ mapping is one-to-many zoom mapping (pixel replication)
+ mapping is many-to-one dezoom mapping (antialias)
+
+ antialiasing techniques
+
+ nearest nearest neighbor
+ bilinear 2x2 distance weighted sum
+
+ area included area weighted sum
+ lowpass convolve followed by nearest neighbor
+ gaussian gaussian weighted sum over NxN pixels
+
+ All of these involve projecting the center of each destination
+ pixel back into the source raster. The antialiasing technique
+ applied to the NxN neighborhood around the source coordinate
+ then determines the value of the destination pixel.
+
+ Reasonable choices
+ nearest fastest, but no antialiasing
+ bilinear mininum smoothing if mag < 2
+ lowpass not bad for mag < 3
+ area,gaussian best for large demagnification ratios
+
+ Nearest and bilinear (NB) are mutually exclusive and may be selected
+ independently of area, lowpass, or gaussian (ALG). If one of ALG is
+ selected and one of NB is also selected, the antialias code will use
+ one or the other technique depending upon the scaling. If one of NB
+ or ALG is selected but not both, the specified technique will be
+ used regardless of the scaling.
+
+ setMapping should compute scaling maps
+ copyRaster uses these to compute the destination pixels
+ refreshRaster uses these to compute region of source rect
+
+ computing a mapping
+ rasterop
+ src rect, dst rect
+ coordinate types
+ flags: enabled, defined, refresh
+ scaling type (unitary, zoom, dezoom)
+ backprojection array maps dst pixel to src pixel
+ integer mapping (1-1, zoom): pixel number, integer
+ antialias mapping (dezoom): pixel center, floating
+ extent array gives range of dst pixels affected by a given
+ src pixel - 2 values per source pixel
+ xscale, yscale (forward direction)
+
+
+2. PSEUDOCODE
+
+procedure copyRaster (src, src rect, dst, dst rect)
+begin
+ create temporary mapping
+ refresh entire mapping
+end
+
+procedure writePixels (dst, dst rect, pixels)
+begin
+ modify source raster pixels
+ update any mappings that intersect source rect
+end
+
+procedure setMapping (mapping, mapping data)
+begin
+ if (new mapping, mapping not enabled, or refreshNone set)
+ merely store new mapping
+ else {
+ # Edit and refresh a mapping.
+ if (scale is unchanged) {
+ compare old, new mappings
+ refresh only changed regions
+ store new mapping
+ } else {
+ store new mapping
+ refresh entire mapping
+ }
+ refresh any uncovered regions
+ }
+
+ if (mapping is one-to-one) {
+ scaling = none
+ } else if (mapping is one-to-many) {
+ compute integer dst->src scaling maps
+ scaling = zoom
+ } else if (mapping is many-to-one) {
+ compute array of back projected dst->src pixel centers
+ scaling = dezoom
+ }
+end
+
+procedure refresh_source (mapping, source rect)
+begin
+ compute destination rect
+ refresh_destination (mapping, destination rect)
+end
+
+procedure refresh_destination (mapping, destination rect)
+begin
+ set clip mask in GC to prevent drawing into any mapped regions
+ which cover the mapping being refreshed
+
+ # Special case of pixmap to pixmap copy with no scaling.
+ if (no scaling and src is pixmap and dst is pixmap) {
+ do direct XCopyArea
+ goto done
+ }
+
+ # Get source ximage.
+ if (src is pixmap) {
+ xin = ximage returned by XGetImage
+ set del_xin flag
+ } else
+ xin = src ximage
+
+ # Special case of ximage to pixmap copy with no scaling.
+ if (no scaling and dst is pixmap) {
+ do XPutImage to write xin to dst pixmap
+ goto done
+ }
+
+ # Get destination ximage.
+ if (dst is pixmap) {
+ xout = create an ximage of the required size
+ set del_xout flag
+ } else
+ xout = dst ximage
+
+ # Copy src ximage to dst ximage.
+ if (mapping is one to one) {
+ copy region of xin to xout without scaling
+
+ } else if (mapping is one to many - zoom) {
+ for (each line of destination)
+ if (mapped src Y same as previous line)
+ copy previous dst line
+ else {
+ for (each destination pixel)
+ pixel = get pixel from xin using dst->src map
+ }
+
+ } else (mapping is many to one - dezoom) {
+ if (function is lowpass) {
+ compute lowpass xin
+ set function to nearest neighbor
+ }
+
+ for (each line of destination)
+ for (each destination pixel)
+ pixel = antialias_function (src, x, y, nx, ny)
+ }
+
+ if (dst is pixmap)
+ do XPutImage to write xout to dst pixmap
+
+ clear clip mask in GC
+end
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/README b/vendor/x11iraf/obm/ObmW/README
new file mode 100644
index 00000000..b75418d3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/README
@@ -0,0 +1,83 @@
+ObmW -- Custom widgets used by the Object Manager. This directory contains
+standalone X toolkit widgets; these are not tied to the Object Manager in any
+way. The widgets in this collection are included here if they are used in
+the Object Manager but are not part of any standard toolkit.
+
+To interface a new widget to the Object Manager, one can add the widget
+source to this directory and modify ObmP.h and obmres.dat (which is generated
+using obmres.c) in the OBM root directory to tell OBM about the widget and
+its resources. One may optionally wish to subclass the OBM Widget class to
+make any widget-specific functions available to interpreted GUI code.
+
+Widets:
+
+ Gterm Gterm gterm-image widget (2D graphics and imaging)
+ Layout Layout geometry widget, uses layout description language
+
+ Arrow Arrow arrow widget, as in a scrollbar
+ Board Board geometry widget, organizes children by coordinate
+ Frame Frame draws a frame around a child widget
+ Group Group organize multiple children into a group
+ Icon Icon display a color pixmap
+ MultiList MultiList list widget with multiple selections
+ RadioGrp RadioGroup radio group, subclass of Group
+ RowCol RowCol geometry widget, arranges children in a table
+ Scrollbar Scrollbar2 alternative to Athena scrollbar widget
+ Slider2 Slider2D 2D slider widget (can be used as 1D slider)
+ Label TextBox framed box with formatted text
+ Button TextButton TextBox as a button with callback
+ Toggle TextToggle button with on,off bitmap to the left
+
+ Common XfwfCommon used internally by all FWF widgets
+ MenuBar MenuBar doesn't work, placeholder for now
+
+
+Notes on widget callbacks (used internally by OBM, not GUIs).
+--------------------------------------------------------------
+
+FWF widgets:
+
+ Boolean XfwfMultiListGetItemInfo (mlw,item_index,str_ptr,h_ptr,s_ptr)
+ Boolean XfwfMultiListHighlightItem (mlw,item_index)
+ Boolean XfwfMultiListIsHighlighted (mlw,item_index)
+ struct = XfwfMultiListGetHighlighted (mlw)
+ XfwfMultiListSetNewData (mlw,list,nitems,longest,resize,
+ sensitivity_array)
+
+ int XfwfMultiListToggleItem (mlw,item_index)
+ XfwfMultiListHighlightAll (mlw)
+ XfwfMultiListUnhighlightAll (mlw)
+ XfwfMultiListUnhighlightItem (mlw,item_index)
+
+ XfwfGetThumb (self,info)
+ XfwfMoveThumb (self,x,y)
+ XfwfResizeThumb (self,wd,ht)
+ XfwfSetScrollbar (self,pos,size)
+
+ void XfwfConnectScrollingWidgets (w1, w2)
+
+
+Athena widgets:
+
+ char* XawDialogGetValueString (w)
+ XtFormDoLayout (w, do_layout)
+
+ XawListChange (w, list, nitems, longest, resize)
+ XawListHighlight (w, item)
+ XawListUnhighlight (w)
+ XawListShowCurrent (w)
+
+ XawScrollbarSetThumb (w, top, shown)
+
+ Panner: Callback when panner moves.
+ Porthole: Multiple children, only one managed at a time. Single
+ callback called when child is moved or resized.
+ Repeater: Repeating version of command widget. Two callbacks, start
+ callback and stop callback.
+ Scrollbar: Callbacks: jumpProc, scrollProc
+ StripChart: getValue callback called to get new data point
+ Tree: No special callbacks or functions
+ Viewport: Report callback called if child moved or resized
+
+ All geometry widgets have a function to disable/force layout of the
+ children, used to disable layout when multiple children are modified.
diff --git a/vendor/x11iraf/obm/ObmW/RadioGrp.c b/vendor/x11iraf/obm/ObmW/RadioGrp.c
new file mode 100644
index 00000000..14d39924
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RadioGrp.c
@@ -0,0 +1,239 @@
+/* Generated by wbuild from "RadioGrp.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Toggle.h"
+#include "RadioGrpP.h"
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void class_initialize(
+#if NeedFunctionPrototypes
+void
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void create_toggles(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+#define done(type, value) do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ }while (0 )
+
+
+static Boolean cvtStringToStringArray(
+#if NeedFunctionPrototypes
+Display *,XrmValuePtr ,Cardinal *,XrmValuePtr ,XrmValuePtr ,XtPointer *
+#endif
+);
+static StringArray newStringArray(
+#if NeedFunctionPrototypes
+StringArray
+#endif
+);
+static void freeStringArray(
+#if NeedFunctionPrototypes
+StringArray
+#endif
+);
+/*ARGSUSED*/static void create_toggles(self)Widget self;
+{
+ Cardinal i;
+ StringArray s;
+
+ for (i = 0; i < ((XfwfRadioGroupWidget)self)->composite.num_children; i++)
+ XtDestroyWidget(((XfwfRadioGroupWidget)self)->composite.children[i]);
+
+ if (((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels == NULL) return;
+
+ for (s = ((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels, i = 0; s[i] != NULL; i++) {
+ (void) XtVaCreateManagedWidget
+ (s[i], xfwfToggleWidgetClass, self, XtNlabel, s[i], XtNshrinkToFit,
+ True, XtNborderWidth, 0, XtNframeWidth, 0, NULL);
+ }
+}
+/*ARGSUSED*/static Boolean cvtStringToStringArray(display,args,num_args,from,to,converter_data)Display * display;XrmValuePtr args;Cardinal * num_args;XrmValuePtr from;XrmValuePtr to;XtPointer * converter_data;
+{
+ String t, s;
+ StringArray a = NULL;
+ Cardinal i;
+ char delim;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToStringArray", "wrongParameters",
+ "XtToolkitError",
+ "String to StringArray conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ delim = ((String) from->addr)[0];
+ s = XtNewString((String) from->addr + 1);
+ i = 0;
+ while (s && *s) {
+ t = strchr(s, delim);
+ if (t) *t = '\0';
+ a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
+ a[i] = s;
+ i++;
+ s = t ? t + 1 : NULL;
+ }
+ a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
+ a[i] = NULL;
+ done(StringArray, a);
+}
+/*ARGSUSED*/static StringArray newStringArray(a)StringArray a;
+{
+ Cardinal n, i;
+ StringArray s;
+
+ if (!a) return NULL;
+ for (s = a, n = 0; s[n]; n++) ;
+ s = (StringArray) XtMalloc((n + 1) * sizeof(*s));
+ for (i = 0; i < n; i++) s[i] = XtNewString(a[i]);
+ s[n] = NULL;
+ return s;
+}
+/*ARGSUSED*/static void freeStringArray(a)StringArray a;
+{
+ Cardinal i;
+
+ if (!a) return;
+ for (i = 0; a[i]; i++) XtFree(a[i]);
+ XtFree((String) a);
+}
+
+static XtResource resources[] = {
+{XtNlabels,XtCLabels,XtRStringArray,sizeof(((XfwfRadioGroupRec*)NULL)->xfwfRadioGroup.labels),XtOffsetOf(XfwfRadioGroupRec,xfwfRadioGroup.labels),XtRImmediate,(XtPointer)NULL },
+};
+
+XfwfRadioGroupClassRec xfwfRadioGroupClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfGroupClassRec,
+"RadioGroup",
+sizeof(XfwfRadioGroupRec),
+class_initialize,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+NULL,
+0,
+resources,
+1,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+XtInheritExpose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfRowCol_class part */
+XtInherit_layout,
+},
+{ /* XfwfGroup_class part */
+0
+},
+{ /* XfwfRadioGroup_class part */
+0
+},
+};
+WidgetClass xfwfRadioGroupWidgetClass = (WidgetClass) &xfwfRadioGroupClassRec;
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfRadioGroupWidgetClass c = (XfwfRadioGroupWidgetClass) class;
+ XfwfRadioGroupWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfRadioGroupWidgetClass) return;
+ super = (XfwfRadioGroupWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void class_initialize()
+{
+ XtSetTypeConverter(XtRString, "StringArray", cvtStringToStringArray,
+ NULL, 0, XtCacheNone, NULL);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels = newStringArray(((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels);
+ create_toggles(self);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfRadioGroupWidget)old)->xfwfRadioGroup.labels != ((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels) {
+ freeStringArray(((XfwfRadioGroupWidget)old)->xfwfRadioGroup.labels);
+ ((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels = newStringArray(((XfwfRadioGroupWidget)self)->xfwfRadioGroup.labels);
+ create_toggles(self);
+ }
+ return False;
+}
diff --git a/vendor/x11iraf/obm/ObmW/RadioGrp.h b/vendor/x11iraf/obm/ObmW/RadioGrp.h
new file mode 100644
index 00000000..9724e570
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RadioGrp.h
@@ -0,0 +1,22 @@
+/* Generated by wbuild from "RadioGrp.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfRadioGroup_H_
+#define _XfwfRadioGroup_H_
+#include "Group.h"
+typedef String * StringArray;
+
+#ifndef XtNlabels
+#define XtNlabels "labels"
+#endif
+#ifndef XtCLabels
+#define XtCLabels "Labels"
+#endif
+#ifndef XtRStringArray
+#define XtRStringArray "StringArray"
+#endif
+
+typedef struct _XfwfRadioGroupClassRec *XfwfRadioGroupWidgetClass;
+typedef struct _XfwfRadioGroupRec *XfwfRadioGroupWidget;
+externalref WidgetClass xfwfRadioGroupWidgetClass;
+#endif /*_XfwfRadioGroup_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/RadioGrp.man b/vendor/x11iraf/obm/ObmW/RadioGrp.man
new file mode 100644
index 00000000..769547ef
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RadioGrp.man
@@ -0,0 +1,384 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfRadioGroup
+.SH DESCRIPTION
+The RadioGroup widget is a simple specialization of the Group
+widget. It has an extra resource, \fIlabels\fP, which holds the labels of
+the toggle buttons that are created automatically. For the common case
+that a Group widget contains only radio buttons, the RadioGroup widget
+is much more convenient. It is also much less flexible. E.g., it is
+very difficult to change resources of the radio buttons, when the
+defaults are not satisfactory.
+
+In particular, the Toggle widgets are created with the following
+hardcoded resources: \fIshrinkToFit = True\fP, \fIborder_width = 0\fP,
+\fIframeWidth = 0\fP. The names of the Toggle widgets are equal to their
+labels.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfRadioGroup
+Name Class Type Default
+XtNlabels XtCLabels StringArray NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNlabels"
+The \fIlabels\fP resource is an array of strings. Each string will
+become the label of a toggle button. The last member of the array must
+be a \fINULL\fP pointer.
+
+There is a converter that allows the list of strings to be entered as
+a single string, with any character as separator.
+
+
+
+.hi
+
+.nf
+StringArray labels = NULL
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfGroup
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNselectionStyle XtCSelectionStyle SelectionType XfwfSingleSelection
+XtNselection XtCSelection Long 0
+XtNactivate XtCActivate Callback NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfRowCol
+Name Class Type Default
+XtNstoreByRow XtCStoreByRow Boolean True
+XtNrows XtCRows Int 0
+XtNcolumns XtCColumns Int 0
+XtNalignment XtCAlignment Alignment XfwfTopLeft
+XtNshrinkToFit XtCShrinkToFit Boolean False
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The type \fIStringArray\fP represents an array of \fIString\fPs, with the
+proviso that by convention the last member of a \fIStringArray\fP is
+always a \fINULL\fP pointer. There is a converter that can construct a
+\fIStringArray\fP from a single string.
+
+
+
+.nf
+
+.B type
+ StringArray = String *
+.fi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <Xfwf/Toggle.h>
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+\fIclass_initialize\fP registers the type converter.
+
+.nf
+class_initialize()
+{
+ XtSetTypeConverter(XtRString, "StringArray", cvtStringToStringArray,
+ NULL, 0, XtCacheNone, NULL);
+}
+.fi
+
+In the \fIinitialize\fP method, the utility function \fIcreate_toggles\fP is
+called, which creates toggle widgets for each label in the \fIlabels\fP
+resource.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $labels = newStringArray($labels);
+ create_toggles($);
+}
+.fi
+
+The \fIset_values\fP method makes a private copy of the \fIlabels\fP
+resource and calls \fIcreate_labels\fP. Since the RadioGroup doesn't draw
+anything itself, the return value is always \fIFalse\fP.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($old$labels != $labels) {
+ freeStringArray($old$labels);
+ $labels = newStringArray($labels);
+ create_toggles($);
+ }
+ return False;
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The function \fIcreate_toggles\fP first destroys all existing children
+and then creates new ones. For each string in the \fIlabels\fP resource
+there will be an XfwfToggle button.
+
+.nf
+create_toggles($)
+{
+ Cardinal i;
+ StringArray s;
+
+ for (i = 0; i < $num_children; i++)
+ XtDestroyWidget($children[i]);
+
+ if ($labels == NULL) return;
+
+ for (s = $labels, i = 0; s[i] != NULL; i++) {
+ (void) XtVaCreateManagedWidget
+ (s[i], xfwfToggleWidgetClass, $, XtNlabel, s[i], XtNshrinkToFit,
+ True, XtNborderWidth, 0, XtNframeWidth, 0, NULL);
+ }
+}
+.fi
+
+The converter from \fIString\fP to \fIStringArray\fP makes a copy of the
+passed string and then replaces all occurences of the delimiter with
+a nul byte. The \fIStringArray\fP a is filled with pointers to the parts
+of the string.
+
+The delimiter character is the first character in the string.
+
+\fBdef\fP done(type, value) =
+do {
+ if (to->addr != NULL) {
+ if (to->size < sizeof(type)) {
+ to->size = sizeof(type);
+ return False;
+ }
+ *(type*)(to->addr) = (value);
+ } else {
+ static type static_val;
+ static_val = (value);
+ to->addr = (XtPointer)static_val;
+ }
+ to->size = sizeof(type);
+ return True;
+ }while (0 )
+
+.nf
+Boolean cvtStringToStringArray(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ String t, s;
+ StringArray a = NULL;
+ Cardinal i;
+ char delim;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToStringArray", "wrongParameters",
+ "XtToolkitError",
+ "String to StringArray conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ delim = ((String) from->addr)[0];
+ s = XtNewString((String) from->addr + 1);
+ i = 0;
+ while (s *s) {
+ t = strchr(s, delim);
+ if (t) *t = '\\0';
+ a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
+ a[i] = s;
+ i++;
+ s = t ? t + 1 : NULL;
+ }
+ a = (StringArray) XtRealloc((String) a, (i + 1) * sizeof(*a));
+ a[i] = NULL;
+ done(StringArray, a);
+}
+.fi
+
+The function \fInewStringArray\fP makes a copy of a \fIStringArray\fP. It
+allocates new space for the array itself and for the strings that it
+contains.
+
+.nf
+StringArray newStringArray(StringArray a)
+{
+ Cardinal n, i;
+ StringArray s;
+
+ if (!a) return NULL;
+ for (s = a, n = 0; s[n]; n++) ;
+ s = (StringArray) XtMalloc((n + 1) * sizeof(*s));
+ for (i = 0; i < n; i++) s[i] = XtNewString(a[i]);
+ s[n] = NULL;
+ return s;
+}
+.fi
+
+\fIfreeStringArray\fP deallocates the array and all strings it contains.
+
+.nf
+freeStringArray(StringArray a)
+{
+ Cardinal i;
+
+ if (!a) return;
+ for (i = 0; a[i]; i++) XtFree(a[i]);
+ XtFree((String) a);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/RadioGrpP.h b/vendor/x11iraf/obm/ObmW/RadioGrpP.h
new file mode 100644
index 00000000..be994fa8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RadioGrpP.h
@@ -0,0 +1,43 @@
+/* Generated by wbuild from "RadioGrp.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfRadioGroupP_H_
+#define _XfwfRadioGroupP_H_
+#include "GroupP.h"
+#include "RadioGrp.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfRadioGroupClassPart;
+typedef struct _XfwfRadioGroupClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfRowColClassPart xfwfRowCol_class;
+XfwfGroupClassPart xfwfGroup_class;
+XfwfRadioGroupClassPart xfwfRadioGroup_class;
+} XfwfRadioGroupClassRec;
+
+typedef struct {
+/* resources */
+StringArray labels;
+/* private state */
+} XfwfRadioGroupPart;
+
+typedef struct _XfwfRadioGroupRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfRowColPart xfwfRowCol;
+XfwfGroupPart xfwfGroup;
+XfwfRadioGroupPart xfwfRadioGroup;
+} XfwfRadioGroupRec;
+
+externalref XfwfRadioGroupClassRec xfwfRadioGroupClassRec;
+
+#endif /* _XfwfRadioGroupP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/RowCol.c b/vendor/x11iraf/obm/ObmW/RowCol.c
new file mode 100644
index 00000000..c37fed43
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RowCol.c
@@ -0,0 +1,346 @@
+/* Generated by wbuild from "RowCol.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "RowColP.h"
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void change_managed(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void layout(
+#if NeedFunctionPrototypes
+Widget,int
+#endif
+);
+static XtGeometryResult geometry_manager(
+#if NeedFunctionPrototypes
+Widget ,XtWidgetGeometry *,XtWidgetGeometry *
+#endif
+);
+static void resize(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static char rcsid[] = "$Header: RowCol.w,v 1.1 92/10/14 18:36:36 bert Exp $";
+static void align_child(
+#if NeedFunctionPrototypes
+Widget,int ,int ,int ,int ,Alignment
+#endif
+);
+/*ARGSUSED*/static void align_child(self,cx,cy,width,height,alignment)Widget self;int cx;int cy;int width;int height;Alignment alignment;
+{
+ Position x, y;
+
+ if (alignment & XfwfLeft) x = cx;
+ else if (alignment & XfwfRight) x = cx + width - ((XfwfRowColWidget)self)->core.width;
+ else x = cx + (width - ((XfwfRowColWidget)self)->core.width) / 2;
+ if (alignment & XfwfTop) y = cy;
+ else if (alignment & XfwfBottom) y = cy + height - ((XfwfRowColWidget)self)->core.height;
+ else y = cy + (height - ((XfwfRowColWidget)self)->core.height) / 2;
+ XtMoveWidget(self, x, y);
+}
+
+static XtResource resources[] = {
+{XtNstoreByRow,XtCStoreByRow,XtRBoolean,sizeof(((XfwfRowColRec*)NULL)->xfwfRowCol.storeByRow),XtOffsetOf(XfwfRowColRec,xfwfRowCol.storeByRow),XtRImmediate,(XtPointer)True },
+{XtNrows,XtCRows,XtRInt,sizeof(((XfwfRowColRec*)NULL)->xfwfRowCol.rows),XtOffsetOf(XfwfRowColRec,xfwfRowCol.rows),XtRImmediate,(XtPointer)0 },
+{XtNcolumns,XtCColumns,XtRInt,sizeof(((XfwfRowColRec*)NULL)->xfwfRowCol.columns),XtOffsetOf(XfwfRowColRec,xfwfRowCol.columns),XtRImmediate,(XtPointer)0 },
+{XtNalignment,XtCAlignment,XtRAlignment,sizeof(((XfwfRowColRec*)NULL)->xfwfRowCol.alignment),XtOffsetOf(XfwfRowColRec,xfwfRowCol.alignment),XtRImmediate,(XtPointer)XfwfTopLeft },
+{XtNshrinkToFit,XtCShrinkToFit,XtRBoolean,sizeof(((XfwfRowColRec*)NULL)->xfwfRowCol.shrinkToFit),XtOffsetOf(XfwfRowColRec,xfwfRowCol.shrinkToFit),XtRImmediate,(XtPointer)False },
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfRowColRec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfRowColRec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfSunken },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfRowColRec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfRowColRec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)2 },
+};
+
+XfwfRowColClassRec xfwfRowColClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfBoardClassRec,
+"RowCol",
+sizeof(XfwfRowColRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+NULL,
+0,
+resources,
+7,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+resize,
+XtInheritExpose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+geometry_manager,
+change_managed,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfRowCol_class part */
+layout,
+},
+};
+WidgetClass xfwfRowColWidgetClass = (WidgetClass) &xfwfRowColClassRec;
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfRowColWidgetClass c = (XfwfRowColWidgetClass) class;
+ XfwfRowColWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfRowColWidgetClass) return;
+ super = (XfwfRowColWidgetClass)class->core_class.superclass;
+ if (c->xfwfRowCol_class.layout == XtInherit_layout)
+ c->xfwfRowCol_class.layout = super->xfwfRowCol_class.layout;
+}
+/*ARGSUSED*/static void change_managed(self)Widget self;
+{
+ ((XfwfRowColWidgetClass)self->core.widget_class)->xfwfRowCol_class.layout(self, ((XfwfRowColWidget)self)->xfwfRowCol.shrinkToFit);
+}
+/*ARGSUSED*/static void layout(self,shrink)Widget self;int shrink;
+{
+ int nrows, ncols, i, nchild, n;
+ Position left, top, x, y;
+ Dimension width, height, w, h;
+ Widget child;
+
+ nchild = 0;
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_width = 0;
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_height = 0;
+
+ for (i = 0; i < ((XfwfRowColWidget)self)->composite.num_children; i++) {
+ child = ((XfwfRowColWidget)self)->composite.children[i];
+ if (! XtIsManaged(child)) continue;
+ nchild++;
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_width =
+ max(((XfwfRowColWidget)self)->xfwfRowCol.max_width,
+ ((XfwfRowColWidget)child)->core.width +
+ 2*((XfwfRowColWidget)child)->core.border_width);
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_height =
+ max(((XfwfRowColWidget)self)->xfwfRowCol.max_height,
+ ((XfwfRowColWidget)child)->core.height +
+ 2*((XfwfRowColWidget)child)->core.border_width);
+ }
+
+ ((XfwfRowColWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &left, &top, &width, &height);
+
+ /* If there is a single child resize it to fill the window instead of
+ * laying out multiple child widgets. This allows a group widget to be
+ * used to draw a labeled frame around a composite child. 09Mar94 DCT.
+ */
+ if (((XfwfRowColWidget)self)->composite.num_children == 1) {
+ if (width > 0 && width < 16384 && height > 0 && height < 16384) {
+ /* Don't resize child if parent doesn't have a size yet.
+ */
+ child = ((XfwfRowColWidget)self)->composite.children[0];
+ w = width - 2 * child->core.border_width;
+ h = height - 2 * child->core.border_width;
+
+ XtResizeWidget (child, w, h,
+ ((XfwfRowColWidget)child)->core.border_width);
+ align_child (child, left, top, w, h, XfwfLeft|XfwfTop);
+
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_width =
+ child->core.width - 2 * child->core.border_width;
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_height =
+ child->core.height - 2 * child->core.border_width;
+
+ nrows = ncols = 1;
+ goto do_shrink;
+ }
+ }
+
+ if (((XfwfRowColWidget)self)->xfwfRowCol.columns != 0) {
+ ncols = ((XfwfRowColWidget)self)->xfwfRowCol.columns;
+ nrows = (nchild + ncols - 1)/ncols;
+ } else if (((XfwfRowColWidget)self)->xfwfRowCol.rows != 0) {
+ nrows = ((XfwfRowColWidget)self)->xfwfRowCol.rows;
+ ncols = (nchild + nrows - 1)/nrows;
+ } else if (((XfwfRowColWidget)self)->composite.num_children == 1) {
+ /* 09Mar94 DCT */
+ nrows = ncols = 1;
+ } else {
+ ncols = ((XfwfRowColWidget)self)->xfwfRowCol.max_width != 0 ? width/((XfwfRowColWidget)self)->xfwfRowCol.max_width : 1;
+ if (ncols == 0) ncols = 1;
+ nrows = (nchild + ncols - 1)/ncols;
+ }
+
+ x = left;
+ y = top;
+ n = 0;
+ if (((XfwfRowColWidget)self)->xfwfRowCol.storeByRow) {
+ for (i = 0; i < ((XfwfRowColWidget)self)->composite.num_children; i++) {
+ child = ((XfwfRowColWidget)self)->composite.children[i];
+ if (! XtIsManaged(child)) continue;
+ align_child(child, x, y, ((XfwfRowColWidget)self)->xfwfRowCol.max_width, ((XfwfRowColWidget)self)->xfwfRowCol.max_height, ((XfwfRowColWidget)self)->xfwfRowCol.alignment);
+ n++;
+ if (n == ncols) {
+ n = 0;
+ x = left;
+ y += ((XfwfRowColWidget)self)->xfwfRowCol.max_height;
+ } else
+ x += ((XfwfRowColWidget)self)->xfwfRowCol.max_width;
+ }
+ } else {
+ for (i = 0; i < ((XfwfRowColWidget)self)->composite.num_children; i++) {
+ child = ((XfwfRowColWidget)self)->composite.children[i];
+ if (! XtIsManaged(child)) continue;
+ align_child(child, x, y, ((XfwfRowColWidget)self)->xfwfRowCol.max_width, ((XfwfRowColWidget)self)->xfwfRowCol.max_height, ((XfwfRowColWidget)self)->xfwfRowCol.alignment);
+ n++;
+ if (n == nrows) {
+ n = 0;
+ y = top;
+ x += ((XfwfRowColWidget)self)->xfwfRowCol.max_width;
+ } else
+ y += ((XfwfRowColWidget)self)->xfwfRowCol.max_height;
+ }
+ }
+
+do_shrink:
+ if (shrink) {
+ w = 2*left + ncols * ((XfwfRowColWidget)self)->xfwfRowCol.max_width;
+ h = 2*top + nrows * ((XfwfRowColWidget)self)->xfwfRowCol.max_height;
+ if (((XfwfRowColWidget)self)->xfwfRowCol.columns != 0)
+ XtVaSetValues(self, XtNwidth, w, XtNheight, h, NULL);
+ else
+ XtVaSetValues(self, XtNheight, h, NULL);
+ }
+}
+
+
+/*ARGSUSED*/static XtGeometryResult
+geometry_manager (child,request,reply)
+Widget child;
+XtWidgetGeometry * request;
+XtWidgetGeometry * reply;
+{
+ Widget self = XtParent(child);
+ Dimension newwd, newht, newbd;
+
+ if (request->request_mode & (CWX | CWY))
+ return XtGeometryNo;
+ if (request->request_mode & XtCWQueryOnly)
+ return XtGeometryYes;
+
+ newwd = request->request_mode & CWWidth ?
+ request->width : ((XfwfRowColWidget)child)->core.width;
+ newht = request->request_mode & CWHeight ?
+ request->height : ((XfwfRowColWidget)child)->core.height;
+ newbd = request->request_mode & CWBorderWidth ?
+ request->border_width : ((XfwfRowColWidget)child)->core.border_width;
+
+ if (newwd == ((XfwfRowColWidget)child)->core.width &&
+ newht == ((XfwfRowColWidget)child)->core.height &&
+ newbd == ((XfwfRowColWidget)child)->core.border_width)
+ return XtGeometryNo;
+
+ XtResizeWidget(child, newwd, newht, newbd);
+
+ ((XfwfRowColWidgetClass)self->core.widget_class)->xfwfRowCol_class.layout
+ (self, ((XfwfRowColWidget)self)->xfwfRowCol.shrinkToFit);
+
+ /* Since layout can resize the child widget it isn't appropriate to just
+ * return XtGeometryDone here, as the FWF code does. 17Mar94 DCT.
+ */
+ if (newwd == ((XfwfRowColWidget)child)->core.width &&
+ newht == ((XfwfRowColWidget)child)->core.height &&
+ newbd == ((XfwfRowColWidget)child)->core.border_width) {
+
+ return XtGeometryDone;
+
+ } else {
+ reply->request_mode = 0;
+ if (newwd != child->core.width) {
+ reply->request_mode |= CWWidth;
+ reply->width = child->core.width;
+ }
+ if (newht != child->core.height) {
+ reply->request_mode |= CWHeight;
+ reply->height = child->core.height;
+ }
+
+ return XtGeometryAlmost;
+ }
+}
+
+/*ARGSUSED*/static void resize(self)Widget self;
+{
+ if (((XfwfRowColWidget)self)->xfwfRowCol.rows == 0 && ((XfwfRowColWidget)self)->xfwfRowCol.columns == 0) ((XfwfRowColWidgetClass)self->core.widget_class)->xfwfRowCol_class.layout(self, False);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfRowColWidget)self)->xfwfRowCol.max_width = ((XfwfRowColWidget)self)->xfwfRowCol.max_height = 0;
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_layout = False;
+ Boolean need_redisplay = False;
+
+ if (((XfwfRowColWidget)old)->xfwfRowCol.storeByRow != ((XfwfRowColWidget)self)->xfwfRowCol.storeByRow) need_layout = True;
+ if (((XfwfRowColWidget)old)->xfwfRowCol.rows != ((XfwfRowColWidget)self)->xfwfRowCol.rows) need_layout = True;
+ if (((XfwfRowColWidget)old)->xfwfRowCol.columns != ((XfwfRowColWidget)self)->xfwfRowCol.columns) need_layout = True;
+ if (((XfwfRowColWidget)old)->xfwfRowCol.alignment != ((XfwfRowColWidget)self)->xfwfRowCol.alignment) need_layout = True;
+ if (((XfwfRowColWidget)old)->xfwfRowCol.shrinkToFit != ((XfwfRowColWidget)self)->xfwfRowCol.shrinkToFit) need_layout = True;
+ if (need_layout) {
+ ((XfwfRowColWidgetClass)self->core.widget_class)->xfwfRowCol_class.layout(self, ((XfwfRowColWidget)self)->xfwfRowCol.shrinkToFit);
+ need_redisplay = True;
+ }
+ return need_redisplay;
+}
diff --git a/vendor/x11iraf/obm/ObmW/RowCol.h b/vendor/x11iraf/obm/ObmW/RowCol.h
new file mode 100644
index 00000000..4542d7a7
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RowCol.h
@@ -0,0 +1,60 @@
+/* Generated by wbuild from "RowCol.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfRowCol_H_
+#define _XfwfRowCol_H_
+#include "Board.h"
+#ifndef XtNstoreByRow
+#define XtNstoreByRow "storeByRow"
+#endif
+#ifndef XtCStoreByRow
+#define XtCStoreByRow "StoreByRow"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+#ifndef XtNrows
+#define XtNrows "rows"
+#endif
+#ifndef XtCRows
+#define XtCRows "Rows"
+#endif
+#ifndef XtRInt
+#define XtRInt "Int"
+#endif
+
+#ifndef XtNcolumns
+#define XtNcolumns "columns"
+#endif
+#ifndef XtCColumns
+#define XtCColumns "Columns"
+#endif
+#ifndef XtRInt
+#define XtRInt "Int"
+#endif
+
+#ifndef XtNalignment
+#define XtNalignment "alignment"
+#endif
+#ifndef XtCAlignment
+#define XtCAlignment "Alignment"
+#endif
+#ifndef XtRAlignment
+#define XtRAlignment "Alignment"
+#endif
+
+#ifndef XtNshrinkToFit
+#define XtNshrinkToFit "shrinkToFit"
+#endif
+#ifndef XtCShrinkToFit
+#define XtCShrinkToFit "ShrinkToFit"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+typedef struct _XfwfRowColClassRec *XfwfRowColWidgetClass;
+typedef struct _XfwfRowColRec *XfwfRowColWidget;
+externalref WidgetClass xfwfRowColWidgetClass;
+#endif /*_XfwfRowCol_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/RowCol.man b/vendor/x11iraf/obm/ObmW/RowCol.man
new file mode 100644
index 00000000..1d719b38
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RowCol.man
@@ -0,0 +1,482 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfRowCol
+.SH DESCRIPTION
+The RowCol widget forces all its children into rows and columns. The
+children keep their preferred size, but the preferred position is
+ignored. Resources determine how many rows or columns their should be
+(or as many as will fit) and if the children should be layed out in
+rows or in columns. In both methods, the children are placed on a
+grid, the size of which is determined by the width (height) of the
+widest (tallest) child.
+
+The children can be aligned in several ways: they can be placed in the
+center of their grid cell or against the edges. This is controlled by
+a resource of type \fIAlignment\fP.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfRowCol
+Name Class Type Default
+XtNstoreByRow XtCStoreByRow Boolean True
+XtNrows XtCRows Int 0
+XtNcolumns XtCColumns Int 0
+XtNalignment XtCAlignment Alignment XfwfTopLeft
+XtNshrinkToFit XtCShrinkToFit Boolean False
+
+.TE
+.ps
+
+.TP
+.I "XtNstoreByRow"
+The child widgets can be layed out in rows (left to right) or in
+columns (top to bottom). The resource \fIstoreByRow\fP can be \fITrue\fP or
+\fIFalse\fP. \fITrue\fP means children are added to the right of the previous
+one until the row is full, like words are added to a text. \fIFalse\fP
+means children are added below the previous one, until the column is
+full.
+
+.hi
+
+.nf
+Boolean storeByRow = True
+.fi
+
+.eh
+
+.TP
+.I "XtNrows"
+The number of rows can be set with \fIrows\fP, or the number of columns
+can be set with \fIcolumns\fP. If both are non-zero, \fIrows\fP will be
+ignored. If \fIrows\fP is zero, there will be as many rows as needed. If
+\fIcolumns\fP is zero, there will be as many columns as needed. However,
+if both are zero, there will be as many columns as will fit in the
+current width of the RowCol widget. By default, both \fIrows\fP and
+\fIcolumns\fP are zero.
+
+.hi
+
+.nf
+int rows = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNcolumns"
+
+.hi
+
+.nf
+int columns = 0
+.fi
+
+.eh
+
+.TP
+.I "XtNalignment"
+The area of the RowCol widget is partitioned into rectangular cells
+(a grid). The cells are just large enough to contain the widest and
+the tallest of the children. Within the cell, the children can be put
+in the top left corner (the default) or against one of the edges or in
+the center. This is set with the \fIalignment\fP resource. The type
+\fIAlignment\fP is defined in the ancestor class `Common'.
+
+.hi
+
+.nf
+Alignment alignment = XfwfTopLeft
+.fi
+
+.eh
+
+.TP
+.I "XtNshrinkToFit"
+The resource \fIshrinkToFit\fP determines how the size of the RowCol
+widget itself is computed. When it is \fIFalse\fP (default), the
+\fIlocation\fP resource is used to compute the widget's preferred size.
+When the value is \fITrue\fP, the preferred size is computed fromthe total
+width and height of the children. For example, when the widest child
+has a width of \fIw\fP and \fIcolumns > 0\fP, the preferred width will be
+\fIcolumns * w +\fP frame width. A similar computation is used for the
+height. If \fIcolumns > 0\fP, only the height is computed this way. If
+\fIcolumns = 0, rows > 0\fP, only the width is computed.
+
+.hi
+
+.nf
+Boolean shrinkToFit = False
+.fi
+
+.eh
+
+.TP
+.I "XtNframeType"
+The inherited resource \fIframeType\fP is given a default value of
+\fIXfwfSunken\fP, instead of the inherited default \fIXfwfRaised\fP. The frame
+width is set to a default of 2 pixels, instead of 0.
+
+.hi
+
+.nf
+ frameType = XfwfSunken
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+
+.hi
+
+.nf
+ frameWidth = 2
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.hi
+.SS "Private variables"
+
+The width of the widest and the height of the tallest child are kept
+in private variables, for quicker access.
+
+.nf
+Dimension max_width
+.fi
+
+.nf
+Dimension max_height
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+If a child becomes managed or unmanaged, the RowCol widget
+recomputes the positions of all managed children. That is done by a
+method \fIlayout\fP. In the process, the widget may ask its parent for a
+different size if \fIshrinkToFit = True\fP.
+
+.nf
+change_managed($)
+{
+ $layout($, $shrinkToFit);
+}
+.fi
+
+The \fIlayout\fP function is responsible for moving the children to their
+positions in the grid. It is called from \fIchange_managed\fP,
+\fIgeometry_manager\fP and \fIresize\fP.
+
+The function first computes the maximum width and height of all the
+children, including their borders. Then it computes the number of rows
+and columns. All children are moved to their proper positions with the
+help of a utility function \fIalign_child\fP, which aligns a child widget
+to the grid.
+
+If \fIshrink = True\fP, the RowCol widget also asks its parent for a new
+width and/or height, depending on the resulting layout.
+
+.nf
+layout($, int shrink)
+{
+ int nrows, ncols, i, nchild, n;
+ Position left, top, x, y;
+ Dimension width, height, w, h;
+ Widget child;
+
+ nchild = 0;
+ $max_width = 0;
+ $max_height = 0;
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ if (! XtIsManaged(child)) continue;
+ nchild++;
+ $max_width = max($max_width, $child$width + 2*$child$border_width);
+ $max_height = max($max_height, $child$height + 2*$child$border_width);
+
+ }
+
+ $compute_inside($, left, top, width, height);
+
+ if ($columns != 0) {
+ ncols = $columns;
+ nrows = (nchild + ncols - 1)/ncols;
+ } else if ($rows != 0) {
+ nrows = $rows;
+ ncols = (nchild + nrows - 1)/nrows;
+ } else {
+ ncols = $max_width != 0 ? width/$max_width : 1;
+ if (ncols == 0) ncols = 1;
+ nrows = (nchild + ncols - 1)/ncols;
+ }
+
+ x = left;
+ y = top;
+ n = 0;
+ if ($storeByRow) {
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ if (! XtIsManaged(child)) continue;
+ align_child(child, x, y, $max_width, $max_height, $alignment);
+ n++;
+ if (n == ncols) {
+ n = 0;
+ x = left;
+ y += $max_height;
+ } else
+ x += $max_width;
+ }
+ } else {
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ if (! XtIsManaged(child)) continue;
+ align_child(child, x, y, $max_width, $max_height, $alignment);
+ n++;
+ if (n == nrows) {
+ n = 0;
+ y = top;
+ x += $max_width;
+ } else
+ y += $max_height;
+ }
+ }
+
+ if (shrink) {
+ w = 2*left + ncols * $max_width;
+ h = 2*top + nrows * $max_height;
+ if ($columns != 0)
+ XtVaSetValues($, XtNwidth, w, XtNheight, h, NULL);
+ else
+ XtVaSetValues($, XtNheight, h, NULL);
+ }
+}
+.fi
+
+When a child wants to change its size or border width, it calls its
+parent's \fIgeometry_manager\fP method (through a call to
+\fIXtMakeGeometryRequest\fP or \fIXtMakeResizeRequest\fP.) The RowCol widget
+always grants size changes to its children. The size change is carried
+out immediately and a new layout is computed. If a child requests a
+change of position, the request is denied. A request for a change in
+stacking order is ignored.
+
+.nf
+XtGeometryResult geometry_manager(Widget child, XtWidgetGeometry * request, XtWidgetGeometry * reply)
+{
+ Dimension newwd, newht, newbd;
+
+ if (request->request_mode (CWX | CWY)) return XtGeometryNo;
+ if (request->request_mode XtCWQueryOnly) return XtGeometryYes;
+
+ newwd = request->request_mode CWWidth ? request->width : $child$width;
+ newht = request->request_mode CWHeight ? request->height : $child$height;
+ newbd = request->request_mode CWBorderWidth
+ ? request->border_width : $child$border_width;
+
+ if (newwd == $child$width newht == $child$height
+ newbd == $child$border_width) return XtGeometryNo;
+
+ XtResizeWidget(child, newwd, newht, newbd);
+ $layout($, $shrinkToFit);
+ return XtGeometryDone;
+}
+.fi
+
+The \fIresize\fP method is called when the widget is resized. If the
+\fIrows\fP and \fIcolumns\fP resources are both zero, the children will have
+to be be re-aligned. In this case, there is no sense in asking the
+parent for a new size, so \fIlayout\fP is passed a value of \fIFalse\fP.
+
+.nf
+resize($)
+{
+ if ($rows == 0 $columns == 0) $layout($, False);
+}
+.fi
+
+The initialize method sets the private variables, in this case only
+\fImax_width\fP and \fImax_height\fP. There is no need to check if the resources
+have sensible values.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $max_width = $max_height = 0;
+}
+.fi
+
+The RowCol widget needs to recompute the positions of the children
+when one of the resources changes. When the layout changes, the widget
+also needs to be redrawn, of course. The private variables are not
+dependent on the resources, so they don't need recomputing.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_layout = False;
+ Boolean need_redisplay = False;
+
+ if ($old$storeByRow != $storeByRow) need_layout = True;
+ if ($old$rows != $rows) need_layout = True;
+ if ($old$columns != $columns) need_layout = True;
+ if ($old$alignment != $alignment) need_layout = True;
+ if ($old$shrinkToFit != $shrinkToFit) need_layout = True;
+ if (need_layout) {
+ $layout($, $shrinkToFit);
+ need_redisplay = True;
+ }
+ return need_redisplay;
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+.nf
+char rcsid[] = "$Header: RowCol.w,v 1.1 92/10/14 18:36:36 bert Exp $"
+.fi
+
+\fIalign_child\fP puts a widget in the proper position in the cell given by
+\fIcx\fP, \fIcy\fP, \fIwidth\fP and \fIheight\fP.
+
+.nf
+align_child($, int cx, int cy, int width, int height, Alignment alignment)
+{
+ Position x, y;
+
+ if (alignment XfwfLeft) x = cx;
+ else if (alignment XfwfRight) x = cx + width - $width;
+ else x = cx + (width - $width) / 2;
+ if (alignment XfwfTop) y = cy;
+ else if (alignment XfwfBottom) y = cy + height - $height;
+ else y = cy + (height - $height) / 2;
+ XtMoveWidget($, x, y);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/RowColP.h b/vendor/x11iraf/obm/ObmW/RowColP.h
new file mode 100644
index 00000000..2ddd950d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/RowColP.h
@@ -0,0 +1,51 @@
+/* Generated by wbuild from "RowCol.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfRowColP_H_
+#define _XfwfRowColP_H_
+#include "BoardP.h"
+#include "RowCol.h"
+typedef void (*layout_Proc)(
+#if NeedFunctionPrototypes
+Widget,int
+#endif
+);
+#define XtInherit_layout ((layout_Proc) _XtInherit)
+typedef struct {
+/* methods */
+layout_Proc layout;
+/* class variables */
+} XfwfRowColClassPart;
+typedef struct _XfwfRowColClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfRowColClassPart xfwfRowCol_class;
+} XfwfRowColClassRec;
+
+typedef struct {
+/* resources */
+Boolean storeByRow;
+int rows;
+int columns;
+Alignment alignment;
+Boolean shrinkToFit;
+/* private state */
+Dimension max_width;
+Dimension max_height;
+} XfwfRowColPart;
+
+typedef struct _XfwfRowColRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfRowColPart xfwfRowCol;
+} XfwfRowColRec;
+
+externalref XfwfRowColClassRec xfwfRowColClassRec;
+
+#endif /* _XfwfRowColP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Scrollbar.c b/vendor/x11iraf/obm/ObmW/Scrollbar.c
new file mode 100644
index 00000000..bec84d33
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Scrollbar.c
@@ -0,0 +1,427 @@
+/* Generated by wbuild from "Scrollbar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Arrow.h"
+#include "Slider2.h"
+#include <stdio.h>
+#include "ScrollbarP.h"
+static void Scroll(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"Scroll", Scroll},
+};
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void resize(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void insert_child(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void scroll_response(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static char rcsid[] = "$Header: Scrollbar.w,v 1.1 92/11/02 14:08:00 bert Exp $";
+static void up(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void down(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void thumbscroll(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void copy_background(
+#if NeedFunctionPrototypes
+Widget,int ,XrmValue *
+#endif
+);
+/*ARGSUSED*/static void up(arrow,client_data,call_data)Widget arrow;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+ XfwfScrollInfo info;
+
+ XfwfGetThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, &info);
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ info.reason = XfwfSUp;
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ } else {
+ info.reason = XfwfSLeft;
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ }
+ XtCallCallbackList(self, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollCallback, &info);
+}
+/*ARGSUSED*/static void down(arrow,client_data,call_data)Widget arrow;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+ XfwfScrollInfo info;
+
+ XfwfGetThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, &info);
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ info.reason = XfwfSDown;
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ } else {
+ info.reason = XfwfSRight;
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ }
+ XtCallCallbackList(self, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollCallback, &info);
+}
+/*ARGSUSED*/static void thumbscroll(w,client_data,call_data)Widget w;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+ XfwfScrollInfo *info = (XfwfScrollInfo*) call_data;
+
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical)
+ info->flags &= XFWF_VPOS;
+ else
+ info->flags &= XFWF_HPOS;
+ XtCallCallbackList(self, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollCallback, info);
+}
+/*ARGSUSED*/static void copy_background(self,offset,value)Widget self;int offset;XrmValue * value;
+{
+ value->addr = (XtPointer) &((XfwfScrollbarWidget)self)->core.background_pixel;
+}
+
+static XtResource resources[] = {
+{XtNvertical,XtCVertical,XtRBoolean,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.vertical),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.vertical),XtRImmediate,(XtPointer)True },
+{XtNscrollCallback,XtCScrollCallback,XtRCallback,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.scrollCallback),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.scrollCallback),XtRImmediate,(XtPointer)NULL },
+{XtNscrollResponse,XtCScrollResponse,XtRXTCallbackProc,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.scrollResponse),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.scrollResponse),XtRImmediate,(XtPointer)scroll_response },
+{XtNinitialDelay,XtCInitialDelay,XtRCardinal,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.initialDelay),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.initialDelay),XtRImmediate,(XtPointer)500 },
+{XtNrepeatDelay,XtCRepeatDelay,XtRCardinal,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.repeatDelay),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.repeatDelay),XtRImmediate,(XtPointer)50 },
+{XtNincrement,XtCIncrement,XtRFloat,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.increment),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.increment),XtRString,(XtPointer)"0.05"},
+{XtNscrollbarForeground,XtCScrollbarForeground,XtRPixel,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.scrollbarForeground),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.scrollbarForeground),XtRCallProc,(XtPointer)copy_background },
+{XtNshadow,XtCShadow,XtRDimension,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.shadow),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.shadow),XtRImmediate,(XtPointer)2 },
+{XtNminsize,XtCMinsize,XtRDimension,sizeof(((XfwfScrollbarRec*)NULL)->xfwfScrollbar.minsize),XtOffsetOf(XfwfScrollbarRec,xfwfScrollbar.minsize),XtRImmediate,(XtPointer)20 },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfScrollbarRec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfScrollbarRec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)2 },
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfScrollbarRec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfScrollbarRec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfSunken },
+};
+
+XfwfScrollbarClassRec xfwfScrollbarClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfBoardClassRec,
+"Scrollbar2",
+sizeof(XfwfScrollbarRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+1,
+resources,
+11,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+resize,
+XtInheritExpose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+NULL,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+insert_child,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfScrollbar_class part */
+scroll_response,
+},
+};
+WidgetClass xfwfScrollbarWidgetClass = (WidgetClass) &xfwfScrollbarClassRec;
+/*ARGSUSED*/
+static void Scroll(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XfwfScrollInfo info;
+
+ XfwfGetThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, &info);
+ info.reason = XfwfCvtStringToScrollReason(params[0]);
+ switch (info.reason) {
+ case XfwfSUp:
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ break;
+ case XfwfSDown:
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ break;
+ case XfwfSLeft:
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ break;
+ case XfwfSRight:
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + ((XfwfScrollbarWidget)self)->xfwfScrollbar.increment);
+ break;
+ case XfwfSPageUp:
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - info.vsize);
+ break;
+ case XfwfSPageDown:
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + info.vsize);
+ break;
+ case XfwfSPageLeft:
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - info.hsize);
+ break;
+ case XfwfSPageRight:
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + info.hsize);
+ break;
+ case XfwfSTop:
+ info.flags = XFWF_VPOS;
+ info.vpos = 0.0;
+ break;
+ case XfwfSBottom:
+ info.flags = XFWF_VPOS;
+ info.vpos = 1.0;
+ break;
+ case XfwfSLeftSide:
+ info.flags = XFWF_HPOS;
+ info.hpos = 0.0;
+ break;
+ case XfwfSRightSide:
+ info.flags = XFWF_HPOS;
+ info.hpos = 1.0;
+ break;
+ default: break; /* Not understood */
+ }
+ XtCallCallbackList(self, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollCallback, &info);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfScrollbarWidgetClass c = (XfwfScrollbarWidgetClass) class;
+ XfwfScrollbarWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfScrollbarWidgetClass) return;
+ super = (XfwfScrollbarWidgetClass)class->core_class.superclass;
+ if (c->xfwfScrollbar_class.scroll_response == XtInherit_scroll_response)
+ c->xfwfScrollbar_class.scroll_response = super->xfwfScrollbar_class.scroll_response;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Position x, y, xa2, xslider, ya2, yslider;
+ Dimension w, h, wa, ha, wslider, hslider;
+
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.initializing = True;
+ ((XfwfScrollbarWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ ha = wa = wslider = w;
+ xa2 = xslider = x;
+ hslider = (h - 2*ha > 0) ? h - 2*ha : 10;
+ yslider = y + ha;
+ ya2 = yslider + hslider;
+ } else {
+ wa = ha = hslider = h;
+ ya2 = yslider = y;
+ wslider = (w - 2*wa > 0) ? w - 2*wa : 10;
+ xslider = x + wa;
+ xa2 = xslider + wslider;
+ }
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow1 = XtVaCreateManagedWidget
+ ("_arrow1", xfwfArrowWidgetClass, self,
+ XtNx, x,
+ XtNy, y,
+ XtNwidth, wa,
+ XtNheight, ha,
+ XtNframeWidth, 0,
+ XtNforeground, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground,
+ XtNinitialDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.initialDelay,
+ XtNrepeatDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNdirection, ((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical?XfwfTop:XfwfLeft,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow1, XtNcallback, up, self);
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow2 = XtVaCreateManagedWidget
+ ("_arrow2", xfwfArrowWidgetClass, self,
+ XtNx, xa2,
+ XtNy, ya2,
+ XtNwidth, wa,
+ XtNheight, ha,
+ XtNframeWidth, 0,
+ XtNforeground, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground,
+ XtNinitialDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.initialDelay,
+ XtNrepeatDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNdirection, ((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical?XfwfBottom:XfwfRight,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow2, XtNcallback, down, self);
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.slider = XtVaCreateManagedWidget
+ ("_slider", xfwfSlider2WidgetClass, self,
+ XtNx, xslider,
+ XtNy, yslider,
+ XtNwidth, wslider,
+ XtNheight, hslider,
+ XtNthumbColor, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground,
+ XtNframeWidth, 0,
+ XtNinitialDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.initialDelay,
+ XtNrepeatDelay, ((XfwfScrollbarWidget)self)->xfwfScrollbar.repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, XtNscrollCallback, thumbscroll, self);
+ XtVaGetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, XtNscrollResponse, &((XfwfScrollbarWidget)self)->xfwfScrollbar.slider_scroll, NULL);
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.initializing = False;
+}
+/*ARGSUSED*/static void resize(self)Widget self;
+{
+ Position x, y, xa2, xslider, ya2, yslider;
+ Dimension w, h, wa, ha, wslider, hslider;
+
+ ((XfwfScrollbarWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ wa = wslider = w;
+ xa2 = xslider = x;
+ ha = 2 * (wa + 1)/3;
+ hslider = (h - 2*ha > 0) ? h - 2*ha : 10;
+ yslider = y + ha;
+ ya2 = yslider + hslider;
+ } else {
+ ha = hslider = h;
+ ya2 = yslider = y;
+ wa = 2 * (ha + 1)/3;
+ wslider = (w - 2*wa > 0) ? w - 2*wa : 10;
+ xslider = x + wa;
+ xa2 = xslider + wslider;
+ }
+ XtConfigureWidget(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow1, x, y, wa, ha, 0);
+ XtConfigureWidget(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow2, xa2, ya2, wa, ha, 0);
+ XtConfigureWidget(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, xslider, yslider, wslider, hslider, 0);
+}
+/*ARGSUSED*/static void insert_child(child)Widget child;
+{ Widget self = XtParent(child); {
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.initializing)
+ xfwfBoardClassRec.composite_class.insert_child(child);
+ else {
+ char s[500];
+ (void)sprintf(s, "Cannot add children to a scrollbar (\"%s\"->\"%s\")",
+ XtName(child), XtName(self));
+ XtWarning(s);
+ }
+}
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ if (((XfwfScrollbarWidget)old)->xfwfScrollbar.vertical != ((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ XtWarning("Cannot change the \"vertical\" resource of a scrollbar\n");
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical = ((XfwfScrollbarWidget)old)->xfwfScrollbar.vertical;
+ }
+ if (((XfwfScrollbarWidget)old)->xfwfScrollbar.scrollbarForeground != ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground) {
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, XtNthumbColor, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground, NULL);
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow1, XtNforeground, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground, NULL);
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow2, XtNforeground, ((XfwfScrollbarWidget)self)->xfwfScrollbar.scrollbarForeground, NULL);
+ }
+ if (((XfwfScrollbarWidget)old)->xfwfScrollbar.shadow != ((XfwfScrollbarWidget)self)->xfwfScrollbar.shadow) {
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, XtNthumbFrameWidth, ((XfwfScrollbarWidget)self)->xfwfScrollbar.shadow, NULL);
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow1, XtNarrowShadow, ((XfwfScrollbarWidget)self)->xfwfScrollbar.shadow, NULL);
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.arrow2, XtNarrowShadow, ((XfwfScrollbarWidget)self)->xfwfScrollbar.shadow, NULL);
+ }
+ if (((XfwfScrollbarWidget)old)->xfwfScrollbar.minsize != ((XfwfScrollbarWidget)self)->xfwfScrollbar.minsize) {
+ XtVaSetValues(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, XtNminsize, ((XfwfScrollbarWidget)self)->xfwfScrollbar.minsize, NULL);
+ }
+ return False;
+}
+/*ARGSUSED*/static void scroll_response(wdg,client_data,call_data)Widget wdg;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+
+ ((XfwfScrollbarWidget)self)->xfwfScrollbar.slider_scroll(wdg, ((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, call_data);
+}
+/*ARGSUSED*/void XfwfSetScrollbar(self,pos,size)Widget self;double pos;double size;
+{
+ if (! XtIsSubclass(self, xfwfScrollbarWidgetClass))
+ XtError("XfwfSetScrollbar called with incorrect widget type");
+ if (pos < 0.0 || pos > 1.0 || size < 0.0 || size > 1.0)
+ XtError("XfwfSetScrollbar called with incorrect arguments");
+ if (((XfwfScrollbarWidget)self)->xfwfScrollbar.vertical) {
+ XfwfResizeThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, 1.0, size);
+ XfwfMoveThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, 0.0, pos);
+ } else {
+ XfwfResizeThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, size, 1.0);
+ XfwfMoveThumb(((XfwfScrollbarWidget)self)->xfwfScrollbar.slider, pos, 0.0);
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Scrollbar.h b/vendor/x11iraf/obm/ObmW/Scrollbar.h
new file mode 100644
index 00000000..9c5c62e8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Scrollbar.h
@@ -0,0 +1,105 @@
+/* Generated by wbuild from "Scrollbar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfScrollbar_H_
+#define _XfwfScrollbar_H_
+#include "Board.h"
+void XfwfSetScrollbar(
+#if NeedFunctionPrototypes
+Widget,double ,double
+#endif
+);
+#ifndef XtNvertical
+#define XtNvertical "vertical"
+#endif
+#ifndef XtCVertical
+#define XtCVertical "Vertical"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+#ifndef XtNscrollCallback
+#define XtNscrollCallback "scrollCallback"
+#endif
+#ifndef XtCScrollCallback
+#define XtCScrollCallback "ScrollCallback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+#ifndef XtNscrollResponse
+#define XtNscrollResponse "scrollResponse"
+#endif
+#ifndef XtCScrollResponse
+#define XtCScrollResponse "ScrollResponse"
+#endif
+#ifndef XtRXTCallbackProc
+#define XtRXTCallbackProc "XTCallbackProc"
+#endif
+
+#ifndef XtNinitialDelay
+#define XtNinitialDelay "initialDelay"
+#endif
+#ifndef XtCInitialDelay
+#define XtCInitialDelay "InitialDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNrepeatDelay
+#define XtNrepeatDelay "repeatDelay"
+#endif
+#ifndef XtCRepeatDelay
+#define XtCRepeatDelay "RepeatDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNincrement
+#define XtNincrement "increment"
+#endif
+#ifndef XtCIncrement
+#define XtCIncrement "Increment"
+#endif
+#ifndef XtRFloat
+#define XtRFloat "Float"
+#endif
+
+#ifndef XtNscrollbarForeground
+#define XtNscrollbarForeground "scrollbarForeground"
+#endif
+#ifndef XtCScrollbarForeground
+#define XtCScrollbarForeground "ScrollbarForeground"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNshadow
+#define XtNshadow "shadow"
+#endif
+#ifndef XtCShadow
+#define XtCShadow "Shadow"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNminsize
+#define XtNminsize "minsize"
+#endif
+#ifndef XtCMinsize
+#define XtCMinsize "Minsize"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+typedef struct _XfwfScrollbarClassRec *XfwfScrollbarWidgetClass;
+typedef struct _XfwfScrollbarRec *XfwfScrollbarWidget;
+externalref WidgetClass xfwfScrollbarWidgetClass;
+#endif /*_XfwfScrollbar_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Scrollbar.man b/vendor/x11iraf/obm/ObmW/Scrollbar.man
new file mode 100644
index 00000000..46c2b29f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Scrollbar.man
@@ -0,0 +1,812 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfScrollbar
+.SH DESCRIPTION
+The scrollbar widget helps the user to view data that is too large
+to be displayed all at once. They are often used through a
+ScrolledWindow (see there), where they are put next to and/or below
+the widget that contains the data. The scrollbar controls which part
+is visible. By manipulating the scrollbar the user can move (`scroll')
+the data within the other widget.
+
+A scrollbar consists of two arrows placed at each end of a rectangle,
+either at the top and bottom or at the left and right. The former is
+called a vertical scrollbar, the latter a horizontal one. A smaller
+rectangle, called the thumb or slider, is placed within the larger
+one. It can move up and down (vertical scrollbar) or left/right
+(horizontal scrollbar). Clicking an arrow moves the data in that
+direction. Pressing the mouse button on an arrow and holding it, moves
+the data by small increments as long as the mouse button is down.
+Dragging the slider moves the data proportionally with the slider,
+either along with the movement of the mouse, or all at once when the
+mouse button is released. Pressing the mouse button onthe rectangle
+outside the slider moves the data in larger increments.
+
+The ratio of the slider size to the scroll region size typically
+corresponds to the relationship between the size of the visible data
+and the total size of the data. For example, if 10 percent of the
+data is visible, the slider typically occupies 10 percent of the
+scroll region. This provides the user with a visual clue to the size
+of the invisible data.
+
+The scrollbar widget can be configured as either horizontal or
+vertical. It is made up of two XfwfArrow widgets and an XfwfSlider2
+widget. Therefore, many of the scrollbar's resources are actually
+resources for these, nameless, widgets. The scrollbar has the
+same callback list as the slider.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfScrollbar
+Name Class Type Default
+XtNvertical XtCVertical Boolean True
+XtNscrollCallback XtCScrollCallback Callback NULL
+XtNscrollResponse XtCScrollResponse XTCallbackProc scroll_response
+XtNinitialDelay XtCInitialDelay Cardinal 500
+XtNrepeatDelay XtCRepeatDelay Cardinal 50
+XtNincrement XtCIncrement Float "0.05"
+XtNscrollbarForeground XtCScrollbarForeground Pixel copy_background
+XtNshadow XtCShadow Dimension 2
+XtNminsize XtCMinsize Dimension 20
+
+.TE
+.ps
+
+.TP
+.I "XtNvertical"
+The orientation of the scrollbar is set with the \fIvertical\fP
+resource. \fITrue\fP means vertical, \fIFalse\fP horizontal. This resource may
+only be set during initialization. Any changes via \fIXtVaSetValues\fP
+result in a warning and are then ignored.
+
+
+
+.hi
+
+.nf
+Boolean vertical = True
+.fi
+
+.eh
+
+.TP
+.I "XtNscrollCallback"
+The user can interact with the scrollbar in many ways, but there is
+only a single callback list: \fIscrollCallback\fP. The callback uses the
+\fIcall_data\fP parameter to pass a pointer to an \fIXfwfScrollInfo\fP
+structure: \fIstruct {XfwfSReason reason; XfwfSFlags flags; float vpos,
+vsize, hpos, hsize;}\fP The \fIflags\fP field is a bitwise combination of
+\fIXFWF_VPOS\fP, \fIXFWF_HPOS\fP, \fIXFWF_VSIZE\fP and \fIXFWF_HSIZE\fP. The
+structure contains a field \fIreason\fP, which can have the following
+values (there exist other values, but they are not used by the
+scrollbar):
+
+\item{-} \fIXfwfSUp\fP: if the user clicked (or holds) the up arrow.
+\item{-} \fIXfwfSLeft\fP: ditto left arrow.
+\item{-} \fIXfwfSDown\fP: ditto down arrow.
+\item{-} \fIXfwfSRight\fP: ditto right arrow.
+\item{-} \fIXfwfSPageUp\fP: ditto area above thumb.
+\item{-} \fIXfwfSPageDown\fP: ditto area below thumb.
+\item{-} \fIXfwfSPageLeft\fP: ditto area left of thumb.
+\item{-} \fIXfwfSPageRight\fP: ditto area right of thumb.
+\item{-} \fIXfwfSDrag\fP: if the user drags the thumb.
+\item{-} \fIXfwfSMove\fP: if the user stops dragging the thumb.
+
+The other four fields contain the new position of the thumb, as
+numbers between 0.0 and 1.0 inclusive. In the case of drag and drop
+actions, the position and size reflect the thumb's {\em actual}
+position at the end of the dragging. In the other cases, the position
+is the {\em suggested} new position. In these latter cases, the
+callback routine should compute the new position and use a call to the
+function in the \fIScrollResponse\fP resource (or, more conveniently, to
+\fIXfwfSetScrollbar\fP) to update the scrollbar.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList scrollCallback = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNscrollResponse"
+The standard way to update the scrollbar is with a call to the
+function that is knwon as the \fIscrollResponse\fP function. To get a
+pointer to that function, you should use \fIXtGetValues\fP or
+\fIXtVaGetValues\fP on the \fIXtNscrollResponse\fP resource. But from an
+application it might be easier to use the \fIXfwfSetScrollbar\fP
+convenience function instead.
+
+The \fIscrollResponse\fP routine has the same format as a callback
+procedure. The first argument is a widget, this argument is ignored.
+The second argument is \fIXtPointer client_data\fP, it must point to the
+scrollbar that is to be updated. The third argument is \fIXtPointer
+call_data\fP, it must be a pointer to an \fIXfwfScrollInfo\fP structure (see
+above).
+
+
+
+.hi
+
+.nf
+XtCallbackProc scrollResponse = scroll_response
+.fi
+
+.eh
+
+.TP
+.I "XtNinitialDelay"
+When the user presses and then holds the mouse button on an arrow or
+on an area outside the thumb, the scrollbar waits some milliseconds
+before it starts repeating the callbacks.
+
+
+
+.hi
+
+.nf
+Cardinal initialDelay = 500
+.fi
+
+.eh
+
+.TP
+.I "XtNrepeatDelay"
+Between repeated calls to the callback routines, the scrollbar will
+wait a few milliseconds.
+
+
+
+.hi
+
+.nf
+Cardinal repeatDelay = 50
+.fi
+
+.eh
+
+.TP
+.I "XtNincrement"
+Some widgets may be simple enough that they can scroll a fixed
+amount whenever the user clicks on one of the arrow buttons. If that
+is the case, they can let the scrollbar compute the new position. It
+will be passed in the \fIXfwfScrollInfo\fP structure as the suggested new
+position. Any receiver is free to ignore the suggestion, however. The
+default is to add or subtract 0.05.
+
+
+
+.hi
+
+.nf
+float increment = <String>"0.05"
+.fi
+
+.eh
+
+.TP
+.I "XtNscrollbarForeground"
+The color of the arrow and the thumb also determines the color of
+the 3D shadow, at least if \fIshadowScheme\fP is set to \fIXfwfAuto\fP, as it
+is by default. The default value is determined dynamically, it is
+copied from the \fIbackground\fP resource.
+
+
+
+.hi
+
+.nf
+Pixel scrollbarForeground = <CallProc>copy_background
+.fi
+
+.eh
+
+.TP
+.I "XtNshadow"
+The width of the arrow's and thumb's shadow is by default 2 pixels.
+
+
+
+.hi
+
+.nf
+Dimension shadow = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNminsize"
+The minimum size of the thumb is by default 20 pixels. It can be set
+with the \fIminsize\fP resource.
+
+
+
+.hi
+
+.nf
+Dimension minsize = 20
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+The slider and the two arrows frame will be forced to 0 pixels. The
+only frame is that of the whole scrollbar. The default frame width is
+changed from 0 to 2.
+
+
+
+.hi
+
+.nf
+ frameWidth = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNframeType"
+The default frame type is now \fIXfwfSunken\fP.
+
+
+
+.hi
+
+.nf
+ frameType = XfwfSunken
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The \fIXfwfSetScrollbar\fP convenience function can be used to set the
+position and size of a scrollbar. The two arguments must be between
+0.0 and 1.0 (inclusive).
+
+.nf
+XfwfSetScrollbar( $, double pos, double size)
+.fi
+
+.hi
+{
+ if (! XtIsSubclass($, xfwfScrollbarWidgetClass))
+ XtError("XfwfSetScrollbar called with incorrect widget type");
+ if (pos < 0.0 || pos > 1.0 || size < 0.0 || size > 1.0)
+ XtError("XfwfSetScrollbar called with incorrect arguments");
+ if ($vertical) {
+ XfwfResizeThumb($slider, 1.0, size);
+ XfwfMoveThumb($slider, 0.0, pos);
+ } else {
+ XfwfResizeThumb($slider, size, 1.0);
+ XfwfMoveThumb($slider, pos, 0.0);
+ }
+}
+.eh
+
+.hi
+.SS "Actions"
+
+.TP
+.I "Scroll
+
+The following action is not used by default, but it is defined here,
+because someone might want to bind it to keys. For example, the
+subclasses \fIXfwfVScrollbar\fP and \fIXfwfHScrollbar\fP do that.
+
+.hi
+
+.nf
+void Scroll($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XfwfScrollInfo info;
+
+ XfwfGetThumb($slider, info);
+ info.reason = XfwfCvtStringToScrollReason(params[0]);
+ switch (info.reason) {
+ case XfwfSUp:
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - $increment);
+ break;
+ case XfwfSDown:
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + $increment);
+ break;
+ case XfwfSLeft:
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - $increment);
+ break;
+ case XfwfSRight:
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + $increment);
+ break;
+ case XfwfSPageUp:
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - info.vsize);
+ break;
+ case XfwfSPageDown:
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + info.vsize);
+ break;
+ case XfwfSPageLeft:
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - info.hsize);
+ break;
+ case XfwfSPageRight:
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + info.hsize);
+ break;
+ case XfwfSTop:
+ info.flags = XFWF_VPOS;
+ info.vpos = 0.0;
+ break;
+ case XfwfSBottom:
+ info.flags = XFWF_VPOS;
+ info.vpos = 1.0;
+ break;
+ case XfwfSLeftSide:
+ info.flags = XFWF_HPOS;
+ info.hpos = 0.0;
+ break;
+ case XfwfSRightSide:
+ info.flags = XFWF_HPOS;
+ info.hpos = 1.0;
+ break;
+ default: break; /* Not understood */
+ }
+ XtCallCallbackList($, $scrollCallback, info);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ <Xfwf/Arrow.h>
+.fi
+
+.nf
+
+.B incl
+ <Xfwf/Slider2.h>
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The three children of the scrollbar are stored in private variables.
+
+
+
+.nf
+Widget arrow1
+.fi
+
+.nf
+Widget arrow2
+.fi
+
+.nf
+Widget slider
+.fi
+
+During the \fIinitialize\fP method, the variable \fIinitializing\fP will be
+\fITrue\fP, so that \fIinsert_child\fP can check whether a child should be
+inserted or not.
+
+
+
+.nf
+Boolean initializing
+.fi
+
+The \fIscrollResponse\fP function of the Slider2 that implements the
+thumb is stored in a private variable.
+
+
+
+.nf
+XtCallbackProc slider_scroll
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The \fIinitialize\fP method creates the three widgets that make up the
+scrollbar: two arrows and a slider. It sets the resources of these
+widgets and redirects the callbacks.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Position x, y, xa2, xslider, ya2, yslider;
+ Dimension w, h, wa, ha, wslider, hslider;
+
+ $initializing = True;
+ $compute_inside($, x, y, w, h);
+ if ($vertical) {
+ ha = wa = wslider = w;
+ xa2 = xslider = x;
+ hslider = (h - 2*ha > 0) ? h - 2*ha : 10;
+ yslider = y + ha;
+ ya2 = yslider + hslider;
+ } else {
+ wa = ha = hslider = h;
+ ya2 = yslider = y;
+ wslider = (w - 2*wa > 0) ? w - 2*wa : 10;
+ xslider = x + wa;
+ xa2 = xslider + wslider;
+ }
+ $arrow1 = XtVaCreateManagedWidget
+ ("_arrow1", xfwfArrowWidgetClass, $,
+ XtNx, x,
+ XtNy, y,
+ XtNwidth, wa,
+ XtNheight, ha,
+ XtNframeWidth, 0,
+ XtNforeground, $scrollbarForeground,
+ XtNinitialDelay, $initialDelay,
+ XtNrepeatDelay, $repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNdirection, $vertical?XfwfTop:XfwfLeft,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback($arrow1, XtNcallback, up, $);
+ $arrow2 = XtVaCreateManagedWidget
+ ("_arrow2", xfwfArrowWidgetClass, $,
+ XtNx, xa2,
+ XtNy, ya2,
+ XtNwidth, wa,
+ XtNheight, ha,
+ XtNframeWidth, 0,
+ XtNforeground, $scrollbarForeground,
+ XtNinitialDelay, $initialDelay,
+ XtNrepeatDelay, $repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNdirection, $vertical?XfwfBottom:XfwfRight,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback($arrow2, XtNcallback, down, $);
+ $slider = XtVaCreateManagedWidget
+ ("_slider", xfwfSlider2WidgetClass, $,
+ XtNx, xslider,
+ XtNy, yslider,
+ XtNwidth, wslider,
+ XtNheight, hslider,
+ XtNthumbColor, $scrollbarForeground,
+ XtNframeWidth, 0,
+ XtNinitialDelay, $initialDelay,
+ XtNrepeatDelay, $repeatDelay,
+ XtNtraversalOn, False,
+ XtNhighlightThickness, 0,
+ XtNouterOffset, 0,
+ XtNborderWidth, 0,
+ NULL);
+ XtAddCallback($slider, XtNscrollCallback, thumbscroll, $);
+ XtVaGetValues($slider, XtNscrollResponse, $slider_scroll, NULL);
+ $initializing = False;
+}
+.fi
+
+When the scrollbar is resized, the children must be resized also.
+
+.nf
+resize($)
+{
+ Position x, y, xa2, xslider, ya2, yslider;
+ Dimension w, h, wa, ha, wslider, hslider;
+
+ $compute_inside($, x, y, w, h);
+ if ($vertical) {
+ wa = wslider = w;
+ xa2 = xslider = x;
+ ha = 2 * (wa + 1)/3;
+ hslider = (h - 2*ha > 0) ? h - 2*ha : 10;
+ yslider = y + ha;
+ ya2 = yslider + hslider;
+ } else {
+ ha = hslider = h;
+ ya2 = yslider = y;
+ wa = 2 * (ha + 1)/3;
+ wslider = (w - 2*wa > 0) ? w - 2*wa : 10;
+ xslider = x + wa;
+ xa2 = xslider + wslider;
+ }
+ XtConfigureWidget($arrow1, x, y, wa, ha, 0);
+ XtConfigureWidget($arrow2, xa2, ya2, wa, ha, 0);
+ XtConfigureWidget($slider, xslider, yslider, wslider, hslider, 0);
+}
+.fi
+
+\fIinsert_child\fP is redefined here only to be able to give a warning
+when a child is inserted beyond the three that are created in the
+\fIinitialize\fP method.
+
+.nf
+insert_child(Widget child)
+{
+ if ($initializing)
+ #insert_child(child);
+ else {
+ char s[500];
+ (void)sprintf(s, "Cannot add children to a scrollbar (\\"%s\\"->\\"%s\\")",
+ XtName(child), XtName($));
+ XtWarning(s);
+ }
+}
+.fi
+
+The \fIset_values\fP method passes resource values on to the three
+children.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($old$vertical != $vertical) {
+ XtWarning("Cannot change the \\"vertical\\" resource of a scrollbar\\n");
+ $vertical = $old$vertical;
+ }
+ if ($old$scrollbarForeground != $scrollbarForeground) {
+ XtVaSetValues($slider, XtNthumbColor, $scrollbarForeground, NULL);
+ XtVaSetValues($arrow1, XtNforeground, $scrollbarForeground, NULL);
+ XtVaSetValues($arrow2, XtNforeground, $scrollbarForeground, NULL);
+ }
+ if ($old$shadow != $shadow) {
+ XtVaSetValues($slider, XtNthumbFrameWidth, $shadow, NULL);
+ XtVaSetValues($arrow1, XtNarrowShadow, $shadow, NULL);
+ XtVaSetValues($arrow2, XtNarrowShadow, $shadow, NULL);
+ }
+ if ($old$minsize != $minsize) {
+ XtVaSetValues($slider, XtNminsize, $minsize, NULL);
+ }
+ return False;
+}
+.fi
+
+The \fIscroll_response\fP method is accessed via the \fIscrollResponse\fP
+resource. It is passed the scrollbar itself as the \fIclient_data\fP
+argument and a pointer to an \fIXfwfScrollInfo\fP record as \fIcall_data\fP.
+
+The scrollbar passes on the call to the Slider2 widget that is
+managing the thumb.
+
+.nf
+scroll_response(Widget wdg, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = (Widget) client_data;
+
+ $slider_scroll(wdg, $slider, call_data);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+.nf
+char rcsid[] = "$Header: Scrollbar.w,v 1.1 92/11/02 14:08:00 bert Exp $"
+.fi
+
+The \fIup\fP routine is a callback for the first arrow. It invokes the
+scrollbar's callback.
+
+.nf
+up(Widget arrow, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = (Widget) client_data;
+ XfwfScrollInfo info;
+
+ XfwfGetThumb($slider, info);
+ if ($vertical) {
+ info.reason = XfwfSUp;
+ info.flags = XFWF_VPOS;
+ info.vpos = max(0.0, info.vpos - $increment);
+ } else {
+ info.reason = XfwfSLeft;
+ info.flags = XFWF_HPOS;
+ info.hpos = max(0.0, info.hpos - $increment);
+ }
+ XtCallCallbackList($, $scrollCallback, info);
+}
+.fi
+
+The \fIdown\fP routine is the callback for the second arrow. It invokes the
+scrollbar's callback.
+
+.nf
+down(Widget arrow, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = (Widget) client_data;
+ XfwfScrollInfo info;
+
+ XfwfGetThumb($slider, info);
+ if ($vertical) {
+ info.reason = XfwfSDown;
+ info.flags = XFWF_VPOS;
+ info.vpos = min(1.0, info.vpos + $increment);
+ } else {
+ info.reason = XfwfSRight;
+ info.flags = XFWF_HPOS;
+ info.hpos = min(1.0, info.hpos + $increment);
+ }
+ XtCallCallbackList($, $scrollCallback, info);
+}
+.fi
+
+The \fIthumbscroll\fP routine is the callback for the scroll callback of
+the slider. It invokes the scrollbar's \fIscrollCallback\fP, after making
+sure that only appropriate position information is passed. (The
+Slider2 might pass horizontal position where only vertical position is
+relevant, and vice versa.)
+
+.nf
+thumbscroll(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget $ = (Widget) client_data;
+ XfwfScrollInfo *info = (XfwfScrollInfo*) call_data;
+
+ if ($vertical)
+ info->flags = XFWF_VPOS;
+ else
+ info->flags = XFWF_HPOS;
+ XtCallCallbackList($, $scrollCallback, info);
+}
+.fi
+
+The \fIcopy_background\fP routine is resource default procedure. It is
+called to initialize the default value of the \fIforeground\fP resource.
+
+.nf
+copy_background($, int offset, XrmValue * value)
+{
+ value->addr = (XtPointer) $background_pixel;
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/ScrollbarP.h b/vendor/x11iraf/obm/ObmW/ScrollbarP.h
new file mode 100644
index 00000000..111ee455
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ScrollbarP.h
@@ -0,0 +1,58 @@
+/* Generated by wbuild from "Scrollbar.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfScrollbarP_H_
+#define _XfwfScrollbarP_H_
+#include "BoardP.h"
+#include "Scrollbar.h"
+typedef void (*scroll_response_Proc)(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+#define XtInherit_scroll_response ((scroll_response_Proc) _XtInherit)
+typedef struct {
+/* methods */
+scroll_response_Proc scroll_response;
+/* class variables */
+} XfwfScrollbarClassPart;
+typedef struct _XfwfScrollbarClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfScrollbarClassPart xfwfScrollbar_class;
+} XfwfScrollbarClassRec;
+
+typedef struct {
+/* resources */
+Boolean vertical;
+XtCallbackList scrollCallback;
+XtCallbackProc scrollResponse;
+Cardinal initialDelay;
+Cardinal repeatDelay;
+float increment;
+Pixel scrollbarForeground;
+Dimension shadow;
+Dimension minsize;
+/* private state */
+Widget arrow1;
+Widget arrow2;
+Widget slider;
+Boolean initializing;
+XtCallbackProc slider_scroll;
+} XfwfScrollbarPart;
+
+typedef struct _XfwfScrollbarRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfScrollbarPart xfwfScrollbar;
+} XfwfScrollbarRec;
+
+externalref XfwfScrollbarClassRec xfwfScrollbarClassRec;
+
+#endif /* _XfwfScrollbarP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Separator.c b/vendor/x11iraf/obm/ObmW/Separator.c
new file mode 100644
index 00000000..f7669a76
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Separator.c
@@ -0,0 +1,357 @@
+/*
+ * Separator.c - Separator widget Vladimir Romanovski
+ *
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/RectObjP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/SeparatorP.h>
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xmu/Drawing.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+#define offset(field) XtOffsetOf(SeparatorRec, field)
+
+static XtResource resources[] = {
+ {
+ XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
+ offset(separator.orientation), XtRImmediate, (XtPointer) XtorientHorizontal
+ },
+ {
+ XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(separator.margin), XtRImmediate, (caddr_t)1
+ },
+ {
+ XtNseparatorType, XtCSeparatorType, XtRSeparatorType,
+ sizeof(XawSeparatorType), offset(separator.separatorType),
+ XtRImmediate,(caddr_t)XawSHADOW_ETCHED_IN
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(simple.shadow_thickness), XtRImmediate, (XtPointer)0
+ }
+};
+#undef offset
+
+static void Initialize();
+static void Resize();
+static void Redisplay();
+static Boolean SetValues();
+static void ClassInitialize();
+static void Destroy();
+
+SeparatorClassRec separatorClassRec = {
+ {
+ /* core_class fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Separator",
+ /* widget_size */ sizeof(SeparatorRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* Simple class fields initialization */
+ /* change_sensitive */ XtInheritChangeSensitive,
+ /* display_rect */ XtInheritDisplayRectProc,
+ /* extension */ NULL
+ },
+ { /* Separator class fields initialization */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass separatorWidgetClass = (WidgetClass)&separatorClassRec;
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+/*---------------------------------------------*/
+#define done( type, value ) \
+{ \
+ if ( toVal->addr != NULL ) \
+ { \
+ if ( toVal->size < sizeof( type ) ) \
+ { \
+ toVal->size = sizeof( type ); \
+ return False; \
+ } \
+ *(type*)(toVal->addr) = (value); \
+ } \
+ else \
+ { \
+ static type static_val; \
+ static_val = (value); \
+ toVal->addr = (caddr_t)&static_val; \
+ } \
+ toVal->size = sizeof(type); \
+ return True; \
+} \
+/*---------------------------------------------*/
+
+static XrmQuark QSingle, QDouble, QShadowIn, QShadowOut;
+
+/* ARGSUSED */
+static Boolean
+CvtStringToSeparatorType(dpy, args, num_args, fromVal, toVal, convData)
+ Display *dpy;
+ XrmValuePtr args; /* unused */
+ Cardinal *num_args; /* unused */
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+ XtPointer *convData; /* unused */
+{
+ static XawSeparatorType separatorType;
+ XrmQuark q;
+ char lowerName[BUFSIZ];
+
+ XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
+ q = XrmStringToQuark(lowerName);
+
+ separatorType = XawSINGLE_LINE;
+
+ if (q == QSingle) separatorType = XawSINGLE_LINE;
+ else if (q == QDouble) separatorType = XawDOUBLE_LINE;
+ else if (q == QShadowIn) separatorType = XawSHADOW_ETCHED_IN;
+ else if (q == QShadowOut) separatorType = XawSHADOW_ETCHED_OUT;
+ else
+ XtDisplayStringConversionWarning( dpy, (char *)fromVal->addr,
+ XtRSeparatorType);
+
+ done(XawSeparatorType, separatorType);
+}
+#undef done
+
+static void ClassInitialize()
+{
+ XawInitializeWidgetSet();
+ XtSetTypeConverter( XtRString, XtRSeparatorType, CvtStringToSeparatorType,
+ (XtConvertArgList)NULL, (Cardinal)0,
+ XtCacheNone, (XtDestructor)NULL);
+
+ QSingle = XrmStringToQuark(XawSingle_Line);
+ QDouble = XrmStringToQuark(XawDouble_Line);
+ QShadowIn = XrmStringToQuark(XawShadow_Etched_In);
+ QShadowOut = XrmStringToQuark(XawShadow_Etched_Out);
+}
+
+static void GetGC(sw)
+ SeparatorWidget sw;
+{
+ XGCValues values;
+ unsigned long mask;
+
+ values.foreground = sw->simple.foreground;
+ values.line_width = 0;
+ mask = GCForeground | GCLineWidth;
+
+ sw->separator.gc = XtGetGC ((Widget)sw, mask, (XGCValues*)&values);
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SeparatorWidget newsw = (SeparatorWidget) new;
+
+ if (newsw->core.width == 0)
+ newsw->core.width = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (newsw->core.height == 0)
+ newsw->core.height = 8 + 2*SIMPLE_MARGIN(new);
+
+ GetGC(newsw);
+
+}
+
+static void Resize(w)
+ Widget w;
+{
+ /* If widget is realized, clear and redisplay it */
+
+ if (XtIsRealized(w)) {
+ XClearWindow(XtDisplay(w), XtWindow(w));
+ (*separatorClassRec.core_class.expose) (w, (XEvent*)NULL, (Region)NULL);
+ }
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SeparatorWidget cursw = (SeparatorWidget) current;
+ SeparatorWidget newsw = (SeparatorWidget) new;
+ Boolean redisplay = False;
+
+#define NE(field) (cursw->separator.field != newsw->separator.field)
+
+ if (newsw->core.width == 0)
+ newsw->core.width = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (newsw->core.height == 0)
+ newsw->core.height = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (NE(margin) || NE(separatorType))
+ redisplay = True;
+
+ if (cursw->simple.foreground != newsw->simple.foreground)
+ {
+ XtReleaseGC(new, cursw->separator.gc);
+ GetGC(newsw);
+ redisplay = True;
+ }
+
+ return redisplay;
+}
+
+static void Destroy(w)
+ Widget w;
+{
+ XtReleaseGC( w, ((SeparatorWidget)w)->separator.gc );
+}
+
+static void Redisplay(gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register SeparatorWidget sw = (SeparatorWidget) gw;
+ int x1, y1, x2, y2;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ if (sw->simple.shadow_thickness > 0)
+ (*simpleWidgetClass->core_class.expose) (gw, event, region);
+
+ if (sw->separator.orientation == XtorientHorizontal) {
+ x1 = sw->separator.margin;
+ x2 = sw->core.width - (x1 * 2);
+
+ switch(sw->separator.separatorType) {
+
+ case XawSHADOW_ETCHED_IN :
+ y1 = (sw->core.height - 2) / 2;
+ y2 = y1 + 1;
+
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x2, y1);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x1, y2, x2, y2);
+ break;
+ case XawSHADOW_ETCHED_OUT:
+ y1 = (sw->core.height - 2) / 2;
+ y2 = y1 + 1;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y2, x2, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x1, y1, x2, y1);
+ break;
+
+ case XawDOUBLE_LINE:
+ y1 = (sw->core.height - 2)/ 2;
+ y2 = y1 + 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x2, y1);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y2, x2, y2);
+ break;
+
+ case XawSINGLE_LINE :
+ y1 = sw->core.height / 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x2, y1);
+ default:
+ break;
+ }
+ } else {
+ y1 = sw->separator.margin;
+ y2 = sw->core.height - (y1 * 2);
+
+ switch(sw->separator.separatorType) {
+
+ case XawSHADOW_ETCHED_IN :
+ x1 = (sw->core.width - 2) / 2;
+ x2 = x1 + 1;
+
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x2, y1, x2, y2);
+ break;
+ case XawSHADOW_ETCHED_OUT:
+ x1 = (sw->core.width - 2) / 2;
+ x2 = x1 + 1;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x2, y1, x2, y2);
+ break;
+
+ case XawDOUBLE_LINE:
+ x1 = (sw->core.width - 2)/ 2;
+ x2 = x1 + 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x2, y1, x2, y2);
+ break;
+
+ case XawSINGLE_LINE :
+ x1 = sw->core.width / 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x1, y2);
+ default:
+ break;
+ }
+ }
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Separator.h b/vendor/x11iraf/obm/ObmW/Separator.h
new file mode 100644
index 00000000..e6d6eff8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Separator.h
@@ -0,0 +1,98 @@
+#ifndef _XawSeparator_h
+#define _XawSeparator_h
+
+/***********************************************************************
+ *
+ * Separator Widget
+ *
+ ***********************************************************************/
+
+#include "XrawInit.h"
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback XtCallbackList NULL
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+
+
+typedef enum {
+ XawSINGLE_LINE = Xraw_SEPARATOR,
+ XawDOUBLE_LINE,
+ XawSHADOW_ETCHED_IN,
+ XawSHADOW_ETCHED_OUT
+} XawSeparatorType;
+
+
+#define XawSingle_Line "singleline"
+#define XawDouble_Line "doubleline"
+#define XawShadow_Etched_In "shadowetchedin"
+#define XawShadow_Etched_Out "shadowetchedout"
+
+
+
+#ifndef XtNmargin
+#define XtNmargin "margin"
+#endif
+
+#ifndef XtCMargin
+#define XtCMargin "Margin"
+#endif
+
+#ifndef XtNseparatorType
+#define XtNseparatorType "separatorType"
+#endif
+
+#ifndef XtCSeparatorType
+#define XtCSeparatorType "SeparatorType"
+#endif
+
+#ifndef XtRSeparatorType
+#define XtRSeparatorType "SeparatorType"
+#endif
+
+#define XawTextEncoding8bit 0
+#define XawTextEncodingChar2b 1
+
+#define XtNleftBitmap "leftBitmap"
+#define XtCLeftBitmap "LeftBitmap"
+#define XtNencoding "encoding"
+#define XtCEncoding "Encoding"
+
+#ifndef _XtStringDefs_h_
+#define XtNbitmap "bitmap"
+#define XtNforeground "foreground"
+#define XtNseparator "separator"
+#define XtNfont "font"
+#define XtNinternalWidth "internalWidth"
+#define XtNinternalHeight "internalHeight"
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#define XtCBitmap "Bitmap"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass separatorWidgetClass;
+
+typedef struct _SeparatorClassRec *SeparatorWidgetClass;
+typedef struct _SeparatorRec *SeparatorWidget;
+
+#endif /* _XawSeparator_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/SeparatorP.h b/vendor/x11iraf/obm/ObmW/SeparatorP.h
new file mode 100644
index 00000000..35aa3bae
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/SeparatorP.h
@@ -0,0 +1,62 @@
+/*
+ * SeparatorP.h - Private definitions for Separator widget
+ *
+ */
+
+#ifndef _XawSeparatorP_h
+#define _XawSeparatorP_h
+
+/***********************************************************************
+ *
+ * Separator Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xmu/Converters.h>
+
+#include "XrawInit.h"
+#include "Separator.h"
+
+
+/* New fields for the Separator widget class record */
+
+typedef struct {int foo;} SeparatorClassPart;
+
+/* Full class record declaration */
+typedef struct _SeparatorClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ SeparatorClassPart separator_class;
+} SeparatorClassRec;
+
+extern SeparatorClassRec separatorClassRec;
+
+/* New fields for the Separator widget record */
+
+typedef struct {
+
+ /* Public Resources */
+ XtOrientation orientation;
+ Dimension margin;
+ XawSeparatorType separatorType;
+
+ /* Private part */
+ GC gc;
+
+} SeparatorPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SeparatorRec {
+ CorePart core;
+ SimplePart simple;
+#include <X11/Xaw3d/Simple.h>
+ SeparatorPart separator;
+} SeparatorRec;
+
+#endif /* _XawSeparatorP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Simple.c b/vendor/x11iraf/obm/ObmW/Simple.c
new file mode 100644
index 00000000..83797833
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Simple.c
@@ -0,0 +1,489 @@
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Drawing.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/ContainerP.h>
+
+#define UnspecifiedPixmap (Pixmap)2
+#define UndefinedGC (GC)2
+
+static void InsPixel();
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(SimpleWidget, simple.field)
+ {
+ XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNinsensitiveBorder, XtCInsensitive, XtRPixmap, sizeof(Pixmap),
+ offset(insensitive_border), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(foreground), XtRImmediate, (XtPointer) XtDefaultForeground
+ },
+ {
+ "top.gc", "Top.gc", XtRString, sizeof(String),
+ offset(top_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "bottom.gc", "Bottom.gc", XtRString, sizeof(String),
+ offset(bottom_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "highlight.gc", "Highlight.gc", XtRString, sizeof(String),
+ offset(highlight_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(shadow_thickness), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNtopShadowPixmap, XtCTopShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(top_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(top_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNbottomShadowPixmap, XtCBottomShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(bottom_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(bottom_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNhighlightPixmap, XtCHighlightPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(highlight_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNhighlightPixel, XtCHighlightPixel, XtRPixel, sizeof(Pixel),
+ offset(highlight_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNhighlightThickness, XtCHighlightThickness, XtRDimension,
+ sizeof(Dimension),
+ offset(highlight_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNuserData, XtCUserData, XtRPixmap, sizeof(Pixmap),
+ offset(user_data), XtRImmediate, (XtPointer) NULL
+ },
+ {
+ XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0
+ }
+
+};
+
+static void InsPixel(w, off, value)
+ Widget w;
+ int off;
+ XrmValue *value;
+{
+ register SimpleWidget p = (SimpleWidget) w;
+ static Pixel pixel;
+
+ if (off == offset(top_shadow_color))
+ {
+ p->simple.top_shadow_GC = UndefinedGC;
+ }
+ else if (off == offset(bottom_shadow_color))
+ {
+ p->simple.bottom_shadow_GC = UndefinedGC;
+ }
+ else
+ {
+ p->simple.highlight_GC = UndefinedGC;
+ }
+ value->addr = (XtPointer) &pixel;
+}
+
+#undef offset
+
+static void ClasstInitialize();
+static void ClassPartInitialize();
+static void Initialize();
+static void Realize();
+static void Redisplay();
+static void Destroy();
+
+static Boolean SetValues();
+static Boolean DisplayRectProc();
+static Boolean ChangeSensitive();
+
+static XtGeometryResult QueryGeometry();
+
+SimpleClassRec simpleClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &widgetClassRec,
+ /* class_name */ "Simple",
+ /* widget_size */ sizeof(SimpleRec),
+ /* class_initialize */ ClasstInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ NULL,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ ChangeSensitive,
+ /* display_rect */ DisplayRectProc,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass simpleWidgetClass = (WidgetClass)&simpleClassRec;
+
+static void ClasstInitialize()
+{
+/* EMPTY */
+}
+
+static void ClassPartInitialize(class)
+ WidgetClass class;
+{
+ register SimpleWidgetClass c = (SimpleWidgetClass)class;
+
+ if (c->simple_class.change_sensitive == NULL)
+ {
+ char buf[BUFSIZ];
+
+ sprintf(buf,
+ "%s Widget: The Simple Widget class method 'change_sensitive' is undefined.\nA function must be defined or inherited.",
+ c->core_class.class_name);
+ XtWarning(buf);
+ c->simple_class.change_sensitive = ChangeSensitive;
+ }
+
+ if (c->simple_class.change_sensitive == XtInheritChangeSensitive)
+ c->simple_class.change_sensitive = ChangeSensitive;
+
+ if (c->simple_class.display_rect == XtInheritDisplayRectProc)
+ c->simple_class.display_rect = DisplayRectProc;
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SimpleWidget sw = (SimpleWidget)new;
+ SimplePart* sp = (SimplePart*)&(sw->simple);
+
+ if (sp->top_shadow_pixmap == UnspecifiedPixmap)
+ sp->top_shadow_pixmap = None;
+
+ if (sp->top_shadow_GC == NULL){
+ if (sp->top_shadow_pixmap != None)
+ sp->top_shadow_GC = AllocGCFromPixmap (new, sp->top_shadow_pixmap);
+ else
+ sp->top_shadow_GC = AllocGCFromPixel (new, sp->top_shadow_color);
+ } else if (sp->top_shadow_GC == UndefinedGC)
+ sp->top_shadow_GC = MakeTopShadowGC (new, new->core.background_pixel);
+
+
+ if (sp->bottom_shadow_pixmap == UnspecifiedPixmap)
+ sp->bottom_shadow_pixmap = None;
+
+ if (sp->bottom_shadow_GC == NULL){
+ if (sp->bottom_shadow_pixmap != None)
+ sp->bottom_shadow_GC = AllocGCFromPixmap (new, sp->bottom_shadow_pixmap);
+ else
+ sp->bottom_shadow_GC = AllocGCFromPixel (new, sp->bottom_shadow_color);
+ } else if (sp->bottom_shadow_GC == UndefinedGC)
+ sp->bottom_shadow_GC =MakeBottomShadowGC (new, new->core.background_pixel);
+
+
+ if (sp->highlight_pixmap == UnspecifiedPixmap)
+ sp->highlight_pixmap = None;
+
+ if (sp->highlight_GC == NULL){
+ if (sp->highlight_pixmap != None)
+ sp->highlight_GC = AllocGCFromPixmap (new, sp->highlight_pixmap);
+ else
+ sp->highlight_GC = AllocGCFromPixel (new, sp->highlight_color);
+ } else if (sp->highlight_GC == UndefinedGC)
+ sp->highlight_GC = MakeBottomShadowGC (new, new->core.background_pixel);
+
+}
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ Mask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ Pixmap border_pixmap;
+
+ if (!XtIsSensitive(w))
+ {
+ /* change border to gray; have to remember the old one,
+ * so XtDestroyWidget deletes the proper one */
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ border_pixmap = w->core.border_pixmap;
+ attributes->border_pixmap =
+ w->core.border_pixmap = ((SimpleWidget)w)->simple.insensitive_border;
+
+ *valueMask |= CWBorderPixmap;
+ *valueMask &= ~CWBorderPixel;
+ }
+
+ if ((attributes->cursor = ((SimpleWidget)w)->simple.cursor) != None)
+ *valueMask |= CWCursor;
+
+ XtCreateWindow( w, (unsigned int)InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attributes );
+
+ if (!XtIsSensitive(w))
+ w->core.border_pixmap = border_pixmap;
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SimpleWidget s_old = (SimpleWidget) current;
+ SimpleWidget s_new = (SimpleWidget) new;
+ SimplePart* sp = (SimplePart*)&(s_new->simple);
+ Boolean redraw = False;
+
+#define NE(field) (s_new->simple.field != s_old->simple.field)
+
+ if ( XtIsSensitive(current) != XtIsSensitive(new) )
+ (*((SimpleWidgetClass)XtClass(new))->
+ simple_class.change_sensitive) ( new );
+
+ if ( NE(cursor) && XtIsRealized(new))
+ XDefineCursor(XtDisplay(new), XtWindow(new), s_new->simple.cursor);
+
+ if (NE(top_shadow_pixmap))
+ {
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixmap (new, sp->top_shadow_pixmap);
+ redraw = True;
+ }
+ else if (NE(top_shadow_color) && sp->top_shadow_pixmap == None)
+ {
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixel (new, sp->top_shadow_color);
+ redraw = True;
+ }
+
+ if (NE(bottom_shadow_pixmap))
+ {
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixmap (new, sp->bottom_shadow_pixmap);
+ redraw = True;
+ }
+ else if (NE(bottom_shadow_color) && sp->bottom_shadow_pixmap == None)
+ {
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixel (new, sp->bottom_shadow_color);
+ redraw = True;
+ }
+
+ if (NE(highlight_pixmap))
+ {
+ XtReleaseGC (new, sp->highlight_GC);
+ sp->highlight_GC = AllocGCFromPixmap (new, sp->highlight_pixmap);
+ redraw = True;
+ }
+ else if (NE(highlight_color) && sp->highlight_pixmap)
+ {
+ XtReleaseGC (new, sp->highlight_GC);
+ sp->highlight_GC = AllocGCFromPixel (new, sp->highlight_color);
+ redraw = True;
+ }
+
+#undef NE
+
+ return redraw;
+}
+
+
+static void Unhighlight (gw)
+ Widget gw;
+{
+ register Dimension thick = ((SimpleWidget)gw)->simple.highlight_thickness;
+ register Dimension width = gw->core.width;
+ register Dimension height = gw->core.height;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ if ( XtIsSubclass(XtParent(gw), containerWidgetClass))
+ {
+ XRectangle rectangles[4];
+ GC gc = ((ContainerWidget) XtParent(gw))->container.background_GC;
+
+#define SET_RECTANGLE(I,X,Y,W,H) \
+ rectangles[I].x = X; rectangles[I].y = Y; \
+ rectangles[I].width = W; rectangles[I].height = H
+
+ SET_RECTANGLE(0, 0, 0, thick, height);
+ SET_RECTANGLE(1, 0, height - thick, width, thick);
+ SET_RECTANGLE(2, 0, 0, width, thick);
+ SET_RECTANGLE(3, width - thick, 0, thick, height);
+
+ XFillRectangles (XtDisplay(gw), XtWindow(gw), gc, rectangles, 4);
+
+ }
+ else
+ {
+ Display *dpy = XtDisplay(gw);
+ Window win = XtWindow(gw);
+
+ XClearArea( dpy, win, 0, 0, thick, height, False);
+ XClearArea( dpy, win, 0, height - thick, width, thick, False);
+ XClearArea( dpy, win, 0, 0, width, thick, False);
+ XClearArea( dpy, win, width - thick, 0, thick, height, False);
+ }
+}
+
+
+/* ARGSUSED */
+static void Redisplay( gw, event, region )
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register SimpleWidget s = (SimpleWidget)gw;
+
+ if (XtIsRealized(gw))
+ {
+ Unhighlight (gw);
+
+ if (s->simple.shadow_thickness)
+ XawDrawFrame (gw,
+ s->simple.highlight_thickness,
+ s->simple.highlight_thickness,
+ s->core.width - 2 * s->simple.highlight_thickness,
+ s->core.height - 2 * s->simple.highlight_thickness,
+ XawRAISED,
+ s->simple.shadow_thickness,
+ s->simple.top_shadow_GC,
+ s->simple.bottom_shadow_GC);
+ }
+}
+
+static void Destroy(w)
+ Widget w;
+{
+ register SimpleWidget s = (SimpleWidget)w;
+
+ XtReleaseGC(w, s->simple.top_shadow_GC);
+ XtReleaseGC(w, s->simple.bottom_shadow_GC);
+}
+
+static Boolean DisplayRectProc (w, rect)
+ Widget w;
+ XRectangle *rect;
+{
+ register SimpleWidget s = (SimpleWidget)w;
+
+ rect->x =
+ rect->y = s->simple.highlight_thickness + s->simple.shadow_thickness;
+ rect->width = s->core.width - 2 * rect->x;
+ rect->height = s->core.height - 2 * rect->y;
+
+ return True;
+}
+
+
+static XtGeometryResult QueryGeometry(w, intended, preferred)
+ Widget w;
+ XtWidgetGeometry *intended, *preferred;
+{
+ register SimpleWidget sw = (SimpleWidget)w;
+
+
+ preferred->request_mode = CWWidth | CWHeight;
+
+ preferred->width = preferred->height = 2 * SIMPLE_MARGIN(sw) + 1;
+
+#define WIDTH_HEIGHT (CWWidth | CWHeight)
+
+ if (intended
+ && ((intended->request_mode & WIDTH_HEIGHT) == WIDTH_HEIGHT)
+ && intended->width == preferred->width
+ && intended->height == preferred->height)
+ {
+ return XtGeometryYes;
+ }
+ else if (preferred->width == w->core.width
+ && preferred->height == w->core.height)
+ {
+ return XtGeometryNo;
+ }
+ else
+ {
+ return XtGeometryAlmost;
+ }
+}
+
+
+static Boolean ChangeSensitive(w)
+ register Widget w;
+{
+ if (XtIsRealized(w)) {
+ if (XtIsSensitive(w))
+ if (w->core.border_pixmap != UnspecifiedPixmap)
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ w->core.border_pixmap );
+ else
+ XSetWindowBorder( XtDisplay(w), XtWindow(w),
+ w->core.border_pixel );
+ else {
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ ((SimpleWidget)w)->
+ simple.insensitive_border );
+ }
+ }
+ return False;
+}
diff --git a/vendor/x11iraf/obm/ObmW/SimpleMenu.c b/vendor/x11iraf/obm/ObmW/SimpleMenu.c
new file mode 100644
index 00000000..eeade452
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/SimpleMenu.c
@@ -0,0 +1,1467 @@
+/* $XConsortium: SimpleMenu.c,v 1.32 89/12/11 15:01:50 kit Exp $ */
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * SimpleMenu.c - Source code file for SimpleMenu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ * --------------------------------
+ *
+ * Date: Jul 4, 1995
+ *
+ * Changes: Vladimir T. Romanovski
+ * romsky@hp1.oea.ihep.su // IHEP (Russia)
+ * romsky@munin.ucsf.edu // University of California San Francisco
+ *
+ */
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleMenP.h>
+#include <X11/Xraw/SmeBSB.h>
+#include <X11/Xraw/Cardinals.h>
+#include <X11/Xraw/SmeLineP.h>
+
+#include <X11/Xmu/Initer.h>
+#include <X11/Xmu/CharSet.h>
+
+#define CORE(w) (w)->core
+
+#define ForAllChildren(smw, childP) \
+ for ( (childP) = (SmeObject *) (smw)->composite.children ; \
+ (childP) < (SmeObject *) ((smw)->composite.children + \
+ (smw)->composite.num_children ) ; \
+ (childP)++ )
+
+
+#define UnspecifiedPixmap (Pixmap)2
+#define UndefinedGC (GC)2
+
+static void InsPixel();
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(SimpleMenuWidget, simple_menu.field)
+ {
+ "top.gc", "Top.gc", XtRString, sizeof(String),
+ offset(top_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "bottom.gc", "Bottom.gc", XtRString, sizeof(String),
+ offset(bottom_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(shadow_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNbsbShadowWidth, XtCBsbShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(bsb_shadow_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNtopShadowPixmap, XtCTopShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(top_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(top_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNbottomShadowPixmap, XtCBottomShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(bottom_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(bottom_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNuserData, XtCUserData, XtRPixmap, sizeof(Pixmap),
+ offset(user_data), XtRImmediate, (XtPointer) NULL
+ },
+ {
+ XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNframeType, XtCFrameType, XtRFrameType, sizeof(XawFrameType),
+ offset(frame_type), XtRImmediate, (XtPointer) XawRAISED
+ },
+
+/*
+ * Label Resources.
+ */
+
+ {
+ XtNlabel, XtCLabel, XtRString, sizeof(String),
+ offset(label_string), XtRString, NULL
+ },
+ {
+ XtNlabelClass, XtCLabelClass, XtRPointer, sizeof(WidgetClass),
+ offset(label_class), XtRImmediate, (XtPointer) NULL
+ },
+
+/*
+ * Layout Resources.
+ */
+
+ {
+ XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
+ offset(row_height), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(top_margin), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(bottom_margin), XtRImmediate, (XtPointer) 0
+ },
+
+/*
+ * Misc. Resources
+ */
+
+ {
+ XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
+ XtOffset(SimpleMenuWidget, shell.allow_shell_resize),
+ XtRImmediate, (XtPointer) TRUE
+ },
+ {
+ XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
+ offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE
+ },
+ {
+ XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
+ offset(popup_entry), XtRWidget, NULL
+ },
+ {
+ XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
+ offset(backing_store), XtRImmediate,
+ (XtPointer) (Always + WhenMapped + NotUseful)
+ }
+};
+
+static void InsPixel(w, off, value)
+ Widget w;
+ int off;
+ XrmValue *value;
+{
+ register SimpleMenuWidget p = (SimpleMenuWidget) w;
+ static Pixel pixel;
+
+ if (off == offset(top_shadow_color))
+ {
+ p->simple_menu.top_shadow_GC = UndefinedGC;
+ }
+ else if (off == offset(bottom_shadow_color))
+ {
+ p->simple_menu.bottom_shadow_GC = UndefinedGC;
+ }
+ value->addr = (XtPointer) &pixel;
+}
+
+#undef offset
+
+static char defaultTranslations[] =
+ "<EnterWindow>: highlight() \n\
+ <LeaveWindow>: unhighlight() \n\
+ <BtnMotion>: highlight() \n\
+ <BtnUp>: MenuPopdown() notify() unhighlight()";
+
+/*
+ * Semi Public function definitions.
+ */
+
+static void Redisplay(), Realize(), Resize(), ChangeManaged();
+static void Initialize(), ClassInitialize(), ClassPartInitialize();
+static Boolean SetValues(), SetValuesHook();
+static XtGeometryResult GeometryManager();
+
+/*
+ * Action Routine Definitions
+ */
+
+static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
+
+/*
+ * Private Function Definitions.
+ */
+
+static void MakeSetValuesRequest(), CreateLabel(), Layout();
+static void AddPositionAction(), PositionMenu();
+static Dimension GetMenuWidth(), GetMenuHeight();
+static Widget FindMenu();
+static SmeObject GetEventEntry();
+
+static XtActionsRec actionsList[] =
+{
+ {"notify", Notify},
+ {"highlight", Highlight},
+ {"unhighlight", Unhighlight}
+};
+
+CompositeClassExtensionRec extension_rec = {
+ /* next_extension */ NULL,
+ /* record_type */ NULLQUARK,
+ /* version */ XtCompositeExtensionVersion,
+ /* record_size */ sizeof(CompositeClassExtensionRec),
+ /* accepts_objects */ TRUE,
+};
+
+#define superclass (&overrideShellClassRec)
+
+SimpleMenuClassRec simpleMenuClassRec = {
+ {
+ /* superclass */ (WidgetClass) superclass,
+ /* class_name */ "SimpleMenu",
+ /* size */ sizeof(SimpleMenuRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize*/ ClassPartInitialize,
+ /* Class init'ed */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actionsList,
+ /* num_actions */ XtNumber(actionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ False,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ SetValuesHook,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* intrinsics version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ NULL,
+ /* display_accelerator*/ NULL,
+ /* extension */ NULL
+ },{
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ },{
+ /* Shell extension */ NULL
+ },{
+ /* Override extension */ NULL
+ },{
+ /* Simple Menu extension*/ NULL
+ }
+};
+
+WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
+
+/************************************************************
+ *
+ * Semi-Public Functions.
+ *
+ ************************************************************/
+#define done(type, value) \
+ { \
+ if (to->addr != NULL) { \
+ if (to->size < sizeof(type)) { \
+ to->size = sizeof(type); \
+ return False; \
+ } \
+ *(type*)(to->addr) = (value); \
+ } else { \
+ static type static_val; \
+ static_val = (value); \
+ to->addr = (XtPointer)&static_val; \
+ } \
+ to->size = sizeof(type); \
+ return True; \
+ }
+
+
+/* ARGSUSED */
+static Boolean
+cvtStringToFrameType ( display, args, num_args, from, to, converter_data)
+ Display *display;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr from;
+ XrmValuePtr to;
+ XtPointer *converter_data;
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToFrameType", "wrongParameters",
+ "XtToolkitError",
+ "String to frame type conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "raised") == 0) done(XawFrameType, XawRAISED);
+ if (XmuCompareISOLatin1(s, "sunken") == 0) done(XawFrameType, XawSUNKEN);
+ if (XmuCompareISOLatin1(s, "chiseled") == 0) done(XawFrameType, XawCHISELED);
+ if (XmuCompareISOLatin1(s, "ledged") == 0) done(XawFrameType, XawLEDGED);
+ if (XmuCompareISOLatin1(s, "tack") == 0) done(XawFrameType, XawTACK);
+
+ XtDisplayStringConversionWarning(display, s, XtRFrameType);
+ printf("SimpleMenu.c");
+
+ done(XawFrameType, XawRAISED);
+}
+
+/* Function Name: ClassInitialize
+ * Description: Class Initialize routine, called only once.
+ * Arguments: none.
+ * Returns: none.
+ */
+
+static void
+ClassInitialize()
+{
+ XawInitializeWidgetSet();
+ XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0 );
+ XmuAddInitializer( AddPositionAction, NULL);
+
+ XtSetTypeConverter(XtRString, XtRFrameType, cvtStringToFrameType,
+ NULL, 0, XtCacheNone, NULL);
+}
+
+/* Function Name: ClassPartInitialize
+ * Description: Class Part Initialize routine, called for every
+ * subclass. Makes sure that the subclasses pick up
+ * the extension record.
+ * Arguments: wc - the widget class of the subclass.
+ * Returns: none.
+ */
+
+static void
+ClassPartInitialize(wc)
+WidgetClass wc;
+{
+ SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
+
+/*
+ * Make sure that our subclass gets the extension rec too.
+ */
+
+ extension_rec.next_extension = smwc->composite_class.extension;
+ smwc->composite_class.extension = (XtPointer) &extension_rec;
+}
+
+/* Function Name: Initialize
+ * Description: Initializes the simple menu widget
+ * Arguments: request - the widget requested by the argument list.
+ * new - the new widget with both resource and non
+ * resource values.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+Initialize(request, new)
+Widget request, new;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) new;
+ register SimpleMenuPart* smwp = (SimpleMenuPart*)&smw->simple_menu;
+
+ XmuCallInitializers(XtWidgetToApplicationContext(new));
+
+ if (smwp->label_class == NULL)
+ smwp->label_class = smeBSBObjectClass;
+
+ smwp->label = NULL;
+ smwp->entry_set = NULL;
+ smwp->recursive_set_values = False;
+
+ if (smwp->label_string != NULL)
+ CreateLabel(new);
+
+ smwp->menu_width = TRUE;
+
+ if (smw->core.width == 0)
+ {
+ smwp->menu_width = False;
+ smw->core.width = GetMenuWidth(new, NULL);
+ }
+
+ smwp->menu_height = TRUE;
+
+ if (smw->core.height == 0)
+ {
+ smwp->menu_height = False;
+ smw->core.height = GetMenuHeight(new);
+ }
+
+
+ /*
+ * Top & Bottom Shadow GCs
+ */
+
+ if (smwp->top_shadow_pixmap == UnspecifiedPixmap)
+ smwp->top_shadow_pixmap = None;
+
+ if (smwp->top_shadow_GC == NULL){
+ if (smwp->top_shadow_pixmap != None)
+ smwp->top_shadow_GC = AllocGCFromPixmap (new, smwp->top_shadow_pixmap);
+ else
+ smwp->top_shadow_GC = AllocGCFromPixel (new, smwp->top_shadow_color);
+ } else if (smwp->top_shadow_GC == UndefinedGC)
+ smwp->top_shadow_GC = MakeTopShadowGC (new, new->core.background_pixel);
+
+
+ if (smwp->bottom_shadow_pixmap == UnspecifiedPixmap)
+ smwp->bottom_shadow_pixmap = None;
+
+ if (smwp->bottom_shadow_GC == NULL){
+ if (smwp->bottom_shadow_pixmap != None)
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixmap (new, smwp->bottom_shadow_pixmap);
+ else
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixel (new, smwp->bottom_shadow_color);
+ } else if (smwp->bottom_shadow_GC == UndefinedGC)
+ smwp->bottom_shadow_GC =
+ MakeBottomShadowGC (new, new->core.background_pixel);
+}
+
+/* Function Name: Redisplay
+ * Description: Redisplays the contents of the widget.
+ * Arguments: w - the simple menu widget.
+ * event - the X event that caused this redisplay.
+ * region - the region the needs to be repainted.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void Redisplay(w, event, region)
+ Widget w;
+ XEvent * event;
+ Region region;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+ SmeObjectClass class;
+
+ if (region == NULL)
+ XClearWindow(XtDisplay(w), XtWindow(w));
+
+ /*
+ * Check and Paint each of the entries
+ */
+
+ ForAllChildren(smw, entry)
+ if (XtIsManaged ((Widget)*entry))
+ {
+ class = (SmeObjectClass) (*entry)->object.widget_class;
+
+ if (class->rect_class.expose)
+ (*class->rect_class.expose) ((Widget)*entry, NULL, region);
+ }
+
+ XawDrawFrame(w,
+ 0, 0, CORE(w).width, CORE(w).height,
+ SMW(w).frame_type,
+ SMW(w).shadow_thickness,
+ SMW(w).top_shadow_GC,
+ SMW(w).bottom_shadow_GC);
+
+}
+
+/* Function Name: Realize
+ * Description: Realizes the widget.
+ * Arguments: w - the simple menu widget.
+ * mask - value mask for the window to create.
+ * attrs - attributes for the window to create.
+ * Returns: none
+ */
+
+static void
+Realize(w, mask, attrs)
+Widget w;
+XtValueMask * mask;
+XSetWindowAttributes * attrs;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ attrs->cursor = smw->simple_menu.cursor;
+ *mask |= CWCursor;
+ if ((smw->simple_menu.backing_store == Always) ||
+ (smw->simple_menu.backing_store == NotUseful) ||
+ (smw->simple_menu.backing_store == WhenMapped) ) {
+ *mask |= CWBackingStore;
+ attrs->backing_store = smw->simple_menu.backing_store;
+ }
+ else
+ *mask &= ~CWBackingStore;
+
+ *mask |= CWSaveUnder;
+ attrs->save_under = True;
+
+ (*superclass->core_class.realize) (w, mask, attrs);
+}
+
+/* Function Name: Resize
+ * Description: Handle the menu being resized bigger.
+ * Arguments: w - the simple menu widget.
+ * Returns: none.
+ */
+
+static void Resize(w)
+ Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+
+ if ( !XtIsRealized(w) ) return;
+
+ ForAllChildren(smw, entry) /* reset width of all entries. */
+ if (XtIsManaged( (Widget) *entry)) {
+ (*entry)->rectangle.width = smw->core.width -
+ 2 * SMW(w).shadow_thickness;
+ (*entry)->rectangle.x = SMW(w).shadow_thickness;
+ }
+
+ XClearWindow(XtDisplay(w), XtWindow(w));
+
+ Redisplay(w, (XEvent *) NULL, (Region) NULL);
+
+}
+
+/* Function Name: SetValues
+ * Description: Relayout the menu when one of the resources is changed.
+ * Arguments: current - current state of the widget.
+ * request - what was requested.
+ * new - what the widget will become.
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new)
+ Widget current;
+ Widget request;
+ Widget new;
+{
+ SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
+ SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
+ register SimpleMenuPart* smwp = (SimpleMenuPart*)&smw_new->simple_menu;
+ Boolean ret_val = False;
+ Boolean layout = False;
+ Boolean redisplay = False;
+
+#define NE(name) (smw_old->simple_menu.name != smw_new->simple_menu.name)
+
+ if (!XtIsRealized(current))
+ return False;
+
+ if (!smw_new->simple_menu.recursive_set_values)
+ {
+ if (smw_new->core.width != smw_old->core.width)
+ {
+ smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
+ layout = TRUE;
+ }
+ if (smw_new->core.height != smw_old->core.height)
+ {
+ smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
+ layout = TRUE;
+ }
+ }
+
+ if (NE(cursor))
+ XDefineCursor(XtDisplay(new),
+ XtWindow(new), smw_new->simple_menu.cursor);
+
+ if (NE(label_string))
+ if (smw_new->simple_menu.label_string == NULL) /* Destroy. */
+ XtDestroyWidget((Widget)smw_old->simple_menu.label);
+ else if (smw_old->simple_menu.label_string == NULL) /* Create. */
+ CreateLabel(new);
+ else /* Change. */
+ XtVaSetValues((Widget)smw_new->simple_menu.label,
+ XtNlabel, smw_new->simple_menu.label_string,
+ NULL);
+
+ if (NE(label_class))
+ XtAppWarning(XtWidgetToApplicationContext(new),
+ "No Dynamic class change of the SimpleMenu Label.");
+
+ if (NE(top_margin) || NE(bottom_margin)) /* filler................. */
+ {
+ layout = TRUE;
+ ret_val = TRUE;
+ }
+
+ if (layout)
+ Layout(new, NULL, NULL);
+ {
+
+ if ( NE(shadow_thickness) )
+ redisplay = TRUE;
+
+ if (NE(top_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->top_shadow_GC);
+ smwp->top_shadow_GC = AllocGCFromPixmap (new, smwp->top_shadow_pixmap);
+ redisplay = True;
+
+ }
+ else if (NE(top_shadow_color && smwp->top_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->top_shadow_GC);
+ smwp->top_shadow_GC = AllocGCFromPixel (new, smwp->top_shadow_color);
+ redisplay = True;
+
+ }
+
+ if (NE(bottom_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->bottom_shadow_GC);
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixmap (new, smwp->bottom_shadow_pixmap);
+
+ redisplay = True;
+
+ }
+ else if (NE(bottom_shadow_color && smwp->bottom_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->bottom_shadow_GC);
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixel (new, smwp->bottom_shadow_color);
+ redisplay = True;
+
+ }
+
+#undef NE
+ }
+
+ return(ret_val || redisplay);
+}
+
+/* Function Name: SetValuesHook
+ * Description: To handle a special case, this is passed the
+ * actual arguments.
+ * Arguments: w - the menu widget.
+ * arglist - the argument list passed to XtSetValues.
+ * num_args - the number of args.
+ * Returns: none
+ */
+
+/*
+ * If the user actually passed a width and height to the widget
+ * then this MUST be used, rather than our newly calculated width and
+ * height.
+ */
+
+static Boolean
+SetValuesHook(w, arglist, num_args)
+Widget w;
+ArgList arglist;
+Cardinal *num_args;
+{
+ register Cardinal i;
+ Dimension width, height;
+
+ width = w->core.width;
+ height = w->core.height;
+
+ for ( i = 0 ; i < *num_args ; i++) {
+ if ( streq(arglist[i].name, XtNwidth) )
+ width = (Dimension) arglist[i].value;
+ if ( streq(arglist[i].name, XtNheight) )
+ height = (Dimension) arglist[i].value;
+ }
+
+ if ((width != w->core.width) || (height != w->core.height))
+ MakeSetValuesRequest(w, width, height);
+ return(False);
+}
+
+/************************************************************
+ *
+ * Geometry Management routines.
+ *
+ ************************************************************/
+
+/* Function Name: GeometryManager
+ * Description: This is the SimpleMenu Widget's Geometry Manager.
+ * Arguments: w - the Menu Entry making the request.
+ * request - requested new geometry.
+ * reply - the allowed geometry.
+ * Returns: XtGeometry{Yes, No, Almost}.
+ */
+
+static XtGeometryResult
+GeometryManager(w, request, reply)
+Widget w;
+XtWidgetGeometry * request, * reply;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
+ SmeObject entry = (SmeObject) w;
+ XtGeometryMask mode = request->request_mode;
+ XtGeometryResult answer;
+ Dimension old_height, old_width;
+
+ if ( !(mode & CWWidth) && !(mode & CWHeight) )
+ return(XtGeometryNo);
+
+ reply->width = request->width;
+ reply->height = request->height;
+
+ old_width = entry->rectangle.width;
+ old_height = entry->rectangle.height;
+
+ Layout(w, &(reply->width), &(reply->height) );
+
+/*
+ * Since we are an override shell and have no parent there is no one to
+ * ask to see if this geom change is okay, so I am just going to assume
+ * we can do whatever we want. If you subclass be very careful with this
+ * assumption, it could bite you.
+ *
+ * Chris D. Peterson - Sept. 1989.
+ */
+
+ if ( (reply->width == request->width) &&
+ (reply->height == request->height) ) {
+
+ if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
+ entry->rectangle.width = old_width;
+ entry->rectangle.height = old_height;
+ }
+ else {
+ Layout(( Widget) smw, NULL, NULL);
+ }
+ answer = XtGeometryDone;
+ }
+ else {
+ entry->rectangle.width = old_width;
+ entry->rectangle.height = old_height;
+
+ if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
+ ((reply->height == request->height) && !(mode & CWWidth)) ||
+ ((reply->width == request->width) &&
+ (reply->height == request->height)) )
+ answer = XtGeometryNo;
+ else {
+ answer = XtGeometryAlmost;
+ reply->request_mode = 0;
+ if (reply->width != request->width)
+ reply->request_mode |= CWWidth;
+ if (reply->height != request->height)
+ reply->request_mode |= CWHeight;
+ }
+ }
+ return(answer);
+}
+
+/* Function Name: ChangeManaged
+ * Description: called whenever a new child is managed.
+ * Arguments: w - the simple menu widget.
+ * Returns: none.
+ */
+
+static void
+ChangeManaged(w)
+Widget w;
+{
+ Layout(w, NULL, NULL);
+}
+
+/************************************************************
+ *
+ * Global Action Routines.
+ *
+ * These actions routines will be added to the application's
+ * global action list.
+ *
+ ************************************************************/
+
+/* Function Name: PositionMenuAction
+ * Description: Positions the simple menu widget.
+ * Arguments: w - a widget (no the simple menu widget.)
+ * event - the event that caused this action.
+ * params, num_params - parameters passed to the routine.
+ * we expect the name of the menu here.
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+PositionMenuAction(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ Widget menu;
+ XPoint loc;
+
+ if (*num_params != 1) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s %s",
+ "Xaw - SimpleMenuWidget: position menu action expects only one",
+ "parameter which is the name of the menu.");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ if ( (menu = FindMenu(w, params[0])) == NULL) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s '%s'",
+ "Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ loc.x = event->xbutton.x_root;
+ loc.y = event->xbutton.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ loc.x = event->xcrossing.x_root;
+ loc.y = event->xcrossing.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ case MotionNotify:
+ loc.x = event->xmotion.x_root;
+ loc.y = event->xmotion.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ default:
+ PositionMenu(menu, NULL);
+ break;
+ }
+}
+
+/************************************************************
+ *
+ * Widget Action Routines.
+ *
+ ************************************************************/
+
+/* Function Name: Unhighlight
+ * Description: Unhighlights current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Unhighlight(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry = smw->simple_menu.entry_set;
+ SmeObjectClass class;
+
+ if ( entry == NULL) return;
+
+ smw->simple_menu.entry_set = NULL;
+ class = (SmeObjectClass) entry->object.widget_class;
+ (class->sme_class.unhighlight) ( (Widget) entry);
+}
+
+/* Function Name: Highlight
+ * Description: Highlights current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Highlight(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry;
+ SmeObjectClass class;
+
+ if ( !XtIsSensitive(w) ) return;
+
+ entry = GetEventEntry(w, event);
+
+ if (entry == smw->simple_menu.entry_set) return;
+
+ Unhighlight(w, event, params, num_params);
+
+ if (entry == NULL) return;
+
+ if ( !XtIsSensitive( (Widget) entry)) {
+ smw->simple_menu.entry_set = NULL;
+ return;
+ }
+
+ smw->simple_menu.entry_set = entry;
+ class = (SmeObjectClass) entry->object.widget_class;
+
+ (class->sme_class.highlight) ( (Widget) entry);
+}
+
+/* Function Name: Notify
+ * Description: Notify user of current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Notify(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry = smw->simple_menu.entry_set;
+ SmeObjectClass class;
+
+ if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
+
+ class = (SmeObjectClass) entry->object.widget_class;
+ (class->sme_class.notify)( (Widget) entry );
+}
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawSimpleMenuAddGlobalActions
+ * Description: adds the global actions to the simple menu widget.
+ * Arguments: app_con - the appcontext.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuAddGlobalActions(app_con)
+XtAppContext app_con;
+{
+ XtInitializeWidgetClass(simpleMenuWidgetClass);
+ XmuCallInitializers( app_con );
+}
+
+
+/* Function Name: XawSimpleMenuGetActiveEntry
+ * Description: Gets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: the currently set entry or NULL if none is set.
+ */
+
+Widget
+XawSimpleMenuGetActiveEntry(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ return( (Widget) smw->simple_menu.entry_set);
+}
+
+/* Function Name: XawSimpleMenuClearActiveEntry
+ * Description: Unsets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuClearActiveEntry(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ smw->simple_menu.entry_set = NULL;
+}
+
+/************************************************************
+ *
+ * Private Functions.
+ *
+ ************************************************************/
+
+/* Function Name: CreateLabel
+ * Description: Creates a the menu label.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ *
+ * Creates the label object and makes sure it is the first child in
+ * in the list.
+ */
+
+static void
+CreateLabel(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ register Widget * child, * next_child;
+ register int i;
+ Arg args[2];
+
+ if ( (smw->simple_menu.label_string == NULL) ||
+ (smw->simple_menu.label != NULL) ) {
+ char error_buf[BUFSIZ];
+
+ sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
+ "label string is NULL", "label already exists",
+ "no label is being created.");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
+ XtSetArg(args[1], XtNjustify, XtJustifyCenter);
+ smw->simple_menu.label = (SmeObject)
+ XtCreateManagedWidget("menuLabel",
+ smw->simple_menu.label_class, w,
+ args, TWO);
+
+ next_child = NULL;
+ for (child = smw->composite.children + smw->composite.num_children,
+ i = smw->composite.num_children ; i > 0 ; i--, child--) {
+ if (next_child != NULL)
+ *next_child = *child;
+ next_child = child;
+ }
+ *child = (Widget) smw->simple_menu.label;
+}
+
+/* Function Name: Layout
+ * Description: lays the menu entries out all nice and neat.
+ * Arguments: w - See below (+++)
+ * width_ret, height_ret - The returned width and
+ * height values.
+ * Returns: none.
+ *
+ * if width == NULL || height == NULL then it assumes the you do not care
+ * about the return values, and just want a relayout.
+ *
+ * if this is not the case then it will set width_ret and height_ret
+ * to be width and height that the child would get if it were layed out
+ * at this time.
+ *
+ * +++ "w" can be the simple menu widget or any of its object children.
+ */
+
+static void
+Layout(w, width_ret, height_ret)
+Widget w;
+Dimension *width_ret, *height_ret;
+{
+ SmeObject current_entry, *entry;
+ SimpleMenuWidget smw;
+ Dimension width, height;
+ Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
+ Boolean allow_change_size;
+ height = 0;
+
+ if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
+ smw = (SimpleMenuWidget) w;
+ current_entry = NULL;
+ }
+ else {
+ smw = (SimpleMenuWidget) XtParent(w);
+ current_entry = (SmeObject) w;
+ }
+
+ allow_change_size = (!XtIsRealized((Widget)smw) ||
+ (smw->shell.allow_shell_resize));
+
+ if ( smw->simple_menu.menu_height )
+ height = smw->core.height;
+ else
+ if (do_layout) {
+ height = smw->simple_menu.top_margin;
+ height += smw->simple_menu.shadow_thickness;
+ ForAllChildren(smw, entry) {
+ if (!XtIsManaged( (Widget) *entry)) continue;
+
+ if ( (smw->simple_menu.row_height != 0) &&
+ (*entry != smw->simple_menu.label) )
+ (*entry)->rectangle.height = smw->simple_menu.row_height;
+
+ (*entry)->rectangle.y = height;
+ (*entry)->rectangle.x = smw->simple_menu.shadow_thickness;
+ height += (*entry)->rectangle.height;
+ }
+ height += smw->simple_menu.bottom_margin;
+ height += smw->simple_menu.shadow_thickness;
+ }
+ else {
+ if ((smw->simple_menu.row_height != 0) &&
+ (current_entry != smw->simple_menu.label) )
+ height = smw->simple_menu.row_height;
+ }
+
+ if (smw->simple_menu.menu_width)
+ width = smw->core.width;
+ else if ( allow_change_size ){
+ width = GetMenuWidth((Widget) smw, (Widget) current_entry);
+ width +=2*smw->simple_menu.shadow_thickness;
+ }
+ else
+ width = smw->core.width;
+
+ if (do_layout) {
+ ForAllChildren(smw, entry)
+ if (XtIsManaged( (Widget) *entry))
+ (*entry)->rectangle.width = width -
+ 2*smw->simple_menu.shadow_thickness;
+
+ if (allow_change_size)
+ MakeSetValuesRequest((Widget) smw, width, height);
+ }
+ else {
+ *width_ret = width;
+ if (height != 0)
+ *height_ret = height;
+ }
+}
+
+/* Function Name: AddPositionAction
+ * Description: Adds the XawPositionSimpleMenu action to the global
+ * action list for this appcon.
+ * Arguments: app_con - the application context for this app.
+ * data - NOT USED.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+AddPositionAction(app_con, data)
+XtAppContext app_con;
+XtPointer data;
+{
+ static XtActionsRec pos_action[] = {
+ { "XawPositionSimpleMenu", PositionMenuAction },
+ };
+
+ XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
+}
+
+/* Function Name: FindMenu
+ * Description: Find the menu give a name and reference widget.
+ * Arguments: widget - reference widget.
+ * name - the menu widget's name.
+ * Returns: the menu widget or NULL.
+ */
+
+static Widget
+FindMenu(widget, name)
+Widget widget;
+String name;
+{
+ register Widget w, menu;
+
+ for ( w = widget ; w != NULL ; w = XtParent(w) )
+ if ( (menu = XtNameToWidget(w, name)) != NULL )
+ return(menu);
+ return(NULL);
+}
+
+/* Function Name: MoveMenu
+ * Description: Actually moves the menu, may force it to
+ * to be fully visable if menu_on_screen is TRUE.
+ * Arguments: w - the simple menu widget.
+ * x, y - the current location of the widget.
+ * Returns: none
+ */
+
+static void
+MoveMenu(w, x, y)
+Widget w;
+Position x, y;
+{
+ Arg arglist[2];
+ Cardinal num_args = 0;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ if (smw->simple_menu.menu_on_screen) {
+ int width = w->core.width + 2 * w->core.border_width;
+ int height = w->core.height + 2 * w->core.border_width;
+
+ if (x < 0)
+ x = 0;
+ else {
+ int scr_width = WidthOfScreen(XtScreen(w));
+ if (x + width > scr_width)
+ x = scr_width - width;
+ }
+
+ if (y < 0)
+ y = 0;
+ else {
+ int scr_height = HeightOfScreen(XtScreen(w));
+ if (y + height > scr_height)
+ y = scr_height - height;
+ }
+ }
+
+ XtSetArg(arglist[num_args], XtNx, x); num_args++;
+ XtSetArg(arglist[num_args], XtNy, y); num_args++;
+ XtSetValues(w, arglist, num_args);
+}
+
+/* Function Name: PositionMenu
+ * Description: Places the menu
+ * Arguments: w - the simple menu widget.
+ * location - a pointer the the position or NULL.
+ * Returns: none.
+ */
+
+static void
+PositionMenu(w, location)
+Widget w;
+XPoint * location;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry;
+ XPoint t_point;
+
+ if (location == NULL) {
+ Window junk1, junk2;
+ int root_x, root_y, junkX, junkY;
+ unsigned int junkM;
+
+ location = &t_point;
+ if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2,
+ &root_x, &root_y, &junkX, &junkY, &junkM) == False) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s %s", "Xaw - SimpleMenuWidget:",
+ "Could not find location of mouse pointer");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+ location->x = (short) root_x;
+ location->y = (short) root_y;
+ }
+
+ /*
+ * The width will not be correct unless it is realized.
+ */
+
+ XtRealizeWidget(w);
+
+ location->x -= (Position) w->core.width/2;
+
+ if (smw->simple_menu.popup_entry == NULL)
+ entry = smw->simple_menu.label;
+ else
+ entry = smw->simple_menu.popup_entry;
+
+ if (entry != NULL)
+ location->y -= entry->rectangle.y + entry->rectangle.height/2;
+
+ MoveMenu(w, (Position) location->x, (Position) location->y);
+}
+
+/* Function Name: MakeSetValuesRequest
+ * Description: Makes a (possibly recursive) call to SetValues,
+ * I take great pains to not go into an infinite loop.
+ * Arguments: w - the simple menu widget.
+ * width, height - the size of the ask for.
+ * Returns: none
+ */
+
+static void
+MakeSetValuesRequest(w, width, height)
+Widget w;
+Dimension width, height;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ Arg arglist[2];
+ Cardinal num_args = (Cardinal) 0;
+
+ if ( !smw->simple_menu.recursive_set_values ) {
+ if ( (smw->core.width != width) || (smw->core.height != height) ) {
+ smw->simple_menu.recursive_set_values = TRUE;
+ XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
+ XtSetArg(arglist[num_args], XtNheight, height); num_args++;
+ XtSetValues(w, arglist, num_args);
+ }
+ else if (XtIsRealized( (Widget) smw))
+ Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
+ }
+ smw->simple_menu.recursive_set_values = False;
+}
+
+/* Function Name: GetMenuWidth
+ * Description: Sets the length of the widest entry in pixels.
+ * Arguments: w - the simple menu widget.
+ * Returns: width of menu.
+ */
+
+static Dimension
+GetMenuWidth(w, w_ent)
+Widget w, w_ent;
+{
+ SmeObject cur_entry = (SmeObject) w_ent;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ Dimension width, widest = (Dimension) 0;
+ SmeObject * entry;
+
+ if ( smw->simple_menu.menu_width )
+ return(smw->core.width);
+
+ ForAllChildren(smw, entry) {
+ XtWidgetGeometry preferred;
+
+ if (!XtIsManaged( (Widget) *entry)) continue;
+
+ if (*entry != cur_entry) {
+ XtQueryGeometry((Widget)*entry, NULL, &preferred);
+
+ if (preferred.request_mode & CWWidth)
+ width = preferred.width;
+ else
+ width = (*entry)->rectangle.width;
+ }
+ else
+ width = (*entry)->rectangle.width;
+
+ if ( width > widest )
+ widest = width;
+ }
+
+ return(widest);
+}
+
+/* Function Name: GetMenuHeight
+ * Description: Sets the length of the widest entry in pixels.
+ * Arguments: w - the simple menu widget.
+ * Returns: width of menu.
+ */
+
+static Dimension
+GetMenuHeight(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+ Dimension height;
+
+ if (smw->simple_menu.menu_height)
+ return(smw->core.height);
+
+ height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
+
+ if (smw->simple_menu.row_height == 0)
+ ForAllChildren(smw, entry)
+ if (XtIsManaged ((Widget) *entry))
+ height += (*entry)->rectangle.height;
+ else
+ height += smw->simple_menu.row_height * smw->composite.num_children;
+
+ return(height);
+}
+
+/* Function Name: GetEventEntry
+ * Description: Gets an entry given an event that has X and Y coords.
+ * Arguments: w - the simple menu widget.
+ * event - the event.
+ * Returns: the entry that this point is in.
+ */
+
+static SmeObject
+GetEventEntry(w, event)
+Widget w;
+XEvent * event;
+{
+ Position x_loc, y_loc;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+
+ switch (event->type) {
+ case MotionNotify:
+ x_loc = event->xmotion.x;
+ y_loc = event->xmotion.y;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ x_loc = event->xcrossing.x;
+ y_loc = event->xcrossing.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ x_loc = event->xbutton.x;
+ y_loc = event->xbutton.y;
+ break;
+ default:
+ XtAppError(XtWidgetToApplicationContext(w),
+ "Unknown event type in GetEventEntry().");
+ break;
+ }
+
+ if ( (x_loc < 0) || (x_loc >= smw->core.width) || (y_loc < 0) ||
+ (y_loc >= smw->core.height) )
+ return(NULL);
+
+ ForAllChildren(smw, entry) {
+ if (!XtIsManaged ((Widget) *entry)) continue;
+
+ if ( ((*entry)->rectangle.y <= y_loc) &&
+ ((*entry)->rectangle.y + (*entry)->rectangle.height >= y_loc) )
+ if ( *entry == smw->simple_menu.label )
+ return(NULL); /* cannot select the label. */
+ else
+ return(*entry);
+ }
+
+ return(NULL);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Slider2.c b/vendor/x11iraf/obm/ObmW/Slider2.c
new file mode 100644
index 00000000..0e21638d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Slider2.c
@@ -0,0 +1,640 @@
+/* Generated by wbuild from "Slider2.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "stip4.bm"
+#include <stdio.h>
+#include "Slider2P.h"
+static void start(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void finish(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void drag(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"start", start},
+{"finish", finish},
+{"drag", drag},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Down>: start() \n\
+<Btn1Motion>: drag() \n\
+<Btn1Up>: finish() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void compute_thumb(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+static void compute_inside(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void move_thumb(
+#if NeedFunctionPrototypes
+Widget,int ,int ,int ,int ,int ,int
+#endif
+);
+static void compute_info(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *,float *,float *,float *,float *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void scroll_response(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+static void create_gc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_graygc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_thumbgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_thumblightgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_thumbdarkgc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void create_gc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfSlider2Widget)self)->xfwfLabel.gc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfLabel.gc);
+ values.background = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfLabel.foreground;
+ values.font = ((XfwfSlider2Widget)self)->xfwfLabel.font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ ((XfwfSlider2Widget)self)->xfwfLabel.gc = XtGetGC(self, mask, &values);
+
+ if (((XfwfSlider2Widget)self)->xfwfLabel.rv_gc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfLabel.rv_gc);
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.background = ((XfwfSlider2Widget)self)->xfwfLabel.foreground;
+ values.font = ((XfwfSlider2Widget)self)->xfwfLabel.font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ ((XfwfSlider2Widget)self)->xfwfLabel.rv_gc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_graygc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfSlider2Widget)self)->xfwfLabel.graygc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfLabel.graygc);
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ values.fill_style = FillStippled;
+ mask = GCForeground | GCStipple | GCFillStyle;
+ ((XfwfSlider2Widget)self)->xfwfLabel.graygc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_thumbgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc);
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbPixmap != NULL) {
+ mask = GCTile | GCFillStyle;
+ values.tile = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbPixmap;
+ values.fill_style = FillTiled;
+ } else {
+ mask = GCForeground;
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ }
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_thumblightgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc);
+ switch (((XfwfSlider2Widget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfFrame.topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.stipple = ((XfwfSlider2Widget)self)->xfwfFrame.topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfCommon_class.lighter_color(self, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_thumbdarkgc(self)Widget self;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc != NULL) XtReleaseGC(self, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc);
+ switch (((XfwfSlider2Widget)self)->xfwfFrame.shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = ((XfwfSlider2Widget)self)->xfwfFrame.bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = ((XfwfSlider2Widget)self)->xfwfFrame.bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen(self));
+ values.background = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen(self)) > 4
+ && ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfCommon_class.darker_color(self, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor, &values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = ((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor;
+ values.foreground = WhitePixelOfScreen(XtScreen(self));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay(self),
+ RootWindowOfScreen(XtScreen(self)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc = XtGetGC(self, mask, &values);
+}
+
+static XtResource resources[] = {
+{XtNthumbColor,XtCThumbColor,XtRPixel,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.thumbColor),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.thumbColor),XtRString,(XtPointer)XtDefaultBackground },
+{XtNthumbPixmap,XtCThumbPixmap,XtRPixmap,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.thumbPixmap),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.thumbPixmap),XtRImmediate,(XtPointer)NULL },
+{XtNminsize,XtCMinsize,XtRDimension,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.minsize),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.minsize),XtRImmediate,(XtPointer)20 },
+{XtNthumbFrameWidth,XtCThumbFrameWidth,XtRDimension,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.thumbFrameWidth),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.thumbFrameWidth),XtRImmediate,(XtPointer)2 },
+{XtNthumbFrameType,XtCThumbFrameType,XtRFrameType,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.thumbFrameType),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.thumbFrameType),XtRImmediate,(XtPointer)XfwfRaised },
+{XtNscrollCallback,XtCScrollCallback,XtRCallback,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.scrollCallback),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.scrollCallback),XtRImmediate,(XtPointer)NULL },
+{XtNscrollResponse,XtCScrollResponse,XtRXTCallbackProc,sizeof(((XfwfSlider2Rec*)NULL)->xfwfSlider2.scrollResponse),XtOffsetOf(XfwfSlider2Rec,xfwfSlider2.scrollResponse),XtRImmediate,(XtPointer)scroll_response },
+{XtNframeWidth,XtCFrameWidth,XtRDimension,sizeof(((XfwfSlider2Rec*)NULL)->xfwfFrame.frameWidth),XtOffsetOf(XfwfSlider2Rec,xfwfFrame.frameWidth),XtRImmediate,(XtPointer)2 },
+{XtNframeType,XtCFrameType,XtRFrameType,sizeof(((XfwfSlider2Rec*)NULL)->xfwfFrame.frameType),XtOffsetOf(XfwfSlider2Rec,xfwfFrame.frameType),XtRImmediate,(XtPointer)XfwfSunken },
+};
+
+XfwfSlider2ClassRec xfwfSlider2ClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfLabelClassRec,
+"Slider2d",
+sizeof(XfwfSlider2Rec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+3,
+resources,
+9,
+NULLQUARK,
+False ,
+XtExposeCompressMultiple |XtExposeGraphicsExpose ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfLabel_class part */
+XtInherit_set_label,
+},
+{ /* XfwfSlider2_class part */
+compute_thumb,
+move_thumb,
+compute_info,
+scroll_response,
+},
+};
+WidgetClass xfwfSlider2WidgetClass = (WidgetClass) &xfwfSlider2ClassRec;
+/*ARGSUSED*/
+static void start(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ Dimension w, h;
+ Position x, y;
+ XfwfScrollInfo info;
+ Boolean outside = False;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease
+ && event->type != MotionNotify)
+ XtError("The start action must be bound to a mouse event");
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &x, &y, &w, &h);
+ if (event->xbutton.x < x) { /* Left of thumb */
+ info.reason = XfwfSPageLeft;
+ info.flags = XFWF_HPOS; /* Suggest a value: */
+ info.hpos = max(0.0, ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x - ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd);
+ outside = True;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+ }
+ if (event->xbutton.x >= x + w) { /* Right of thumb */
+ info.reason = XfwfSPageRight;
+ info.flags = XFWF_HPOS; /* Suggest a value: */
+ info.hpos = min(1.0, ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x + ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd);
+ outside = True;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+ }
+ if (event->xbutton.y < y) { /* Above thumb */
+ info.reason = XfwfSPageUp;
+ info.flags = XFWF_VPOS; /* Suggest a value: */
+ info.vpos = max(0.0, ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y - ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht);
+ outside = True;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+ }
+ if (event->xbutton.y >= y + h) { /* Below thumb */
+ info.reason = XfwfSPageDown;
+ info.flags = XFWF_VPOS; /* Suggest a value: */
+ info.vpos = min(1.0, ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y + ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht);
+ outside = True;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+ }
+ if (! outside) { /* Inside the thumb */
+ ((XfwfSlider2Widget)self)->xfwfSlider2.drag_in_progress = True;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.m_delta_x = x - event->xbutton.x;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.m_delta_y = y - event->xbutton.y;
+ }
+}
+
+/*ARGSUSED*/
+static void finish(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XfwfScrollInfo info;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.drag_in_progress) {
+ ((XfwfSlider2Widget)self)->xfwfSlider2.drag_in_progress = False;
+ info.reason = XfwfSMove;
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.hpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x;
+ info.vpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+ }
+}
+
+/*ARGSUSED*/
+static void drag(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XfwfScrollInfo info;
+ Dimension wd, ht, fwd, fht;
+ Position oldx, oldy, newx, newy, fx, fy;
+ float dum1, dum2;
+
+ if (! ((XfwfSlider2Widget)self)->xfwfSlider2.drag_in_progress) return;
+ if (event->type != ButtonPress && event->type != ButtonRelease
+ && event->type != MotionNotify)
+ XtError("The drag action must be bound to a mouse event");
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &oldx, &oldy, &wd, &ht);
+ newx = event->xbutton.x + ((XfwfSlider2Widget)self)->xfwfSlider2.m_delta_x;
+ newy = event->xbutton.y + ((XfwfSlider2Widget)self)->xfwfSlider2.m_delta_y;
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_info(self, &newx, &newy, &wd, &ht, &((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x, &((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y,&dum1,&dum2);
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.move_thumb(self, oldx, oldy, wd, ht, newx, newy);
+ info.reason = XfwfSDrag;
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.hpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x;
+ info.vpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &info);
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfSlider2WidgetClass c = (XfwfSlider2WidgetClass) class;
+ XfwfSlider2WidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfSlider2WidgetClass) return;
+ super = (XfwfSlider2WidgetClass)class->core_class.superclass;
+ if (c->xfwfSlider2_class.compute_thumb == XtInherit_compute_thumb)
+ c->xfwfSlider2_class.compute_thumb = super->xfwfSlider2_class.compute_thumb;
+ if (c->xfwfSlider2_class.move_thumb == XtInherit_move_thumb)
+ c->xfwfSlider2_class.move_thumb = super->xfwfSlider2_class.move_thumb;
+ if (c->xfwfSlider2_class.compute_info == XtInherit_compute_info)
+ c->xfwfSlider2_class.compute_info = super->xfwfSlider2_class.compute_info;
+ if (c->xfwfSlider2_class.scroll_response == XtInherit_scroll_response)
+ c->xfwfSlider2_class.scroll_response = super->xfwfSlider2_class.scroll_response;
+}
+/*ARGSUSED*/static void compute_thumb(self,x,y,width,height)Widget self;Position * x;Position * y;Dimension * width;Dimension * height;
+{
+ Position fx, fy;
+ Dimension fw, fh;
+
+ xfwfLabelClassRec.xfwfCommon_class.compute_inside(self, &fx, &fy, &fw, &fh);
+ *width = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd * fw + 0.5;
+ *height = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht * fh + 0.5;
+ if (*width < ((XfwfSlider2Widget)self)->xfwfSlider2.minsize) *width = min(fw, ((XfwfSlider2Widget)self)->xfwfSlider2.minsize);
+ if (*height < ((XfwfSlider2Widget)self)->xfwfSlider2.minsize) *height = min(fh, ((XfwfSlider2Widget)self)->xfwfSlider2.minsize);
+ *x = fx + ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x * (fw - *width) + 0.5;
+ *y = fy + ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y * (fh - *height) + 0.5;
+}
+/*ARGSUSED*/static void compute_inside(self,x,y,w,h)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;
+{
+ int tmp;
+
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, x, y, w, h);
+ *x += ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth;
+ *y += ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth;
+ tmp = *w - 2 * ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth; *w = (tmp < 0) ? 0 : tmp;
+ tmp = *h - 2 * ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth; *h = (tmp < 0) ? 0 : tmp;
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Position x, y;
+ Dimension wd, ht;
+
+ if (! XtIsRealized(self)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc, region);
+ XSetRegion(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc, region);
+ XSetRegion(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc, region);
+ }
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &x, &y, &wd, &ht);
+ XFillRectangle(XtDisplay(self), XtWindow(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc, x, y, wd, ht);
+ XfwfDrawFrame(self, x, y, wd, ht, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameType, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth,
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc, ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc);
+ if (region != NULL) {
+ XSetClipMask(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumbgc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc, None);
+ XSetClipMask(XtDisplay(self), ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc, None);
+ }
+ xfwfLabelClassRec.core_class.expose(self, event, region);
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y = 0.0;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht = 1.0;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.drag_in_progress = False;
+ create_thumbgc(self);
+ create_gc(self);
+ create_graygc(self);
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumblightgc = NULL; create_thumblightgc(self);
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumbdarkgc = NULL; create_thumbdarkgc(self);
+}
+/*ARGSUSED*/static void move_thumb(self,oldx,oldy,wd,ht,newx,newy)Widget self;int oldx;int oldy;int wd;int ht;int newx;int newy;
+{
+ int h;
+
+ XCopyArea(XtDisplay(self), XtWindow(self), XtWindow(self),
+ DefaultGCOfScreen(XtScreen(self)),
+ oldx, oldy, wd, ht, newx, newy);
+ /* First check if the old and new areas do not overlap */
+ if (newx + wd <= oldx || oldx + wd <= newx
+ || newy + ht <= oldy || oldy + ht <= newy) {
+ XClearArea(XtDisplay(self), XtWindow(self), oldx, oldy, wd, ht, False);
+ return;
+ } else { /* They do overlap */
+ h = oldy - newy;
+ if (h > 0)
+ XClearArea(XtDisplay(self), XtWindow(self), oldx, newy + ht, wd,h,False);
+ else if (h < 0)
+ XClearArea(XtDisplay(self), XtWindow(self), oldx, oldy, wd, -h, False);
+ if (newx < oldx)
+ XClearArea(XtDisplay(self), XtWindow(self), newx + wd,
+ max(oldy, newy), oldx - newx, ht - abs(h), False);
+ else if (oldx < newx)
+ XClearArea(XtDisplay(self), XtWindow(self), oldx, max(oldy, newy),
+ newx - oldx, ht - abs(h), False);
+ }
+}
+/*ARGSUSED*/static void compute_info(self,x,y,w,h,thumb_x,thumb_y,thumb_wd,thumb_ht)Widget self;Position * x;Position * y;Dimension * w;Dimension * h;float * thumb_x;float * thumb_y;float * thumb_wd;float * thumb_ht;
+{
+ Dimension fw, fh;
+ Position fx, fy;
+
+ xfwfLabelClassRec.xfwfCommon_class.compute_inside(self, &fx, &fy, &fw, &fh);
+ *w = min(fw, max(((XfwfSlider2Widget)self)->xfwfSlider2.minsize, *w));
+ *h = min(fh, max(((XfwfSlider2Widget)self)->xfwfSlider2.minsize, *h));
+ *x = min(fx + fw - *w, max(fx, *x));
+ *y = min(fy + fh - *h, max(fy, *y));
+ *thumb_wd = ((float) *w)/fw;
+ *thumb_ht = ((float) *h)/fh;
+ *thumb_x = (*w == fw) ? 0.0 : ((float) (*x - fx))/(fw - *w);
+ *thumb_y = (*h == fh) ? 0.0 : ((float) (*y - fy))/(fh - *h);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean need_redisplay = False;
+ Position x, y;
+ Dimension w, h;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbPixmap != ((XfwfSlider2Widget)old)->xfwfSlider2.thumbPixmap) {
+ create_thumbgc(self);
+ need_redisplay = True;
+ } else if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbColor != ((XfwfSlider2Widget)old)->xfwfSlider2.thumbColor) {
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumbPixmap = NULL;
+ create_thumbgc(self);
+ need_redisplay = True;
+ }
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameWidth != ((XfwfSlider2Widget)old)->xfwfSlider2.thumbFrameWidth)
+ need_redisplay = True;
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumbFrameType != ((XfwfSlider2Widget)old)->xfwfSlider2.thumbFrameType)
+ need_redisplay = True;
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.minsize != ((XfwfSlider2Widget)old)->xfwfSlider2.minsize) {
+ compute_thumb(old, &x, &y, &w, &h);
+ if (w < ((XfwfSlider2Widget)self)->xfwfSlider2.minsize || h < ((XfwfSlider2Widget)self)->xfwfSlider2.minsize) need_redisplay = True;
+ }
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.scrollResponse != ((XfwfSlider2Widget)old)->xfwfSlider2.scrollResponse) {
+ ((XfwfSlider2Widget)self)->xfwfSlider2.scrollResponse = ((XfwfSlider2Widget)old)->xfwfSlider2.scrollResponse;
+ XtWarning("scrollResponse resource may only be queried, not set");
+ }
+ return need_redisplay;
+}
+/*ARGSUSED*/static void scroll_response(wdg,client_data,call_data)Widget wdg;XtPointer client_data;XtPointer call_data;
+{
+ Widget self = (Widget) client_data;
+ XfwfScrollInfo *inf = (XfwfScrollInfo *)call_data;
+ XfwfScrollInfo new_info;
+ float x, y, w, h;
+ Position newx, newy, oldx, oldy;
+ Dimension newwd, newht, oldwd, oldht, wd, ht;
+ XEvent event;
+ XRectangle rect;
+ Region clip;
+ Display *dpy = XtDisplay(self);
+
+ x = (inf->flags&XFWF_HPOS) && range(inf->hpos) ? inf->hpos : ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x;
+ y = (inf->flags&XFWF_VPOS) && range(inf->vpos) ? inf->vpos : ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y;
+ w = (inf->flags&XFWF_HSIZE) && range(inf->hsize) ? inf->hsize : ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd;
+ h = (inf->flags&XFWF_VSIZE) && range(inf->vsize) ? inf->vsize : ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht;
+
+ if (((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd != w || ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht != h) { /* Size changed */
+ if (XtIsRealized(self))
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &oldx, &oldy, &oldwd, &oldht);
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd = w;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht = h;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x = x;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y = y;
+ if (XtIsRealized(self)) {
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &newx, &newy, &newwd, &newht);
+ XClearArea(dpy, XtWindow(self), oldx, oldy, oldwd, oldht, False);
+ event.xexpose.x = rect.x = newx;
+ event.xexpose.y = rect.y = newy;
+ event.xexpose.width = rect.width = newwd;
+ event.xexpose.height = rect.height = newht;
+ clip = XCreateRegion();
+ XUnionRectWithRegion(&rect, clip, clip);
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->core_class.expose(self, &event, clip);
+ XDestroyRegion(clip);
+ }
+ } else if (((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x != x || ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y != y) { /* Only position changed */
+ if (XtIsRealized(self))
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &oldx, &oldy, &wd, &ht);
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x = x;
+ ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y = y;
+ if (XtIsRealized(self)) {
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.compute_thumb(self, &newx, &newy, &wd, &ht);
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.move_thumb(self, oldx, oldy, wd, ht, newx, newy);
+ }
+ }
+
+ if (inf->reason != XfwfSNotify) {
+ new_info = *inf;
+ new_info.reason = XfwfSNotify;
+ XtCallCallbackList(self, ((XfwfSlider2Widget)self)->xfwfSlider2.scrollCallback, &new_info);
+ }
+}
+/*ARGSUSED*/void XfwfGetThumb(self,info)Widget self;XfwfScrollInfo * info;
+{
+ if (! XtIsSubclass(self, xfwfSlider2WidgetClass))
+ XtError("XfwfGetThumb called with incorrect widget type");
+ info->reason = XfwfSNotify;
+ info->flags = XFWF_VPOS | XFWF_VSIZE | XFWF_HPOS | XFWF_HSIZE;
+ info->vpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_y;
+ info->vsize = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_ht;
+ info->hpos = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_x;
+ info->hsize = ((XfwfSlider2Widget)self)->xfwfSlider2.thumb_wd;
+}
+/*ARGSUSED*/void XfwfMoveThumb(self,x,y)Widget self;double x;double y;
+{
+ XfwfScrollInfo info;
+
+ if (! XtIsSubclass(self, xfwfSlider2WidgetClass))
+ XtError("XfwfMoveThumb called with incorrect widget type");
+ if (x < 0.0 || x > 1.0 || y < 0.0 || y > 1.0)
+ XtError("XfwfMoveThumb called with incorrect arguments");
+
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.reason = XfwfSNotify;
+ info.vpos = y;
+ info.hpos = x;
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.scroll_response(NULL, self, &info);
+}
+/*ARGSUSED*/void XfwfResizeThumb(self,wd,ht)Widget self;double wd;double ht;
+{
+ XfwfScrollInfo info;
+
+ if (! XtIsSubclass(self, xfwfSlider2WidgetClass))
+ XtError("XfwfResizeThumb called with incorrect widget type");
+ if (wd < 0.0 || wd > 1.0 || ht < 0.0 || ht > 1.0)
+ XtError("XfwfResizeThumb called with incorrect arguments");
+
+ info.reason = XfwfSNotify;
+ info.flags = XFWF_VSIZE | XFWF_HSIZE;
+ info.vsize = ht;
+ info.hsize = wd;
+ ((XfwfSlider2WidgetClass)self->core.widget_class)->xfwfSlider2_class.scroll_response(NULL, self, &info);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Slider2.h b/vendor/x11iraf/obm/ObmW/Slider2.h
new file mode 100644
index 00000000..962590b7
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Slider2.h
@@ -0,0 +1,96 @@
+/* Generated by wbuild from "Slider2.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfSlider2_H_
+#define _XfwfSlider2_H_
+#include "Label.h"
+#include "scroll.h"
+void XfwfGetThumb(
+#if NeedFunctionPrototypes
+Widget,XfwfScrollInfo *
+#endif
+);
+void XfwfMoveThumb(
+#if NeedFunctionPrototypes
+Widget,double ,double
+#endif
+);
+void XfwfResizeThumb(
+#if NeedFunctionPrototypes
+Widget,double ,double
+#endif
+);
+#ifndef XtNthumbColor
+#define XtNthumbColor "thumbColor"
+#endif
+#ifndef XtCThumbColor
+#define XtCThumbColor "ThumbColor"
+#endif
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNthumbPixmap
+#define XtNthumbPixmap "thumbPixmap"
+#endif
+#ifndef XtCThumbPixmap
+#define XtCThumbPixmap "ThumbPixmap"
+#endif
+#ifndef XtRPixmap
+#define XtRPixmap "Pixmap"
+#endif
+
+#ifndef XtNminsize
+#define XtNminsize "minsize"
+#endif
+#ifndef XtCMinsize
+#define XtCMinsize "Minsize"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNthumbFrameWidth
+#define XtNthumbFrameWidth "thumbFrameWidth"
+#endif
+#ifndef XtCThumbFrameWidth
+#define XtCThumbFrameWidth "ThumbFrameWidth"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNthumbFrameType
+#define XtNthumbFrameType "thumbFrameType"
+#endif
+#ifndef XtCThumbFrameType
+#define XtCThumbFrameType "ThumbFrameType"
+#endif
+#ifndef XtRFrameType
+#define XtRFrameType "FrameType"
+#endif
+
+#ifndef XtNscrollCallback
+#define XtNscrollCallback "scrollCallback"
+#endif
+#ifndef XtCScrollCallback
+#define XtCScrollCallback "ScrollCallback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+#ifndef XtNscrollResponse
+#define XtNscrollResponse "scrollResponse"
+#endif
+#ifndef XtCScrollResponse
+#define XtCScrollResponse "ScrollResponse"
+#endif
+#ifndef XtRXTCallbackProc
+#define XtRXTCallbackProc "XTCallbackProc"
+#endif
+
+typedef struct _XfwfSlider2ClassRec *XfwfSlider2WidgetClass;
+typedef struct _XfwfSlider2Rec *XfwfSlider2Widget;
+externalref WidgetClass xfwfSlider2WidgetClass;
+#endif /*_XfwfSlider2_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Slider2.man b/vendor/x11iraf/obm/ObmW/Slider2.man
new file mode 100644
index 00000000..399250bb
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Slider2.man
@@ -0,0 +1,1068 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfSlider2
+.SH DESCRIPTION
+A Slider2 widget consists of a rectangular area in which a `thumb' can be
+moved about. A Slider2 is typically used to pan or scroll another window; as
+such is can replace two scrollbars. The thumb can be dragged with the mouse,
+or the mouse can be clicked next to the thumb, to move it in the direction of
+the mouse. The thumb may contain one or more lines of text, although there
+is usually no room for more than one or two words.
+
+The widget has three callbacks. The thumb position and size are not
+controled by resources, but by calling a function.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfSlider2
+Name Class Type Default
+XtNthumbColor XtCThumbColor Pixel XtDefaultBackground
+XtNthumbPixmap XtCThumbPixmap Pixmap NULL
+XtNminsize XtCMinsize Dimension 20
+XtNthumbFrameWidth XtCThumbFrameWidth Dimension 2
+XtNthumbFrameType XtCThumbFrameType FrameType XfwfRaised
+XtNscrollCallback XtCScrollCallback Callback NULL
+XtNscrollResponse XtCScrollResponse XTCallbackProc scroll_response
+
+.TE
+.ps
+
+.TP
+.I "XtNthumbColor"
+The color of the thumb is by default set to the default background
+color of the display, but it can be changed with the \fIthumbColor\fP
+resource. It is also possible to tile the thumb with a pixmap, see
+below.
+
+
+
+.hi
+
+.nf
+Pixel thumbColor = <String>XtDefaultBackground
+.fi
+
+.eh
+
+.TP
+.I "XtNthumbPixmap"
+Instead of a color, the thumb can also be tiled with a pixmap.
+However, there is currently no converter from string to pixmap, so
+this resource can only be set from the application, not from resource
+files.
+
+If both \fIthumbColor\fP and \fIthumbPixmap\fP are set, the pixmap takes
+precedence.
+
+
+
+.hi
+
+.nf
+Pixmap thumbPixmap = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNminsize"
+The minimum size of the thumb is by default 20 pixels. It can be set
+with the \fIminsize\fP resource.
+
+
+
+.hi
+
+.nf
+Dimension minsize = 20
+.fi
+
+.eh
+
+.TP
+.I "XtNthumbFrameWidth"
+The width of the frame around the thumb is independent of the frame
+around the whole widget. It can be set with \fIthumbFrameWidth\fP.
+
+
+
+.hi
+
+.nf
+Dimension thumbFrameWidth = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNthumbFrameType"
+The style of the frame around the thumb is set with
+\fIthumbFrameType\fP. By default, it is \fIXfwfRaised\fP. Note that there are no
+resources to control the shadow scheme of the thumb independently from
+that of the outer frame. That means that the resources \fIshadowScheme\fP,
+\fItopShadowColor\fP, \fItopShadowStipple\fP, etc, also influence the frame of the
+thumb.
+
+
+
+.hi
+
+.nf
+FrameType thumbFrameType = XfwfRaised
+.fi
+
+.eh
+
+.TP
+.I "XtNscrollCallback"
+The routines on the callback list are called whenever the user
+manipulates the slider and also when the Slider2 receives a call on
+its \fIscrollResponse\fP function with a reason other than \fIXfwfSNotify\fP.
+
+The \fIcall_data\fP parameter of the callback routines is a pointer
+to an \fIXfwfScrollInfo\fP structure, which looks like this: \fItypedef
+struct _XfwfScrollInfo { XfwfSReason reason; XfwfSFlags flags; float
+vpos, vsize, hpos, hsize;} XfwfScrollInfo\fP.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList scrollCallback = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNscrollResponse"
+The Slider2 widget provides has a method for dealing with scroll
+requests from the application or from other widgets. A pointer to that
+function can be retrieved with \fIXtGetValues\fP as the resource
+\fIXtNscrollResponse\fP. This resource can only be queried, not set.
+
+
+
+.hi
+
+.nf
+XtCallbackProc scrollResponse = scroll_response
+.fi
+
+.eh
+
+.TP
+.I "XtNframeWidth"
+The default frame width is changed from 0 to 2.
+
+
+
+.hi
+
+.nf
+ frameWidth = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNframeType"
+The default frame type is now \fIXfwfSunken\fP.
+
+
+
+.hi
+
+.nf
+ frameType = XfwfSunken
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfLabel
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNtablist XtCTablist String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNalignment XtCAlignment Alignment 0
+XtNtopMargin XtCTopMargin Dimension 2
+XtNbottomMargin XtCBottomMargin Dimension 2
+XtNleftMargin XtCLeftMargin Dimension 2
+XtNrightMargin XtCRightMargin Dimension 2
+XtNshrinkToFit XtCShrinkToFit Boolean False
+XtNrvStart XtCRvStart Int 0
+XtNrvLength XtCRvLength Int 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The \fIscroll.h\fP header file is needed for the \fIXfwfScrollInfo\fP
+structure.
+
+.nf
+
+.B incl
+ <Xfwf/scroll.h>
+.fi
+
+The current size and position of the thumb can be queried with the
+function \fIgetThumb\fP. It fills the \fIinfo\fP argument with the current values.
+
+.nf
+XfwfGetThumb( $, XfwfScrollInfo * info)
+.fi
+
+.hi
+{
+ if (! XtIsSubclass($, xfwfSlider2WidgetClass))
+ XtError("XfwfGetThumb called with incorrect widget type");
+ info->reason = XfwfSNotify;
+ info->flags = XFWF_VPOS | XFWF_VSIZE | XFWF_HPOS | XFWF_HSIZE;
+ info->vpos = $thumb_y;
+ info->vsize = $thumb_ht;
+ info->hpos = $thumb_x;
+ info->hsize = $thumb_wd;
+}
+.eh
+
+To change the position of the thumb, a call to \fImoveThumb\fP can be
+used. The arguments must be two numbers between 0 and 1. The thumb
+is moved with \fIXCopyArea\fP.
+
+This is a convenience function. The standard interface is through the
+\fIscrollResponse\fP resource. In the Slider2 widget, that resource is
+connected to the \fIscroll_response\fP method.
+
+.nf
+XfwfMoveThumb( $, double x, double y)
+.fi
+
+.hi
+{
+ XfwfScrollInfo info;
+
+ if (! XtIsSubclass($, xfwfSlider2WidgetClass))
+ XtError("XfwfMoveThumb called with incorrect widget type");
+ if (x < 0.0 || x > 1.0 || y < 0.0 || y > 1.0)
+ XtError("XfwfMoveThumb called with incorrect arguments");
+
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.reason = XfwfSNotify;
+ info.vpos = y;
+ info.hpos = x;
+ $scroll_response(NULL, $, info);
+}
+.eh
+
+Resizing the thumb is done with \fIresizeThumb\fP. The two arguments
+must be between 0 and 1.
+
+This is a convenience function. The standard interface is through the
+\fIscrollResponse\fP resource. In the Slider2 widget, that resource is
+connected to the \fIscroll_response\fP method.
+
+.nf
+XfwfResizeThumb( $, double wd, double ht)
+.fi
+
+.hi
+{
+ XfwfScrollInfo info;
+
+ if (! XtIsSubclass($, xfwfSlider2WidgetClass))
+ XtError("XfwfResizeThumb called with incorrect widget type");
+ if (wd < 0.0 || wd > 1.0 || ht < 0.0 || ht > 1.0)
+ XtError("XfwfResizeThumb called with incorrect arguments");
+
+ info.reason = XfwfSNotify;
+ info.flags = XFWF_VSIZE | XFWF_HSIZE;
+ info.vsize = ht;
+ info.hsize = wd;
+ $scroll_response(NULL, $, info);
+}
+.eh
+
+.SS "Translations"
+
+The \fIstart\fP action should be bound to a mouse button press, because it
+needs the coordinates of the mouse. The \fIdrag\fP action is bound to mouse
+movement and the \fIfinish\fP action is normally bound to a release of the
+mouse button.
+
+.nf
+<Btn1Down>: start()
+.fi
+
+.nf
+<Btn1Motion>: drag()
+.fi
+
+.nf
+<Btn1Up>: finish()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "start
+
+The \fIstart\fP action checks the position of the mouse and if it was
+outside the thumb, it calls the \fIscrollCallback\fP. Otherwise, it only
+records the position. Note that the mouse may have been to the left as
+well as below the thumb, causing the callbacks to be called twice.
+
+.hi
+
+.nf
+void start($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Dimension w, h;
+ Position x, y;
+ XfwfScrollInfo info;
+ Boolean outside = False;
+
+ if (event->type != ButtonPress event->type != ButtonRelease
+ event->type != MotionNotify)
+ XtError("The start action must be bound to a mouse event");
+ $compute_thumb($, x, y, w, h);
+ if (event->xbutton.x < x) { /* Left of thumb */
+ info.reason = XfwfSPageLeft;
+ info.flags = XFWF_HPOS; /* Suggest a value: */
+ info.hpos = max(0.0, $thumb_x - $thumb_wd);
+ outside = True;
+ XtCallCallbackList($, $scrollCallback, info);
+ }
+ if (event->xbutton.x >= x + w) { /* Right of thumb */
+ info.reason = XfwfSPageRight;
+ info.flags = XFWF_HPOS; /* Suggest a value: */
+ info.hpos = min(1.0, $thumb_x + $thumb_wd);
+ outside = True;
+ XtCallCallbackList($, $scrollCallback, info);
+ }
+ if (event->xbutton.y < y) { /* Above thumb */
+ info.reason = XfwfSPageUp;
+ info.flags = XFWF_VPOS; /* Suggest a value: */
+ info.vpos = max(0.0, $thumb_y - $thumb_ht);
+ outside = True;
+ XtCallCallbackList($, $scrollCallback, info);
+ }
+ if (event->xbutton.y >= y + h) { /* Below thumb */
+ info.reason = XfwfSPageDown;
+ info.flags = XFWF_VPOS; /* Suggest a value: */
+ info.vpos = min(1.0, $thumb_y + $thumb_ht);
+ outside = True;
+ XtCallCallbackList($, $scrollCallback, info);
+ }
+ if (! outside) { /* Inside the thumb */
+ $drag_in_progress = True;
+ $m_delta_x = x - event->xbutton.x;
+ $m_delta_y = y - event->xbutton.y;
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "finish
+
+The \fIfinish\fP action does nothing if this is the end of a
+click outside the thumb. The callbacks for this event have already
+been called.
+
+If this is the end of a drag action, we reset the flag
+\fIdrag_in_progress\fP to False and call the drop callbacks.
+
+.hi
+
+.nf
+void finish($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XfwfScrollInfo info;
+
+ if ($drag_in_progress) {
+ $drag_in_progress = False;
+ info.reason = XfwfSMove;
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.hpos = $thumb_x;
+ info.vpos = $thumb_y;
+ XtCallCallbackList($, $scrollCallback, info);
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "drag
+
+An application that can draw fast enough, may wish to redraw with
+every movement of the thumb, instead of only at the end of the drag
+action. The drag callback is provided for this purpose. It is called
+in the same way as the drop callback, with the current relative
+position of the thumb.
+
+.hi
+
+.nf
+void drag($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XfwfScrollInfo info;
+ Dimension wd, ht, fwd, fht;
+ Position oldx, oldy, newx, newy, fx, fy;
+ float dum1, dum2;
+
+ if (! $drag_in_progress) return;
+ if (event->type != ButtonPress event->type != ButtonRelease
+ event->type != MotionNotify)
+ XtError("The drag action must be bound to a mouse event");
+ $compute_thumb($, oldx, oldy, wd, ht);
+ newx = event->xbutton.x + $m_delta_x;
+ newy = event->xbutton.y + $m_delta_y;
+ $compute_info($, newx, newy, wd, ht, $thumb_x, $thumb_y,dum1,dum2);
+ $move_thumb($, oldx, oldy, wd, ht, newx, newy);
+ info.reason = XfwfSDrag;
+ info.flags = XFWF_VPOS | XFWF_HPOS;
+ info.hpos = $thumb_x;
+ info.vpos = $thumb_y;
+ XtCallCallbackList($, $scrollCallback, info);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+.nf
+
+.B incl
+ "stip4.bm"
+.fi
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The position and size of the thumb are controlled by four variables
+that can assume values between 0 and 1. If \fIthumb_x\fP is 0, the thumb
+is located against the left side, if it is 1, the thumb is put against
+the right side.
+
+If \fIthumb_wd\fP is 1, the thumb is as large as possible, if it is 0, it
+will have its minimum width \fIminsize\fP.
+
+.nf
+float thumb_x
+.fi
+
+.nf
+float thumb_y
+.fi
+
+.nf
+float thumb_wd
+.fi
+
+.nf
+float thumb_ht
+.fi
+
+A boolean variable is set to when a draggin action has started, but
+not yet finished.
+
+.nf
+Boolean drag_in_progress
+.fi
+
+During a drag operation, the thumb is kept at a fixed offset from
+the moving mouse. The offset is stored in two local variables.
+
+.nf
+int m_delta_x
+.fi
+
+.nf
+int m_delta_y
+.fi
+
+We also need three more GC's for the thumb and the light and dark
+parts of the thumb's frame.
+
+.nf
+GC thumbgc
+.fi
+
+.nf
+GC thumblightgc
+.fi
+
+.nf
+GC thumbdarkgc
+.fi
+
+.hi
+
+.hi
+.SH "Class variables"
+
+The Core variable \fIcompress_exposure\fP is OR'ed with
+\fIXtExposeGraphicsExpose\fP, in order to get graphics expose events delivered
+to the \fIexpose\fP method.
+
+.nf
+compress_exposure = XtExposeCompressMultiple |XtExposeGraphicsExpose
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The \fIcompute_thumb\fP method returns the position and size of the
+thumb in pixels.
+
+.nf
+compute_thumb($, Position * x, Position * y, Dimension * width, Dimension * height)
+{
+ Position fx, fy;
+ Dimension fw, fh;
+
+ #compute_inside($, fx, fy, fw, fh);
+ *width = $thumb_wd * fw + 0.5;
+ *height = $thumb_ht * fh + 0.5;
+ if (*width < $minsize) *width = min(fw, $minsize);
+ if (*height < $minsize) *height = min(fh, $minsize);
+ *x = fx + $thumb_x * (fw - *width) + 0.5;
+ *y = fy + $thumb_y * (fh - *height) + 0.5;
+}
+.fi
+
+The \fIcompute_inside\fP method of the Label class returns the area inside the
+frame, but the label of Slider2 widget should appear in the thumb. Therefore
+the \fIcompute_inside\fP method is redefined. This means that the \fIexpose\fP
+method of the Label class can still be used, because it calls this function
+to establish the position of the text.
+
+.nf
+compute_inside($, Position * x, Position * y, Dimension * w, Dimension * h)
+{
+ int tmp;
+
+ $compute_thumb($, x, y, w, h);
+ *x += $thumbFrameWidth;
+ *y += $thumbFrameWidth;
+ tmp = *w - 2 * $thumbFrameWidth; *w = (tmp < 0) ? 0 : tmp;
+ tmp = *h - 2 * $thumbFrameWidth; *h = (tmp < 0) ? 0 : tmp;
+}
+.fi
+
+The \fIexpose\fP method of the superclass is called to draw the outer frame
+and the text inside the thumb. Only the frame of the thumb is drawn here.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Position x, y;
+ Dimension wd, ht;
+
+ if (! XtIsRealized($)) return;
+ if (region != NULL) {
+ XSetRegion(XtDisplay($), $thumbgc, region);
+ XSetRegion(XtDisplay($), $thumbdarkgc, region);
+ XSetRegion(XtDisplay($), $thumblightgc, region);
+ }
+ $compute_thumb($, x, y, wd, ht);
+ XFillRectangle(XtDisplay($), XtWindow($), $thumbgc, x, y, wd, ht);
+ XfwfDrawFrame($, x, y, wd, ht, $thumbFrameType, $thumbFrameWidth,
+ $thumblightgc, $thumbdarkgc);
+ if (region != NULL) {
+ XSetClipMask(XtDisplay($), $thumbgc, None);
+ XSetClipMask(XtDisplay($), $thumbdarkgc, None);
+ XSetClipMask(XtDisplay($), $thumblightgc, None);
+ }
+ #expose($, event, region);
+}
+.fi
+
+The \fIinitialize\fP method only needs to set the local variables. The
+\fIgraygc\fP that is inherited from Label has to be defined differently,
+because it now should use the thumb's background, instead of the
+widget's. (It still doesn't work right when the thumb is tiled with a
+pixmap, however.) Likewise, \fIgc\fP and \fIrv_gc\fP must be defined
+differently. The two new GC's are also initialized.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ $thumb_x = $thumb_y = 0.0;
+ $thumb_wd = $thumb_ht = 1.0;
+ $drag_in_progress = False;
+ create_thumbgc($);
+ create_gc($);
+ create_graygc($);
+ $thumblightgc = NULL; create_thumblightgc($);
+ $thumbdarkgc = NULL; create_thumbdarkgc($);
+}
+.fi
+
+The following routine's name, \fImove_thumb\fP, indicates what it is
+used for, but not what it really does. It doesn't depend on the thumb
+at all, it simply copies a rectangle to another position in the window
+and clears the old rectangle to the background color.
+
+.nf
+move_thumb($, int oldx, int oldy, int wd, int ht, int newx, int newy)
+{
+ int h;
+
+ XCopyArea(XtDisplay($), XtWindow($), XtWindow($),
+ DefaultGCOfScreen(XtScreen($)),
+ oldx, oldy, wd, ht, newx, newy);
+ /* First check if the old and new areas do not overlap */
+ if (newx + wd <= oldx || oldx + wd <= newx
+ || newy + ht <= oldy || oldy + ht <= newy) {
+ XClearArea(XtDisplay($), XtWindow($), oldx, oldy, wd, ht, False);
+ return;
+ } else { /* They do overlap */
+ h = oldy - newy;
+ if (h > 0)
+ XClearArea(XtDisplay($), XtWindow($), oldx, newy + ht, wd,h,False);
+ else if (h < 0)
+ XClearArea(XtDisplay($), XtWindow($), oldx, oldy, wd, -h, False);
+ if (newx < oldx)
+ XClearArea(XtDisplay($), XtWindow($), newx + wd,
+ max(oldy, newy), oldx - newx, ht - abs(h), False);
+ else if (oldx < newx)
+ XClearArea(XtDisplay($), XtWindow($), oldx, max(oldy, newy),
+ newx - oldx, ht - abs(h), False);
+ }
+}
+.fi
+
+The \fIcompute_info\fP method computes the relative position and size of the
+thumb, given its geometry in pixels. Before that, it makes sure the pixel
+values are within the frame and it adapts the values if needed.
+
+.nf
+compute_info($, Position * x, Position * y, Dimension * w, Dimension * h, float * thumb_x, float * thumb_y, float * thumb_wd, float * thumb_ht)
+{
+ Dimension fw, fh;
+ Position fx, fy;
+
+ #compute_inside($, fx, fy, fw, fh);
+ *w = min(fw, max($minsize, *w));
+ *h = min(fh, max($minsize, *h));
+ *x = min(fx + fw - *w, max(fx, *x));
+ *y = min(fy + fh - *h, max(fy, *y));
+ *thumb_wd = ((float) *w)/fw;
+ *thumb_ht = ((float) *h)/fh;
+ *thumb_x = (*w == fw) ? 0.0 : ((float) (*x - fx))/(fw - *w);
+ *thumb_y = (*h == fh) ? 0.0 : ((float) (*y - fy))/(fh - *h);
+}
+.fi
+
+The \fIset_values\fP method changes the GC's when needed.
+A change in \fIminsize\fP doesn't necessarily cause a redraw; only if
+the current thumb size is less than the new minimum does the widget
+needs to be redrawn.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redisplay = False;
+ Position x, y;
+ Dimension w, h;
+
+ if ($thumbPixmap != $old$thumbPixmap) {
+ create_thumbgc($);
+ need_redisplay = True;
+ } else if ($thumbColor != $old$thumbColor) {
+ $thumbPixmap = NULL;
+ create_thumbgc($);
+ need_redisplay = True;
+ }
+ if ($thumbFrameWidth != $old$thumbFrameWidth)
+ need_redisplay = True;
+ if ($thumbFrameType != $old$thumbFrameType)
+ need_redisplay = True;
+ if ($minsize != $old$minsize) {
+ compute_thumb(old, x, y, w, h);
+ if (w < $minsize || h < $minsize) need_redisplay = True;
+ }
+ if ($scrollResponse != $old$scrollResponse) {
+ $scrollResponse = $old$scrollResponse;
+ XtWarning("scrollResponse resource may only be queried, not set");
+ }
+ return need_redisplay;
+}
+.fi
+
+The method \fIscroll_response\fP is exported via the \fIscrollResponse\fP
+resource. It has the format of a callback function, so that it can be
+registered as a callback in the \fIscrollCallback\fP list of some other
+widget. The \fIclient_data\fP must be a pointer to the Slider2 widget
+itself, the \fIcall_data\fP is a pointer to an \fIXfwfScrollInfo\fP structure.
+The widget \fIwdg\fP is the widget from whose callback list the function
+is called.
+
+If the size of the thumb changed, the area must be cleared and redrawn
+with \fIexpose\fP, but if only the position changed, the thumb can be
+moved with the \fImove_thumb\fP method, which is much faster.
+
+\fBdef\fP range(x) =
+(0.0 <=(x )(x )<=1.0 )
+
+.nf
+scroll_response(Widget wdg, XtPointer client_data, XtPointer call_data)
+{
+ Widget self = (Widget) client_data;
+ XfwfScrollInfo *inf = (XfwfScrollInfo *)call_data;
+ XfwfScrollInfo new_info;
+ float x, y, w, h;
+ Position newx, newy, oldx, oldy;
+ Dimension newwd, newht, oldwd, oldht, wd, ht;
+ XEvent event;
+ XRectangle rect;
+ Region clip;
+ Display *dpy = XtDisplay($);
+
+ x = (inf->flagsXFWF_HPOS) range(inf->hpos) ? inf->hpos : $thumb_x;
+ y = (inf->flagsXFWF_VPOS) range(inf->vpos) ? inf->vpos : $thumb_y;
+ w = (inf->flagsXFWF_HSIZE) range(inf->hsize) ? inf->hsize : $thumb_wd;
+ h = (inf->flagsXFWF_VSIZE) range(inf->vsize) ? inf->vsize : $thumb_ht;
+
+ if ($thumb_wd != w || $thumb_ht != h) { /* Size changed */
+ if (XtIsRealized($))
+ $compute_thumb($, oldx, oldy, oldwd, oldht);
+ $thumb_wd = w;
+ $thumb_ht = h;
+ $thumb_x = x;
+ $thumb_y = y;
+ if (XtIsRealized($)) {
+ $compute_thumb($, newx, newy, newwd, newht);
+ XClearArea(dpy, XtWindow($), oldx, oldy, oldwd, oldht, False);
+ event.xexpose.x = rect.x = newx;
+ event.xexpose.y = rect.y = newy;
+ event.xexpose.width = rect.width = newwd;
+ event.xexpose.height = rect.height = newht;
+ clip = XCreateRegion();
+ XUnionRectWithRegion(rect, clip, clip);
+ $expose($, event, clip);
+ XDestroyRegion(clip);
+ }
+ } else if ($thumb_x != x || $thumb_y != y) { /* Only position changed */
+ if (XtIsRealized($))
+ $compute_thumb($, oldx, oldy, wd, ht);
+ $thumb_x = x;
+ $thumb_y = y;
+ if (XtIsRealized($)) {
+ $compute_thumb($, newx, newy, wd, ht);
+ $move_thumb($, oldx, oldy, wd, ht, newx, newy);
+ }
+ }
+
+ if (inf->reason != XfwfSNotify) {
+ new_info = *inf;
+ new_info.reason = XfwfSNotify;
+ XtCallCallbackList($, $scrollCallback, new_info);
+ }
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The \fIcreate_gc\fP routine creates the GCs for the text.
+
+.nf
+create_gc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($gc != NULL) XtReleaseGC($, $gc);
+ values.background = $thumbColor;
+ values.foreground = $foreground;
+ values.font = $font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ $gc = XtGetGC($, mask, values);
+
+ if ($rv_gc != NULL) XtReleaseGC($, $rv_gc);
+ values.foreground = $thumbColor;
+ values.background = $foreground;
+ values.font = $font->fid;
+ mask = GCFont | GCBackground | GCForeground;
+ $rv_gc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fIcreate_graygc\fP routine creates the GC that grays the label in
+the thumb.
+
+.nf
+create_graygc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($graygc != NULL) XtReleaseGC($, $graygc);
+ values.foreground = $thumbColor;
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ values.fill_style = FillStippled;
+ mask = GCForeground | GCStipple | GCFillStyle;
+ $graygc = XtGetGC($, mask, values);
+}
+.fi
+
+\fIcreate_thumbgc\fP creates the GC that draw the background in the
+thumb.
+
+.nf
+create_thumbgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($thumbgc != NULL) XtReleaseGC($, $thumbgc);
+ if ($thumbPixmap != NULL) {
+ mask = GCTile | GCFillStyle;
+ values.tile = $thumbPixmap;
+ values.fill_style = FillTiled;
+ } else {
+ mask = GCForeground;
+ values.foreground = $thumbColor;
+ }
+ $thumbgc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fIcreate_thumblightgc\fP functions makes the GC for drawing the light
+parts of the thumb's frame.
+
+.nf
+create_thumblightgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($thumblightgc != NULL) XtReleaseGC($, $thumblightgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $topShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $thumbColor;
+ values.stipple = $topShadowStipple;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $lighter_color($, $thumbColor, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $thumbColor;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ $thumblightgc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fIcreate_thumbdarkgc\fP routines does the same for the dark parts of the
+thumb's frame.
+
+.nf
+create_thumbdarkgc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($thumbdarkgc != NULL) XtReleaseGC($, $thumbdarkgc);
+ switch ($shadowScheme) {
+ case XfwfColor:
+ mask = GCForeground;
+ values.foreground = $bottomShadowColor;
+ break;
+ case XfwfStipple:
+ mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = $bottomShadowStipple;
+ values.foreground = BlackPixelOfScreen(XtScreen($));
+ values.background = $thumbColor;
+ break;
+ case XfwfAuto:
+ if (DefaultDepthOfScreen(XtScreen($)) > 4
+ $darker_color($, $thumbColor, values.foreground)) {
+ mask = GCForeground;
+ } else {
+ mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
+ values.fill_style = FillOpaqueStippled;
+ values.background = $thumbColor;
+ values.foreground = WhitePixelOfScreen(XtScreen($));
+ values.stipple =
+ XCreateBitmapFromData(XtDisplay($),
+ RootWindowOfScreen(XtScreen($)),
+ stip4_bits, stip4_width, stip4_height);
+ }
+ break;
+ }
+ $thumbdarkgc = XtGetGC($, mask, values);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/Slider2P.h b/vendor/x11iraf/obm/ObmW/Slider2P.h
new file mode 100644
index 00000000..c4191940
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Slider2P.h
@@ -0,0 +1,87 @@
+/* Generated by wbuild from "Slider2.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfSlider2P_H_
+#define _XfwfSlider2P_H_
+#include "LabelP.h"
+#include "Slider2.h"
+typedef void (*compute_thumb_Proc)(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *
+#endif
+);
+#define XtInherit_compute_thumb ((compute_thumb_Proc) _XtInherit)
+typedef void (*move_thumb_Proc)(
+#if NeedFunctionPrototypes
+Widget,int ,int ,int ,int ,int ,int
+#endif
+);
+#define XtInherit_move_thumb ((move_thumb_Proc) _XtInherit)
+typedef void (*compute_info_Proc)(
+#if NeedFunctionPrototypes
+Widget,Position *,Position *,Dimension *,Dimension *,float *,float *,float *,float *
+#endif
+);
+#define XtInherit_compute_info ((compute_info_Proc) _XtInherit)
+typedef void (*scroll_response_Proc)(
+#if NeedFunctionPrototypes
+Widget ,XtPointer ,XtPointer
+#endif
+);
+#define XtInherit_scroll_response ((scroll_response_Proc) _XtInherit)
+typedef struct {
+/* methods */
+compute_thumb_Proc compute_thumb;
+move_thumb_Proc move_thumb;
+compute_info_Proc compute_info;
+#define range(x) (0.0 <=(x )&&(x )<=1.0 )
+
+
+scroll_response_Proc scroll_response;
+/* class variables */
+} XfwfSlider2ClassPart;
+typedef struct _XfwfSlider2ClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfLabelClassPart xfwfLabel_class;
+XfwfSlider2ClassPart xfwfSlider2_class;
+} XfwfSlider2ClassRec;
+
+typedef struct {
+/* resources */
+Pixel thumbColor;
+Pixmap thumbPixmap;
+Dimension minsize;
+Dimension thumbFrameWidth;
+FrameType thumbFrameType;
+XtCallbackList scrollCallback;
+XtCallbackProc scrollResponse;
+/* private state */
+float thumb_x;
+float thumb_y;
+float thumb_wd;
+float thumb_ht;
+Boolean drag_in_progress;
+int m_delta_x;
+int m_delta_y;
+GC thumbgc;
+GC thumblightgc;
+GC thumbdarkgc;
+} XfwfSlider2Part;
+
+typedef struct _XfwfSlider2Rec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfLabelPart xfwfLabel;
+XfwfSlider2Part xfwfSlider2;
+} XfwfSlider2Rec;
+
+externalref XfwfSlider2ClassRec xfwfSlider2ClassRec;
+
+#endif /* _XfwfSlider2P_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/TabString.h b/vendor/x11iraf/obm/ObmW/TabString.h
new file mode 100644
index 00000000..9151df67
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TabString.h
@@ -0,0 +1,26 @@
+/*
+ * Functions for drawing String's with tab characters in them
+ */
+
+#if (NeedFunctionPrototypes > 0)
+
+extern void XfwfDrawImageString(Display *display, Drawable drawable,
+ GC gc, int x, int y, String string, int length,
+ int *tabs);
+extern void XtabDrawString(Display *display, Drawable drawable, GC gc,
+ int x, int y, String string, int length, int *tabs);
+extern int * XfwfTablist2Tabs(char *tablist);
+extern int XfwfTextWidth(XFontStruct *font, String str, int length,
+ int *tabs);
+extern char * strnchr(char *s, int c, int n);
+
+#else
+
+extern void XfwfDrawImageString();
+extern void XtabDrawString();
+extern int * XfwfTablist2Tabs();
+extern int XfwfTextWidth();
+extern char * strnchr();
+
+#endif
+
diff --git a/vendor/x11iraf/obm/ObmW/Table.c b/vendor/x11iraf/obm/ObmW/Table.c
new file mode 100644
index 00000000..ecb6e8e8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Table.c
@@ -0,0 +1,4594 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+#include <X11/IntrinsicP.h>
+#include <X11/RectObjP.h>
+#include <X11/StringDefs.h>
+#include <X11/keysym.h>
+#include <X11/Xos.h>
+
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/Drawing.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/TableP.h>
+#include <X11/Xraw/TableUtil.h>
+#include <X11/Xraw/Frame.h>
+#include <X11/Xraw/AsciiText.h>
+#include <X11/Xraw/Viewport.h>
+#include <X11/Xraw/Scrollbar.h>
+#include <X11/Xraw/ScrolledTable.h>
+
+#ifdef EBUG_XRAW_MALLOC
+#include <dbmalloc/malloc.h>
+#endif
+
+#define MULTI_LINE_TABLE 32767
+
+
+#undef CELL_IN /* */
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define CALLOC(num,type) (num * sizeof(type) <= 0 ? (type*)NULL : \
+ (type*)XtMalloc((Cardinal)(num) * (Cardinal)sizeof(type)))
+
+#define NOT_A_CUT_BUFFER (-1)
+
+#define MAXCUT 30000
+#define EDIT(w) (((XawTableWidget) w)->table.edit)
+#define InRange(n,a,b) MAX(a,MIN(n,b))
+
+#define LEFT_EDGE(tw) (((XawTableWidget)tw)->table.internal_width + \
+ ((XawTableWidget)tw)->table.label_shadow_thickness)
+
+#define TOP_EDGE(tw) (((XawTableWidget)tw)->table.internal_height + \
+ ((XawTableWidget)tw)->table.label_shadow_thickness)
+
+#define CELL(field) cell->field
+#define STUFF(w) ((XawTableWidget)w)->table.table_stuff
+#define COLUMNS(w) ((XawTableWidget)w)->table.columns
+#define ROWS(w) ((XawTableWidget)w)->table.rows
+#define GET_CELL_LABEL ((CELL(label) == NULL ? Dummy : CELL(label)))
+
+#define COLUMN_DATA(tw) ((XawTableColumnRec*)tw->table.column_data)
+#define COLUMN_WIDTH(tw,column) \
+(tw->table.literal ? \
+ ( \
+ (COLUMN_DATA(tw)[column].flag & _CL_width) ?\
+ COLUMN_DATA(tw)[column].width : \
+ tw->table.column_default_width \
+ ) \
+ * tw->table.literal_width + \
+ 2 * tw->table.internal_width \
+ : \
+ ( \
+ (COLUMN_DATA(tw)[column].flag & _CL_width) ?\
+ COLUMN_DATA(tw)[column].width : \
+ tw->table.column_default_width \
+ ) \
+/* _COLUMN_WIDTH_ */)
+
+
+#define MANAGE_EDIT(tw) \
+ if ( ! XtIsManaged(EDIT(tw))) \
+ { \
+ XtManageChild (EDIT(tw)); \
+ XtSetKeyboardFocus ((Widget)tw, EDIT(tw)); \
+ }
+
+
+#define UNMANAGE_EDIT(tw) \
+ if ( XtIsManaged(EDIT(tw))) \
+ { \
+ XtUnmanageChild (tw->table.edit); \
+ XtSetKeyboardFocus((Widget)tw, (Widget)None); \
+ }
+
+
+#define DO_CALLBACK(w,callback,data) \
+ if (XtCallbackHasSome == XtHasCallbacks(w, callback)) \
+ XtCallCallbacks (w, callback, (XtPointer)&data)
+
+
+#define IsEditInRowColumn(tw, row, column) \
+ (XtIsManaged(EDIT(tw)) && (row == tw->table.edit_row) \
+ && (column == tw->table.edit_column))
+
+
+
+#define REJECT (-1)
+#define ACCEPT (0)
+
+#define CHECK_TABLE(tw) \
+ _check_table ((XtPointer)STUFF(tw), ROWS(tw), COLUMNS(tw)); \
+ CheckAllLabels(tw)
+
+
+
+typedef struct _XawTableCellRec {
+ /* Node communication entity */
+ XawTableNodeRec node;
+ /* Cell label entity */
+ char *label;
+ Position label_x;
+ Dimension label_width;
+ Dimension label_len;
+ /* Cell colour entity */
+ Boolean highlight;
+ Boolean special_colour;
+ Pixel fore;
+ Pixel back;
+ GC normal;
+ GC reverse;
+ GC top;
+ GC bottom;
+
+}XawTableCellRec;
+
+#define _CL_width (1L<<0)
+#define _CL_font (1L<<1)
+#define _CL_label (1L<<2)
+#define _CL_justify (1L<<3)
+#define _CL_background (1L<<4)
+#define _CL_foreground (1L<<5)
+
+typedef struct _XawTableColumnRec {
+ int flag;
+ int width;
+ XFontStruct *font;
+ char *label;
+ XtJustify justify;
+ Pixel background;
+ Pixel foreground;
+ GC normal;
+ GC reverse;
+ GC top;
+ GC bottom;
+}XawTableColumnRec;
+
+
+#ifdef CRAY
+#define WORD64
+#endif
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+static void Def_pixel();
+static void Def_scroll();
+static void Def_column_default_width();
+static void Def_literal_width();
+static void Def_shadow_thickness();
+
+#define Offset(field) XtOffsetOf(TableRec, field)
+
+static XtResource resources[] = {
+ {
+ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.foreground), XtRString, XtDefaultForeground
+ },
+ {
+ XtNeditForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.edit_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNeditBackground, XtCBackground, XtRPixel, sizeof(Pixel),
+ Offset(table.edit_back), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNrowForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.row_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNcolumnForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.column_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ Offset(table.font), XtRString, XtDefaultFont
+ },
+ {
+ XtNliteral, XtCLiteral, XtRBoolean, sizeof(Boolean),
+ Offset(table.literal), XtRImmediate, (XtPointer)False
+ },
+ {
+ XtNrowOriented, XtCRowOriented, XtRBoolean, sizeof(Boolean),
+ Offset(table.row_oriented), XtRImmediate, (XtPointer)True
+ },
+ {
+ XtNmaskNumber, XtCMaskNumber, XtRInt, sizeof(int),
+ Offset(table.mask_number), XtRImmediate, (XtPointer)7
+ },
+ {
+ XtNcolumns, XtCColumns, XtRInt, sizeof(int),
+ Offset(table.columns), XtRImmediate, (XtPointer)1
+ },
+ {
+ XtNrows, XtCRows, XtRInt, sizeof(int),
+ Offset(table.rows), XtRImmediate, (XtPointer)1
+ },
+ {
+ XtNtableMargin, XtCTableMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.tab_margin), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNrowMargin, XtCRowMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.row_margin), XtRImmediate, (XtPointer)1
+ },
+ {
+ XtNcolumnMargin, XtCColumnMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.col_margin), XtRImmediate, (XtPointer)1
+ },
+ {
+ XtNlabelShadowWidth, XtCLabelShadowWidth, XtRDimension,
+ sizeof(Dimension), Offset(table.label_shadow_thickness), XtRImmediate,
+ (XtPointer)1
+ },
+ {
+ XtNjustify, XtCJustify, XtRJustify, sizeof(XtJustify),
+ Offset(table.justify), XtRImmediate, (XtPointer)XtJustifyCenter
+ },
+ {
+ XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ Offset(table.internal_width), XtRImmediate, (XtPointer)4
+ },
+ {
+ XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
+ Offset(table.internal_height), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNencoding, XtCEncoding, XtRUnsignedChar, sizeof(unsigned char),
+ Offset(table.encoding), XtRImmediate, (XtPointer)XawTextEncoding8bit
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ Offset(container.shadow_thickness), XtRCallProc,
+ (XtPointer) Def_shadow_thickness
+ },
+ {
+ XtNvetricalScroll, XtCScroll, XtRWidget, sizeof(Widget),
+ Offset(table.v_scroll), XtRCallProc, (XtPointer)Def_scroll
+ },
+ {
+ XtNhorizontalScroll, XtCScroll, XtRWidget, sizeof(Widget),
+ Offset(table.h_scroll), XtRCallProc, (XtPointer)Def_scroll
+ },
+ {
+ XtNrowHeight, XtCRowHeight, XtRInt, sizeof(int),
+ Offset(table.row_height), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNdefaultWidth, XtCDefaultWidth, XtRInt, sizeof(int),
+ Offset(table.column_default_width), XtRCallProc,
+ (XtPointer) Def_column_default_width
+ },
+ {
+ XtNeditable, XtCEditable, XtRBoolean, sizeof(Boolean),
+ Offset(table.editable), XtRImmediate, (XtPointer) FALSE
+ },
+ {
+ XtNliteralWidth, XtCLiteralWidth, XtRInt, sizeof(int),
+ Offset(table.literal_width), XtRCallProc, (XtPointer) Def_literal_width
+ },
+
+ /* ALLOWANCE CALLBACKS */
+ {
+ XtNallowAddColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_add_column), XtRCallback, NULL
+ },
+ {
+ XtNallowAddRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_add_row), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_column), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_row), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_table), XtRCallback, NULL
+ },
+ /* INFORMATION CALLBACKS */
+
+ {
+ XtNaddColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.add_column), XtRCallback, NULL
+ },
+ {
+ XtNaddRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.add_row), XtRCallback, NULL
+ },
+ {
+ XtNcreateTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.create_table), XtRCallback, NULL
+ },
+ {
+ XtNchangedCell, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_cell), XtRCallback, NULL
+ },
+ {
+ XtNchangedColumnWidth, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_column_width), XtRCallback, NULL
+ },
+ {
+ XtNchangedRowHeight, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_row_height), XtRCallback, NULL
+ },
+ {
+ XtNdeleteColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_column), XtRCallback, NULL
+ },
+ {
+ XtNdeleteRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_row), XtRCallback, NULL
+ },
+ {
+ XtNdeleteTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_table), XtRCallback, NULL
+ },
+ {
+ XtNwhatCell, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.what_cell), XtRCallback, NULL
+ },
+};
+
+#define PRINTF_BOOL(a) ((a) ? "TRUE":"FALSE")
+#define PRINTF_NULL(a) ((a)==NULL ? "NULL":"not NULL")
+
+static void Def_pixel(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ static Pixel pix = 0;
+
+
+ if ( offset == (int)Offset(table.edit_fore))
+ pix = tw->table.foreground;
+ else if ( offset == (int)Offset(table.edit_back))
+ {
+ if (!FetchPixel(w, "#d0d000", &pix))
+ pix = WhitePixelOfScreen(XtScreen(w));
+ }
+ else
+ pix = tw->core.background_pixel;
+
+ value->addr = (XtPointer)& pix;
+}
+
+/* ARGSUSED */
+static void Def_scroll(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ static Widget view;
+
+ for (view = XtParent(w);
+ (view != (Widget)NULL) && (!XtIsSubclass(view, viewportWidgetClass));
+ view = XtParent(view))
+ /* EMPTY */;
+
+ if (view)
+ {
+ if (offset == Offset(table.v_scroll))
+ {
+ if (((view = XtNameToWidget(view, "vertical")) == (Widget)NULL)
+ || !XtIsSubclass(view, scrollbarWidgetClass))
+ view = (Widget)NULL;
+ }
+ else
+ if (offset == Offset(table.h_scroll))
+ {
+ if (((view = XtNameToWidget(view, "horizontal")) == (Widget)NULL)
+ || !XtIsSubclass(view, scrollbarWidgetClass))
+ view = (Widget)NULL;
+ }
+ }
+
+ value->addr = (XtPointer)&view;
+}
+
+/* ARGSUSED */
+static void Def_column_default_width(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static int column_default_width;
+
+ if (tw->table.literal)
+ column_default_width = 10;
+ else
+ column_default_width = 60;
+
+ value->addr = (XtPointer)&column_default_width;
+}
+
+#ifndef WORD64
+#define TXT_16 XChar2b
+#else
+#define TXT_16 char
+#endif
+
+/* ARGSUSED */
+static void Def_literal_width(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static int literal_width;
+
+ if (tw->table.encoding)
+ tw->table.literal_width = XTextWidth16(tw->table.font, (TXT_16*)"mmm", 3);
+ else
+ tw->table.literal_width = XTextWidth(tw->table.font, "mmm", 3);
+
+ tw->table.literal_width /= 3;
+
+ value->addr = (XtPointer)& literal_width;
+}
+
+/* ARGSUSED */
+static void Def_shadow_thickness(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ Widget parent = XtParent (w);
+ static Dimension shadow_thickness;
+
+ /*
+ if (XtIsSubclass (parent, scrolledTableWidgetClass) ||
+ XtIsSubclass (parent, viewportWidgetClass))
+ */
+ if (XtIsSubclass (parent, viewportWidgetClass))
+ shadow_thickness = 0;
+ else
+ shadow_thickness = 2;
+
+ value->addr = (XtPointer)& shadow_thickness;
+}
+
+
+#undef offset
+
+static void MultipleChangeGC();
+static void Initialize();
+static void Realize();
+static void Resize();
+static void Redisplay();
+static void Destroy();
+
+static Boolean SetValues();
+
+static void WalkForCells();
+static void LoseSelection();
+
+static void CallEdit();
+static void InsertSelection();
+static void StoreBuffer();
+static void WhatCell();
+static void KeyReturn();
+static void HighlightCell();
+static void UnhighlightCell();
+static void DoingNothing();
+
+static char* DummyString();
+
+static Boolean InitCell();
+
+static XtGeometryResult QueryGeometry();
+static XtGeometryResult GeometryManager();
+
+static XtActionsRec actions[] = {
+ {"call-edit", (XtActionProc)CallEdit },
+ {"insert-selection", (XtActionProc)InsertSelection},
+ {"store-in-buffer", (XtActionProc)StoreBuffer },
+ {"what_cell", (XtActionProc)WhatCell },
+ {"key_return", (XtActionProc)KeyReturn },
+ {"highlight", (XtActionProc)HighlightCell },
+ {"unhighlight", (XtActionProc)UnhighlightCell},
+ {"no-op", (XtActionProc)DoingNothing }
+};
+
+static char translations[] =
+ "Ctrl<Btn1Up>: what_cell() \n\
+ <Btn1Up>: call-edit() \n\
+ <Btn2Up>: insert-selection(PRIMARY, CUT_BUFFER0) \n\
+ <Btn3Up>: highlight() store-in-buffer(PRIMARY,CUT_BUFFER0) ";
+
+static char edit_translations[] =
+ " <Key>Return: key_return() \n\
+ <Key>Linefeed: key_return() \n\
+ <Key>Down: no-op(r) \n\
+ <Key>Up: no-op(r) ";
+
+static char* Dummy = "";
+
+
+#define SuperClass ((ContainerWidgetClass)&containerClassRec)
+
+TableClassRec tableClassRec = {
+ { /* core_class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class_name */ "Table",
+ /* widget_size */ sizeof(TableRec),
+ /* classInitialize */ NULL,
+ /* class_partInitialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ FALSE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ TRUE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ translations,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ /* Composite class part */
+ {
+ /* geometry manager */ GeometryManager,
+ /* change_managed */ XtInheritChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL,
+ },
+ /* Constraint class part */
+ {
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ 0,
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL,
+ },
+ /* Container class part */
+ {
+ /* ignore */ 0,
+ },
+ { /* Table class fields initialization */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass tableWidgetClass = (WidgetClass)&tableClassRec;
+
+
+/****************************************************************
+ *
+ * Private procedures
+ *
+ ****************************************************************/
+#define NORMAL_INDEX(fore, back) \
+ (int)(((int)fore * (int)back) & tw->table.mask_hash_table)
+
+#define SHADOW_INDEX(back) (int)(((int)back) & tw->table.mask_hash_table)
+
+#define GET_NORMAL(tw,i) (tw->table.normal_hash_table+(i))
+#define GET_SHADOW(tw,i) (tw->table.shadow_hash_table+(i))
+
+#define NEXT(i) (int)((i+1) & tw->table.mask_hash_table)
+
+static int MaskStaticArray[] = {
+ 0x1, 0x3, 0x7, 0xF,
+ 0x1F, 0x3F, 0x7F, 0xFF,
+ 0x1FF, 0x3FF, 0x7FF, 0xFFF
+ };
+
+static NormalReverseGC* GetNormalGC(w, fore, back, font)
+ Widget w;
+ Pixel fore;
+ Pixel back;
+ Font font;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = NORMAL_INDEX(fore, back);
+
+ while (GET_NORMAL(tw,i)->used > 0)
+ {
+
+ if (GET_NORMAL(tw,i)->fore == fore && GET_NORMAL(tw,i)->back == back)
+ {
+ GET_NORMAL(tw,i)->used++;
+ return GET_NORMAL(tw,i);
+ }
+ i = NEXT(i);
+ }
+
+ if (GET_NORMAL(tw,i)->used == 0)
+ {
+ XtGCMask mask;
+ XGCValues values;
+ Display *dpy = XtDisplay(w);
+ Window win = XtIsRealized(w) ? XtWindow(w) : XDefaultRootWindow(dpy);
+
+
+ mask = GCForeground | GCBackground | GCFont;
+ values.foreground = fore;
+ values.background = back;
+ values.font = font;
+
+ GET_NORMAL(tw,i)->normal = XCreateGC(dpy, win, mask, &values);
+ values.foreground = back;
+ values.background = fore;
+ GET_NORMAL(tw,i)->reverse = XCreateGC(dpy, win, mask, &values);
+
+ GET_NORMAL(tw,i)->used = 1;
+ GET_NORMAL(tw,i)->fore = fore;
+ GET_NORMAL(tw,i)->back = back;
+
+ return GET_NORMAL(tw,i);
+ }
+
+ return (NormalReverseGC*)NULL;
+}
+
+static void GetGCByForeground(w, gc, fore)
+ Widget w;
+ GC *gc;
+ Pixel fore;
+{
+ XGCValues values;
+
+ values.foreground = fore;
+ (*gc) = XtGetGC(w, GCForeground, &values);
+}
+
+
+static ShadowGC* GetShadowGC(w, back)
+ Widget w;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = SHADOW_INDEX(back);
+
+ while (GET_SHADOW(tw,i)->used > 0)
+ {
+ if (GET_SHADOW(tw,i)->back == back)
+ {
+ GET_SHADOW(tw,i)->used++;
+ return GET_SHADOW(tw,i);
+ }
+ i = NEXT(i);
+ }
+
+ if (GET_SHADOW(tw,i)->used == 0)
+ {
+ Pixel top;
+ Pixel bottom;
+
+ GET_SHADOW(tw,i)->used = 1;
+ GET_SHADOW(tw,i)->back = back;
+
+ (void)TopShadowColor(w, back, &top);
+ (void)BottomShadowColor(w, back, &bottom);
+#ifdef CELL_IN
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->bottom, top);
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->top, bottom);
+#else
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->bottom, bottom);
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->top, top);
+#endif
+ return GET_SHADOW(tw,i);
+ }
+
+ return (ShadowGC*)NULL;
+}
+
+static void ReleaseNormalGC(w, fore, back)
+ Widget w;
+ Pixel fore;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = NORMAL_INDEX(fore, back);
+
+ while (GET_NORMAL(tw,i)->used > 0)
+ {
+ if ( GET_NORMAL(tw,i)->fore == fore && GET_NORMAL(tw,i)->back == back)
+ {
+ if (--GET_NORMAL(tw,i)->used == 0) {
+ XFreeGC(XtDisplay(w), GET_NORMAL(tw,i)->normal);
+ XFreeGC(XtDisplay(w), GET_NORMAL(tw,i)->reverse);
+ }
+ break;
+ }
+
+ i = NEXT(i);
+ }
+}
+
+static void ReleaseShadowGC(w, back)
+ Widget w;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = SHADOW_INDEX(back);
+
+ while (GET_SHADOW(tw,i)->used > 0)
+ {
+ if ( GET_SHADOW(tw,i)->back == back)
+ {
+ if (--GET_SHADOW(tw,i)->used == 0)
+ {
+ XtReleaseGC(w, GET_SHADOW(tw,i)->top);
+ XtReleaseGC(w, GET_SHADOW(tw,i)->bottom);
+ }
+ break;
+ }
+ i = NEXT(i);
+ }
+}
+
+static void MultipleChangeGC(w, fore, back, font, normal, reverse)
+ Widget w;
+ Pixel *fore;
+ Pixel *back;
+ Font *font;
+ GC *normal;
+ GC *reverse;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (normal != (GC*)NULL){
+ mask = (XtGCMask)0;
+ if (fore != (Pixel*)NULL) {
+ mask |= GCForeground;
+ values.foreground = *fore;
+ }
+ if (back != (Pixel*)NULL) {
+ mask |= GCBackground;
+ values.background = *back;
+ }
+ if (font != (Font*)NULL) {
+ mask |= GCFont;
+ values.font = *font;
+ }
+ XChangeGC(XtDisplay(w), *normal, mask, &values);
+ }
+
+ if (reverse != (GC*)NULL){
+ mask = (XtGCMask)0;
+ if (fore != (Pixel*)NULL) {
+ mask |= GCForeground;
+ values.foreground = *back; /* reverse */
+ }
+ if (back != (Pixel*)NULL) {
+ mask |= GCBackground;
+ values.background = *fore; /* reverse */
+ }
+ if (font != (Font*)NULL) {
+ mask |= GCFont;
+ values.font = *font;
+ }
+ XChangeGC(XtDisplay(w), *reverse, mask, &values);
+ }
+}
+
+#ifndef WORD64
+
+#define TXT16 XChar2b
+
+#else
+
+#define TXT16 char
+
+static XChar2b *buf2b;
+static int buf2blen = 0;
+
+#define XTextWidth16 _XawTableWidth16
+#define XDrawString16 _XawTableDraw16
+
+#endif /* WORD64 */
+
+
+static void CalculatePreferredSize(w, width, height)
+ Widget w;
+ Dimension *width;
+ Dimension *height;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ register int wid;
+ register int hei;
+ int i;
+
+ /*
+ * Calculate preferred width
+ */
+
+ wid = 2 * (tw->table.tab_margin + tw->container.shadow_thickness);
+ wid += COLUMNS(tw) ? (COLUMNS(tw) - 1) * tw->table.col_margin : 0;
+ wid += 2 * COLUMNS(tw) * tw->table.label_shadow_thickness;
+
+ for(i = 0 ; i < COLUMNS(tw); i++)
+ wid += (Dimension)COLUMN_WIDTH(tw,i);
+
+ /*
+ * Calculate preferred height
+ */
+
+ hei = 2 * (tw->table.tab_margin + tw->container.shadow_thickness);
+ hei += ROWS(tw) ? (ROWS(tw) - 1) * tw->table.row_margin : 0;
+ hei += ROWS(tw) * tw->table.row_height;
+ hei += 2 * ROWS(tw) * tw->table.label_shadow_thickness;
+
+ tw->table.prefer_width = wid;
+ tw->table.prefer_height = hei;
+
+ if (width) *width = wid;
+ if (height) *height = hei;
+
+}
+
+static Position GetX(tw,j)
+ register XawTableWidget tw;
+ int j;
+{
+ register TablePart* table = (TablePart*)&tw->table;
+ register Position x;
+
+ x = j * (table->col_margin + 2 * table->label_shadow_thickness) +
+ (table->tab_margin + tw->container.shadow_thickness);
+
+ for(; j > 0 ; j--)
+ {
+ register int tmp = j - 1;
+ x += (Position)COLUMN_WIDTH(tw, tmp);
+ }
+ return x;
+}
+
+static Position GetY(tw,i)
+ XawTableWidget tw;
+ int i;
+{
+ return(i * (tw->table.row_margin + tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness) +
+ (tw->table.tab_margin + tw->container.shadow_thickness));
+}
+
+
+/*
+ * Calculate width and height of displayed text in pixels
+ */
+
+static void SetLabelHeight(tw)
+ XawTableWidget tw;
+{
+ register XFontStruct *fs = tw->table.font;
+ int row_height = tw->table.row_height;
+
+ if (tw->table.row_height < 1)
+ tw->table.row_height = (fs->max_bounds.ascent +
+ fs->max_bounds.descent +
+ 2 * tw->table.internal_height);
+ if (row_height != tw->table.row_height)
+ {
+ XawTableCallbackStruct callback_str;
+ callback_str.reason = XawTABLE_CHANGED_ROW_HEIGHT;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK((Widget)tw, XtNchangedRowHeight, callback_str);
+ }
+}
+
+static void SetLiteralWidth(tw)
+ XawTableWidget tw;
+{
+ if (tw->table.encoding)
+ tw->table.literal_width = XTextWidth16(tw->table.font, (TXT16*)"mmm", 3);
+ else
+ tw->table.literal_width = XTextWidth(tw->table.font, "mmm", 3);
+
+ tw->table.literal_width /= 3;
+}
+
+
+static void SetLabelWidth(tw,i,j)
+ XawTableWidget tw;
+ int i,j;
+{
+ register XFontStruct *fs = tw->table.font;
+ XawTableCell cell;
+
+ cell = (XawTableCell)get_cell(STUFF(tw),i,j);
+
+ if (CELL(label) == NULL) {
+ CELL(label_len) = 0;
+ CELL(label_width) = 0;
+ } else {
+ CELL(label_len) = strlen(CELL(label));
+ if (tw->table.encoding)
+ CELL(label_width) =
+ XTextWidth16(fs, (TXT16*)CELL(label), (int) CELL(label_len)/2);
+ else
+ CELL(label_width) =
+ XTextWidth(fs, CELL(label), (int) CELL(label_len));
+ }
+}
+
+
+static void CreateTableCellGC(w)
+ Widget w;
+{
+ Display *dpy = XtDisplay(w);
+ Drawable d = XtWindow(w);
+ XawTableWidget tw = (XawTableWidget)w;
+
+ tw->table.normal = XCreateGC(dpy, d, (XtGCMask)0, (XGCValues*)NULL);
+ tw->table.reverse = XCreateGC(dpy, d, (XtGCMask)0, (XGCValues*)NULL);
+
+ MultipleChangeGC(w,
+ (Pixel*)&tw->table.foreground,
+ (Pixel*)&tw->core.background_pixel,
+ (Font*)&tw->table.font->fid,
+ (GC*)&tw->table.normal,
+ (GC*)&tw->table.reverse);
+
+}
+
+static void DrawColumns(tw, b_column, e_column)
+ XawTableWidget tw;
+ int b_column, e_column;
+{
+ int j,y;
+
+ y = (int)GetY(tw,0);
+ for(j = MAX(b_column,0); j <= MIN(e_column, COLUMNS(tw) - 2); j++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.column_gc,
+ (int) (GetX(tw,j+1) - tw->table.col_margin),
+ y,
+ (unsigned int) tw->table.col_margin,
+ (unsigned int)(tw->table.prefer_height-(2*y)));
+
+ }
+}
+
+static void DrawRows(tw, b_row, e_row)
+ XawTableWidget tw;
+ int b_row, e_row;
+{
+ int i,x;
+
+ x = (int)GetX(tw,0);
+ for(i = MAX(b_row, 0); i <= MIN(e_row, ROWS(tw) - 2); i++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.row_gc,
+ x,
+ (int) (GetY(tw,i+1) - tw->table.row_margin),
+ (unsigned int) (tw->table.prefer_width-(2*x)),
+ (unsigned int) tw->table.row_margin);
+
+ }
+}
+
+static void DrawCage(tw, b_row, e_row, b_column, e_column)
+ XawTableWidget tw;
+ int b_row, e_row, b_column, e_column;
+{
+ int i,j;
+ Display* dpy = XtDisplay((Widget)tw);
+ Window win = XtWindow((Widget)tw);
+
+ if (tw->table.row_oriented)
+ {
+ if (tw->table.col_margin > (Dimension)0)
+ {
+ DrawRows(tw, b_row - 1, e_row);
+
+ for(i = b_row; i <= MIN(e_row,ROWS(tw) - 1); i++)
+ {
+ int y = (int) GetY(tw,i);
+
+ for(j = MAX(b_column - 1, 0); j <= MIN(e_column, COLUMNS(tw) - 2); j++)
+ {
+ XFillRectangle (dpy,
+ win,
+ tw->table.column_gc,
+ (int) (GetX(tw, j + 1) - tw->table.col_margin),
+ y,
+ (unsigned int) tw->table.col_margin,
+ (unsigned int) (tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness));
+
+ }
+ }
+ }
+ }
+ else
+ {
+ if (tw->table.row_margin > (Dimension)0)
+ {
+ DrawColumns(tw, b_column - 1, e_column);
+
+ for(j = b_column; j <= MIN(e_column, COLUMNS(tw) - 1); j++)
+ {
+ int x = (int) GetX(tw,j);
+
+ for(i = MAX(b_row - 1, 0); i <= MIN(e_row, ROWS(tw) - 2); i++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.row_gc,
+ x,
+ (int) (GetY(tw,i+1) - tw->table.row_margin),
+ (unsigned int) (COLUMN_WIDTH(tw,j) +
+ 2 * tw->table.label_shadow_thickness),
+ (unsigned int) tw->table.row_margin);
+ }
+ }
+ }
+ }
+}
+
+static void Reposition(tw, cell, i, j)
+ register XawTableWidget tw;
+ XawTableCell cell;
+ int i,j;
+{
+ Position newPos;
+ XtJustify justify;
+
+ if (cell == NULL)
+ cell = (XawTableCell)get_cell(STUFF(tw),i,j);
+
+ if (COLUMN_DATA(tw)[j].flag & _CL_justify)
+ justify = COLUMN_DATA(tw)[j].justify;
+ else
+ justify = tw->table.justify;
+
+ switch (justify) {
+ case XtJustifyLeft : newPos = tw->table.internal_width;
+ break;
+ case XtJustifyRight : newPos = (COLUMN_WIDTH(tw,j) -
+ CELL(label_width) -
+ tw->table.internal_width);
+ break;
+ case XtJustifyCenter :
+ default : newPos = (COLUMN_WIDTH(tw,j) -
+ CELL(label_width)) / 2;
+ break;
+ }
+
+ CELL(label_x) = MAX(newPos, tw->table.internal_width);
+}
+
+/* ARGSUSED */
+static Boolean DeleteCell(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableCell cell = (XawTableCell)call_data;
+
+
+ if (CELL(label) != (char*)NULL)
+ XtFree(CELL(label));
+
+ if (CELL(special_colour))
+ {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ return False;
+}
+
+
+static void UpdateTable(tw)
+ XawTableWidget tw;
+{
+ Dimension width;
+ Dimension height;
+
+ if (tw->table.no_refigure > 0)
+ return;
+
+ CalculatePreferredSize((Widget)tw, &width, &height);
+
+ tw->table.was_resized = False;
+
+ (void)XtMakeResizeRequest((Widget)tw, width, height,
+ (Dimension*)NULL, (Dimension*)NULL);
+ if (tw->table.was_resized == False)
+ {
+ tw->table.was_resized = True;
+ (*tableClassRec.core_class.resize) ((Widget)tw);
+ }
+}
+
+
+static int SetTableSize(w, rows, columns)
+ Widget w;
+ int rows;
+ int columns;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ int i;
+
+ if (rows < 0 || columns < 0) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetTableSize", "SetTableSize","XawToolkitError",
+ "rows or columns for a new table in TableWidget '%s' less then zero",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (STUFF(tw))
+ {
+ callback_str.reason = XawTABLE_ALLOW_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = STUFF(tw);
+ callback_str.new_cell = STUFF(tw);
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteTable, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+ callback_str.reason = XawTABLE_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = STUFF(tw);
+ callback_str.new_cell = STUFF(tw);
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK (w, XtNdeleteTable, callback_str);
+
+ WalkForCells (w, (XawTableProc)DeleteCell,
+ 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ delete_table ((XtPointer)STUFF(tw));
+
+ STUFF(tw) = (XawTableCell)NULL;
+ ROWS(tw) = 0;
+ COLUMNS(tw) = 0;
+ }
+
+ if (rows == 0 || columns == 0)
+ return ACCEPT;
+
+ STUFF(tw) = (XawTableCell)
+ create_table(rows, columns, sizeof(XawTableCellRec));
+
+ if (STUFF(tw) == (XawTableCell)NULL)
+ return ACCEPT;
+
+ ROWS(tw) = rows;
+ COLUMNS(tw) = columns;
+
+ WalkForCells((Widget)tw, (XawTableProc)InitCell, 0, rows-1, 0, columns-1);
+
+ if (COLUMNS(tw)) {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)COLUMN_DATA(tw),
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ for (i = 0; i < COLUMNS(tw); i++)
+ COLUMN_DATA(tw)[i].flag = 0;
+ }
+ else {
+ XtFree((XtPointer)tw->table.column_data);
+ tw->table.column_data = NULL;
+ }
+
+ callback_str.reason = XawTABLE_CREATE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNcreateTable, callback_str);
+
+ return ACCEPT;
+}
+
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request;
+ Widget new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ register XawTableWidget tw = (XawTableWidget) new;
+ Dimension width;
+ Dimension height;
+ int i;
+
+ tw->table.no_refigure = 0;
+ tw->table.no_redraw = 0;
+ tw->table.num_selections = 0;
+ tw->table.cell_own = (XawTableCell)NULL;
+ STUFF(tw) = (XawTableCell)NULL;
+ tw->table.normal = (GC)NULL;
+ tw->table.reverse = (GC)NULL;
+
+ COLUMNS(tw) = MAX (COLUMNS(tw), 0);
+ ROWS(tw) = MAX (ROWS(tw), 0);
+
+ if (COLUMNS(tw)) {
+ tw->table.column_data = (XawTableColumn)
+ CALLOC (COLUMNS(tw), XawTableColumnRec);
+ for (i = 0; i < COLUMNS(tw); i++)
+ COLUMN_DATA(tw)[i].flag = 0;
+ }
+ else
+ tw->table.column_data = NULL;
+
+ SetLiteralWidth(tw);
+
+ EDIT(tw) = XtVaCreateWidget
+ ("edit", asciiTextWidgetClass, new,
+ XtNeditType, XawtextEdit,
+ XtNforeground, tw->table.edit_fore,
+ XtNbackground, tw->table.edit_back,
+ XtNborderWidth, (XtArgVal)0,
+ XtNleftMargin, 2,
+ XtNrightMargin, 2,
+ XtNtopMargin, 0, /* to be fixed in future */
+ XtNbottomMargin, 0, /* to be fixed in future */
+ XtNuseStringInPlace, False,
+ XtNfont, tw->table.font,
+ XtNuserData, (XtArgVal)new,
+ NULL);
+
+ XtOverrideTranslations(EDIT(tw), XtParseTranslationTable(edit_translations));
+
+ GetGCByForeground (new, (GC*)&tw->table.row_gc, tw->table.row_fore);
+ GetGCByForeground (new, (GC*)&tw->table.column_gc, tw->table.column_fore);
+
+ if ((COLUMNS(tw) > 0) && (ROWS(tw) > 0))
+ {
+ if (REJECT == SetTableSize(new, ROWS(tw), COLUMNS(tw)))
+ {
+ ROWS(tw) = 0;
+ COLUMNS(tw) = 0;
+ STUFF(tw) = (XawTableCell)NULL;
+ }
+ }
+
+ if ((tw->table.mask_number < 0)
+ || (tw->table.mask_number >= XtNumber(MaskStaticArray)))
+ tw->table.mask_number = 7;
+
+ tw->table.mask_hash_table = MaskStaticArray[tw->table.mask_number];
+
+ tw->table.normal_hash_table =
+ CALLOC(tw->table.mask_hash_table, NormalReverseGC);
+
+ tw->table.shadow_hash_table = CALLOC(tw->table.mask_hash_table, ShadowGC);
+
+ for(i = 0; i < tw->table.mask_hash_table; i++)
+ {
+ GET_NORMAL(tw,i)->used = 0;
+ GET_NORMAL(tw,i)->normal = (GC)NULL;
+ GET_NORMAL(tw,i)->reverse = (GC)NULL;
+ GET_SHADOW(tw,i)->used = 0;
+ GET_SHADOW(tw,i)->top = (GC)NULL;
+ GET_SHADOW(tw,i)->bottom = (GC)NULL;
+ }
+
+ SetLabelHeight(tw);
+
+ CalculatePreferredSize(new, &width, &height);
+
+ if (new->core.width == 0) new->core.width = width;
+ if (new->core.height == 0) new->core.height = height;
+}
+
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ ShadowGC *shadow;
+
+ (*SuperClass->core_class.realize) (w, valueMask, attributes);
+
+ CreateTableCellGC(w);
+
+ shadow = GetShadowGC(w, tw->table.edit_back);
+ tw->table.edit_top = shadow->top;
+ tw->table.edit_bottom = shadow->bottom;
+
+ shadow = GetShadowGC(w, tw->core.background_pixel);
+ tw->table.top = shadow->top;
+ tw->table.bottom = shadow->bottom;
+
+ XtRealizeWidget(EDIT(w));
+}
+
+/* ARGSUSED */
+static Boolean MatchLabel(w, i, j, call_data, client_data)
+ Widget w; /* unused */
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ XawTableCell cell = (XawTableCell)call_data;
+ XrmQuark* templ = (XrmQuark*)client_data;
+
+ return ((*templ) == XrmStringToQuark (GET_CELL_LABEL));
+}
+
+/* ARGSUSED */
+static Boolean InitCell(p, i, j, call_data, client_data)
+ XtPointer p; /* unused */
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ XawTableCell cell = (XawTableCell)call_data;
+
+ CELL(label) = DummyString();
+ CELL(label_len) = 0;
+ CELL(label_width) = 0;
+ CELL(highlight) = False;
+ CELL(special_colour) = False;
+ CELL(normal) = (GC)NULL;
+ CELL(reverse) = (GC)NULL;
+ CELL(top) = (GC)NULL;
+ CELL(bottom) = (GC)NULL;
+
+ return False;
+}
+
+/*
+ *
+ * Shadow drawing around cell
+ *
+ */
+static void PaintShadow(w, i, j, x, y, cell)
+ Widget w;
+ int i;
+ int j;
+ Position x;
+ Position y;
+ XawTableCell cell;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+
+ if (tw->table.label_shadow_thickness != (Dimension)0) {
+ GC top,bottom;
+
+ if (IsEditInRowColumn(tw,i,j))
+ {
+ top = tw->table.edit_bottom;
+ bottom = tw->table.edit_top;
+ }
+ else if (CELL(special_colour))
+ {
+ top = CELL(top);
+ bottom = CELL(bottom);
+ }else {
+ top = tw->table.top;
+ bottom = tw->table.bottom;
+ }
+
+ XawDrawFrame(w,
+ x,
+ y,
+ (Dimension)(COLUMN_WIDTH(tw,j) +
+ 2 * tw->table.label_shadow_thickness),
+ (Dimension)(tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness),
+ XawRAISED,
+ tw->table.label_shadow_thickness,
+ top,
+ bottom);
+ }
+
+}
+
+/* ARGSUSED */
+static void PaintLabel(w, i, j, x, y, cell)
+ Widget w;
+ int i;
+ int j;
+ Position x,y;
+ XawTableCell cell;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XRectangle rectangle[1];
+ Position label_x;
+ Position label_y;
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,j);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ x += tw->table.label_shadow_thickness;
+ y += tw->table.label_shadow_thickness;
+
+ if (CELL(special_colour) || CELL(highlight))
+ {
+ GC gc;
+
+ if (CELL(special_colour))
+ gc = CELL(highlight) ? CELL(normal) : CELL(reverse);
+ else
+ gc = tw->table.normal ;
+
+ /* Fill background for cell with a special colour */
+ XFillRectangle(XtDisplay(w), XtWindow(w), gc,
+ (int)x, (int)y, width, height);
+ }
+ else
+ {
+ XClearArea (XtDisplay(w), XtWindow(w), (int)x, (int)y,
+ width, height, FALSE);
+ }
+
+ if (CELL(label_len) > 0)
+ {
+ GC gc;
+ register XFontStruct *fs = tw->table.font;
+
+ if (CELL(special_colour))
+ gc = CELL(highlight) ? CELL(reverse) : CELL(normal);
+ else
+ gc = CELL(highlight) ? tw->table.reverse : tw->table.normal;
+
+ /* Set clip rectangle for label in cell */
+ rectangle[0].x = (short)x;
+ rectangle[0].y = (short)y;
+ rectangle[0].width = (unsigned short)COLUMN_WIDTH(tw,j);
+ rectangle[0].height = (unsigned short)tw->table.row_height;
+
+ XSetClipRectangles(XtDisplay(w), gc, 0, 0, rectangle, 1, YSorted);
+
+ /* Drawing label */
+ label_x = x + CELL(label_x);
+ label_y = y +
+ (tw->table.row_height-(fs->max_bounds.ascent+fs->max_bounds.descent))/2
+ /* tw->table.internal_height */
+ + fs->max_bounds.ascent;
+
+ if (tw->table.encoding)
+ XDrawString16(XtDisplay(w), XtWindow(w), gc,
+ label_x, label_y, (TXT16*)CELL(label),
+ (int)CELL(label_len)/2);
+ else
+ XDrawString(XtDisplay(w), XtWindow(w), gc,
+ label_x, label_y, CELL(label), (int)CELL(label_len));
+
+ XSetClipMask(XtDisplay(w), gc, (Pixmap)None);
+
+ }
+}
+
+/* ARGSUSED */
+static Boolean PaintCell(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell = (XawTableCell) call_data;
+ Position x;
+ Position y;
+
+ x = GetX(tw,j);
+ y = GetY(tw,i);
+
+ PaintLabel (w, i, j, x, y, cell);
+ PaintShadow (w, i, j, x, y, cell);
+
+ XFlush(XtDisplay(w));
+ return False;
+}
+
+static void WhatCellsToBeDraw(tw, rect, b_row, e_row, b_column , e_column)
+ XawTableWidget tw;
+ XRectangle rect;
+ register int *b_row, *e_row, *b_column , *e_column;
+{
+ Position x1 = (Position)rect.x,
+ y1 = (Position)rect.y,
+ x2 = (Position)(rect.x + rect.width - 1),
+ y2 = (Position)(rect.y + rect.height - 1);
+
+ for ((*b_column) = 0; (*b_column) < COLUMNS(tw); (*b_column)++)
+ {
+ if (x1 < (GetX(tw,(*b_column) + 1) - tw->table.col_margin)) {
+ /* Added to fix scrolling bug in Viewport parent. MJF 9/6/02
+ */
+ *b_column = MAX (0, *b_column-1);
+ break;
+ }
+ }
+
+ for ((*e_column) = (*b_column); (*e_column) < COLUMNS(tw); (*e_column)++)
+ {
+ if (x2 < (GetX(tw,(*e_column) + 1) - tw->table.col_margin))
+ break;
+ }
+
+
+ for ((*b_row) = 0; (*b_row) < ROWS(tw); (*b_row)++)
+ {
+ if (y1 < (GetY(tw,(*b_row) + 1) - tw->table.row_margin)) {
+ /* Added to fix scrolling bug in Viewport parent. MJF 9/6/02
+ */
+ *b_row = MAX (0, *b_row-1);
+ break;
+ }
+ }
+
+ for ((*e_row) = (*b_row); (*e_row) < ROWS(tw); (*e_row)++)
+ {
+ if (y2 < (GetY(tw,(*e_row) + 1) - tw->table.row_margin))
+ break;
+ }
+}
+
+
+static void Redisplay(w, event, region)
+ Widget w;
+ XEvent *event;
+ Region region;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XRectangle rect;
+ int b_row, e_row, b_column , e_column ;
+
+
+ if (!XtIsRealized(w) || !w->core.visible || tw->table.no_redraw)
+ return;
+
+ if (tw->container.shadow_thickness > 0)
+ (*SuperClass->core_class.expose) (w, event, region);
+
+ if (region != NULL)
+ {
+ XClipBox(region, (XRectangle*)&rect);
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ rect.x = (short) event->xexpose.x;
+ rect.y = (short) event->xexpose.y;
+ rect.width = (unsigned short) event->xexpose.width;
+ rect.height = (unsigned short) event->xexpose.height;
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+
+ /* The following is necessary so the table gets redrawn properly
+ * when being managed by e.g. a Viewport widget. MJF 9/6/02
+ */
+ XawTableDoLayout (w, TRUE);
+ }
+ else if (tw->table.v_scroll || tw->table.h_scroll)
+ {
+ rect.x = (short) 0;
+ rect.y = (short) 0;
+ rect.width = (unsigned short) tw->core.width;
+ rect.height = (unsigned short) tw->core.height;
+
+ if (tw->table.v_scroll && XtIsManaged(tw->table.v_scroll))
+ {
+ float top;
+ float shown;
+
+ XtVaGetValues (tw->table.v_scroll,
+ XtNtopOfThumb, &top,
+ XtNshown, &shown,
+ NULL);
+
+ rect.y = (short) ((float)(tw->core.height) * top);
+ rect.height = (unsigned short) ((float)(tw->core.height) * (top+shown));
+ }
+
+ if (tw->table.h_scroll && XtIsManaged(tw->table.h_scroll))
+ {
+ float top;
+ float shown;
+
+ XtVaGetValues (tw->table.h_scroll,
+ XtNtopOfThumb, &top,
+ XtNshown, &shown,
+ NULL);
+
+ rect.x = (short) ((float)(tw->core.width) * top);
+ rect.width = (unsigned short) ((float)(tw->core.width) * (top+shown));
+ }
+
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+ }
+ else
+ {
+ b_row = 0;
+ e_row = ROWS(tw) - 1;
+ b_column = 0;
+ e_column = COLUMNS(tw) - 1;
+ }
+
+ DrawCage(tw, b_row, e_row, b_column, e_column);
+
+ WalkForCells(w, (XawTableProc)PaintCell, b_row, e_row, b_column, e_column);
+
+ XFlush(XtDisplay(w));
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current;
+ Widget request; /* unused */
+ Widget new;
+ ArgList args; /* unused */
+ Cardinal *num_args; /* unused */
+{
+ XawTableWidget curtw = (XawTableWidget) current;
+ XawTableWidget newtw = (XawTableWidget) new;
+ register int i;
+ int j;
+ Boolean resize = False;
+ Boolean redisplay = False;
+
+#define NE(field) (curtw->table.field != newtw->table.field)
+
+ if (NE(mask_number))
+ XtWarning("Resource XtNmaskNumber in Table widget can not changed");
+
+ newtw->table.mask_number = curtw->table.mask_number;
+ newtw->table.literal = curtw->table.literal;
+
+ if (NE(font->fid))
+ XtVaSetValues (EDIT(newtw), XtNfont, curtw->table.font, NULL);
+
+ if (NE(foreground) ||
+ NE(row_fore) ||
+ NE(column_fore) ||
+ NE(row_oriented) ||
+ NE(font->fid) ||
+ NE(justify) ||
+ NE(tab_margin) ||
+ NE(row_margin) ||
+ NE(col_margin) ||
+ NE(internal_width) ||
+ NE(internal_height) ||
+ NE(label_shadow_thickness) ||
+ NE(encoding))
+ redisplay = True;
+
+ if (NE(font->fid) ||
+ NE(columns) ||
+ NE(rows) ||
+ NE(tab_margin) ||
+ NE(row_margin) ||
+ NE(col_margin) ||
+ NE(internal_width) ||
+ NE(internal_height) ||
+ NE(row_height) ||
+ NE(label_shadow_thickness))
+ resize = True;
+
+ if (NE(columns) || NE(rows))
+ if (REJECT == SetTableSize(new, ROWS(newtw), COLUMNS(newtw))) {
+ newtw->table.columns = curtw->table.columns;
+ newtw->table.rows = curtw->table.rows;
+ }
+
+ if(NE(row_height))
+ {
+ XawTableCallbackStruct callback_str;
+ callback_str.reason = XawTABLE_CHANGED_ROW_HEIGHT;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(new, XtNchangedRowHeight, callback_str);
+ }
+
+ if(NE(font->fid))
+ {
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ SetLabelWidth(newtw, i, j);
+
+ SetLabelHeight(newtw);
+ }
+
+ if(NE(font->fid) || NE(encoding))
+ {
+ SetLiteralWidth(newtw);
+
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ Reposition(newtw, NULL, i, j);
+ }
+ else if(NE(internal_width) || NE(label_shadow_thickness)) {
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ Reposition(newtw, NULL, i, j);
+ }
+
+
+ if (NE(internal_height) || NE(label_shadow_thickness))
+ {
+ SetLabelHeight(newtw);
+ }
+
+ if (resize)
+ CalculatePreferredSize(new, &newtw->core.width, &newtw->core.height);
+
+ if (NE(foreground) || NE(font->fid) ||
+ curtw->core.background_pixel != newtw->core.background_pixel)
+ {
+ MultipleChangeGC(new,
+ (Pixel*)&newtw->table.foreground,
+ (Pixel*)&newtw->core.background_pixel,
+ (Font*)&newtw->table.font->fid,
+ (GC*)&newtw->table.normal,
+ (GC*)&newtw->table.reverse);
+
+ }
+
+ if (NE(row_fore))
+ {
+ XtReleaseGC(new, curtw->table.row_gc);
+ GetGCByForeground(new,(GC*)&newtw->table.row_gc, newtw->table.row_fore);
+ }
+
+ if (NE(column_fore))
+ {
+ XtReleaseGC(new, curtw->table.column_gc);
+ GetGCByForeground(new, &newtw->table.column_gc,newtw->table.column_fore);
+ }
+
+ if (resize)
+ CalculatePreferredSize(new, &(new->core.width), &(new->core.height));
+
+ return redisplay;
+}
+
+
+static void Destroy(w)
+ Widget w;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) != (XawTableCell)NULL)
+ {
+ callback_str.reason = XawTABLE_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNdeleteTable, callback_str);
+ }
+
+ if (tw->table.row_gc != (GC)NULL) {
+ XtReleaseGC(w, tw->table.row_gc);
+ tw->table.row_gc = (GC)NULL;
+ }
+ if (tw->table.column_gc != (GC)NULL) {
+ XtReleaseGC(w, tw->table.column_gc);
+ tw->table.column_gc = (GC)NULL;
+ }
+ if (tw->table.normal != (GC)NULL) {
+ XFreeGC(XtDisplay(w), tw->table.normal);
+ tw->table.normal = (GC)NULL;
+ }
+
+ if (tw->table.reverse != (GC)NULL) {
+ XFreeGC(XtDisplay(w), tw->table.reverse);
+ tw->table.reverse = (GC)NULL;
+ }
+
+ WalkForCells(w, (XawTableProc)DeleteCell, 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ XtFree((XtPointer)tw->table.normal_hash_table);
+ XtFree((XtPointer)tw->table.shadow_hash_table);
+
+ delete_table(tw->table.table_stuff);
+ STUFF(tw) = (XawTableCell)NULL;
+
+ if (tw->table.column_data != NULL)
+ XtFree((XtPointer)tw->table.column_data);
+
+ if (EDIT(w) != WNULL && !EDIT(w)->core.being_destroyed)
+ XtDestroyWidget(EDIT(w));
+}
+
+
+static void Resize(w)
+ Widget w;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ /* If widget is realized, just redisplay it w/o clearing */
+ if (XtIsRealized(w) && tw->table.no_redraw == 0)
+ {
+ /* XClearWindow(XtDisplay(w), XtWindow(w)); */
+ (*tableClassRec.core_class.expose) (w, (XEvent*)NULL,(Region)NULL);
+ }
+
+ tw->table.was_resized = True;
+}
+
+
+static XtGeometryResult QueryGeometry(w, intended, preferred)
+ Widget w;
+ XtWidgetGeometry *intended, *preferred;
+{
+ preferred->request_mode = CWWidth | CWHeight;
+
+ CalculatePreferredSize(w, &preferred->width, &preferred->height);
+
+#define Set(bit) (intended->request_mode & bit)
+
+ if (Set(CWWidth) && intended->width == preferred->width &&
+ Set(CWHeight) && intended->height == preferred->height) {
+ return XtGeometryYes;
+ }
+
+ if (preferred->width == w->core.width &&
+ preferred->height == w->core.height) {
+ return XtGeometryNo;
+ }
+
+ return XtGeometryAlmost;
+
+#undef Set
+}
+
+/* ARGSUSED */
+static XtGeometryResult GeometryManager(w, desired, allowed)
+ Widget w;
+ XtWidgetGeometry *desired;
+ XtWidgetGeometry *allowed;
+{
+ return XtGeometryYes;
+}
+
+
+
+static void ExtractPosition(event, x, y , t)
+ XEvent *event;
+ Position *x, *y; /* RETURN */
+ Time *t; /* RETURN */
+{
+ if (event == NULL)
+ return;
+
+ switch(event->type) {
+ case MotionNotify:
+ *x = event->xmotion.x;
+ *y = event->xmotion.y;
+ *t = event->xmotion.time;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x;
+ *y = event->xbutton.y;
+ *t = event->xbutton.time;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x;
+ *y = event->xkey.y;
+ *t = event->xkey.time;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x;
+ *y = event->xcrossing.y;
+ *t = event->xcrossing.time;
+ break;
+ default:
+ *x = 0;
+ *y = 0;
+ *t = XtLastTimestampProcessed(event->xany.display);
+ }
+}
+
+/* ARGSUSED */
+static Boolean ExtractCell(tw, px, py, row, column)
+ XawTableWidget tw;
+ Position px,py;
+ int *row, *column; /* RETURN */
+{
+ Position x;
+ Position y;
+#define SH (tw->table.label_shadow_thickness)
+ for(*row = 0; *row < ROWS(tw); (*row)++) {
+ for(*column = 0; *column < COLUMNS(tw); (*column)++)
+ if ((x=GetX(tw,*column)+SH) <= px)
+ if ((y=GetY(tw,*row)+SH) <= py)
+ if ((x+COLUMN_WIDTH(tw,*column)) >= px)
+ if ((y+tw->table.row_height) >= py)
+ return False;
+ }
+#undef SH
+
+ return True;
+}
+
+
+/* ARGSUSED */
+static void WalkForCells(w, proc, b_r, e_r, b_c, e_c)
+ Widget w;
+ XawTableProc proc;
+ int b_r, e_r, b_c, e_c;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int i,j;
+
+ (void)go_table((XtPointer)w, proc, STUFF(tw),
+ b_r, e_r, b_c, e_c,
+ XawTABLE_RIGHT_DOWN,
+ &i, &j, (XtPointer)NULL);
+}
+
+static char* DummyString()
+{
+ return XtNewString("");
+}
+
+static char* CopyOnlyPrintable(raw)
+ char* raw;
+{
+ char* clear;
+ char *s,*h;
+ int lenght;
+
+ for(s = raw, lenght = 0; (*s) != '\0';)
+ {
+ if (isprint(*s++))
+ lenght++;
+ }
+
+ clear = CALLOC(++lenght, char);
+
+ for(s = raw, h = clear; (*s) != '\0';)
+ {
+ if (isprint(*s))
+ (*h++) = (*s++);
+ }
+
+ (*h) = '\0';
+
+ return clear;
+}
+
+#ifdef EBUG_XRAW_MALLOC
+/* ARGSUSED */
+static Boolean CheckLabel(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) p;
+ XawTableCell cell = (XawTableCell)call_data;
+ char* label = CELL(label);
+
+ for (label = CELL(label); *label != '\0'; label++)
+ if (!isprint(*label))
+ {
+ char message[80];
+ char *p = NULL;
+ sprintf(message, "wrong label '%s' in cell (%4d,%4d) in Table widget '%s'",
+ CELL(label), i, j, w->core.name);
+ XtWarning(message);
+ *p = '\0';
+ break;
+ }
+
+ return False;
+}
+#endif
+
+#ifdef EBUG_XRAW_MALLOC
+static void CheckAllLabels(tw)
+ XawTableWidget tw;
+{
+ WalkForCells((Widget)tw, (XawTableProc)CheckLabel,
+ 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+}
+#endif
+
+static void MoveEditCell (tw, row, column)
+ XawTableWidget tw;
+ int row;
+ int column;
+{
+ Position x,y;
+
+ x = GetX(tw,column);
+ y = GetY(tw,row);
+
+ XtConfigureWidget(EDIT(tw),
+ (Position)(x + tw->table.label_shadow_thickness),
+ (Position)(y + tw->table.label_shadow_thickness),
+ (Dimension) COLUMN_WIDTH(tw, column),
+ (Dimension) tw->table.row_height,
+ (Dimension)0);
+ XawDrawFrame((Widget)tw,
+ x,
+ y,
+ (Dimension)(COLUMN_WIDTH(tw, column) +
+ 2 * tw->table.label_shadow_thickness),
+ (Dimension)(tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness),
+ XawSUNKEN,
+ tw->table.label_shadow_thickness,
+ tw->table.edit_top,
+ tw->table.edit_bottom);
+
+}
+
+/* ARGSUSED */
+static Boolean CompareCells(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ XawTableCell cell = (XawTableCell)call_data;
+ XawTableCell test_cell = (XawTableCell)client_data;
+
+ return(cell == test_cell);
+}
+
+/******************************************************************
+ *
+ * CONVENIENCE FUNCTIONS
+ *
+ ******************************************************************/
+
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetSize (Widget w,
+ int *rows,
+ int *columns)
+#else
+XawTableGetSize (w, rows, columns)
+ Widget w;
+ int *rows;
+ int *columns;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ *rows = ROWS(tw);
+ *columns = COLUMNS(tw);
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableDoLayout (Widget w,
+ Boolean do_layout)
+#else
+XawTableDoLayout (w, do_layout)
+ Widget w;
+ Boolean do_layout;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (do_layout)
+ tw->table.no_redraw--;
+ else
+ tw->table.no_redraw++;
+
+ tw->table.no_redraw = MAX (tw->table.no_redraw, 0);
+
+ if (tw->table.no_redraw == 0)
+ Redisplay (w, (XEvent *)NULL, (Region)NULL);
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetNewSize (Widget w,
+ int rows,
+ int columns)
+#else
+XawTableSetNewSize (w, rows, columns)
+ Widget w;
+ int rows;
+ int columns;
+#endif
+{
+ if (REJECT == SetTableSize(w, rows, columns))
+ return REJECT;
+
+ UpdateTable((XawTableWidget)w);
+ return ACCEPT;
+}
+
+char *
+#ifdef Xraw_NEED_PROTO
+XawTableGetLabelByCell (XawTableCell cell)
+#else
+XawTableGetLabelByCell (cell)
+ XawTableCell cell;
+#endif
+{
+ return GET_CELL_LABEL;
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetEditPosition (Widget w, int *row, int *column)
+#else
+XawTableGetEditPosition(w, row, column)
+ Widget w;
+ int *row;
+ int *column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ *row = tw->table.edit_row;
+ *column = tw->table.edit_column;
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableWalk (
+ Widget w,
+ XawTableProc proc,
+ int b_row,
+ int e_row,
+ int b_column,
+ int e_column,
+ int direction,
+ int *i, /* returned */
+ int *j, /* returned */
+ XtPointer client_data)
+#else
+XawTableWalk(w, proc, b_row, e_row, b_column, e_column,
+ direction, i, j, client_data)
+ Widget w;
+ XawTableProc proc;
+ int b_row, e_row, b_column, e_column;
+ int direction;
+ int *i; /* returned */
+ int *j; /* returned */
+ XtPointer client_data;
+#endif
+{
+ return go_table((XtPointer)w, proc, STUFF(w),
+ b_row, e_row, b_column, e_column,
+ direction,
+ i, j, client_data);
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableSearchLabel (Widget w, char *name, int *row, int *column)
+#else
+XawTableSearchLabel (w, name, row, column)
+ Widget w;
+ char *name;
+ int *row, *column;
+#endif
+{
+ int row_start = *row;
+ int column_start = *column;
+ XrmQuark templ = XrmStringToQuark (name);
+
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start, row_start, column_start, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start+1, ROWS(w)-1, 0, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ 0, row_start-1, 0, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start, row_start, 0, column_start,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ return (False);
+
+}
+
+/**************************************************************
+ *
+ *
+ *
+ * ROW routines
+ *
+ *
+ *
+ **************************************************************/
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTablePrependRow (Widget w)
+#else
+XawTablePrependRow(w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "prependRow", "XawTablePrependRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_before(STUFF(tw), sizeof(XawTableCellRec));
+ ROWS(tw)++;
+
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, 0, 0, COLUMNS(tw)-1);
+
+ if (XawTableIsEditManaged(w))
+ MoveEditCell (tw, ++(tw->table.edit_row), tw->table.edit_column);
+
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableAppendRow (Widget w)
+#else
+XawTableAppendRow (w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL)
+ {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "appendRow", "XawTableAppendRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), ROWS(tw)-1, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_after(get_cell(STUFF(tw), ROWS(tw) - 1, 0),
+ sizeof(XawTableCellRec));
+
+ ROWS(tw)++;
+
+ WalkForCells(w, (XawTableProc)InitCell,
+ ROWS(tw)-1, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), ROWS(tw)-1, 0);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = ROWS(tw)-1;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableInsertRow (Widget w, int row)
+#else
+XawTableInsertRow (w, row)
+ Widget w;
+ int row;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertRow", "XawTableInsertRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (row != InRange(row, 0, ROWS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertRow", "XawTableInsertRow","XawToolkitError",
+ "Incorrect attempt to insert a row in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_before(get_cell((XtPointer)STUFF(tw), row, 0),
+ sizeof(XawTableCellRec));
+
+ ROWS(tw)++;
+
+ if (row == 0)
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, row, row, 0, COLUMNS(tw)-1);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XawTableIsEditManaged(w) && row <= tw->table.edit_row){
+ tw->table.no_redraw++;
+ MoveEditCell (tw, ++(tw->table.edit_row), tw->table.edit_column);
+ tw->table.no_redraw--;
+ }
+
+ UpdateTable(tw);
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableDeleteRow (Widget w, int row)
+#else
+XawTableDeleteRow (w, row)
+ Widget w;
+ int row;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteRow", "XawTableDeleteRow","XawToolkitError",
+ "An attempt to delete a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (row != InRange(row, 0, ROWS(tw)-1)) {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", ROWS(tw)-1);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteRow", "XawTableDeleteRow","XawToolkitError",
+ "Incorrect value of row (%s, max is %s) in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_DELETE_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNdeleteRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_DELETE_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNdeleteRow, (XtPointer)&callback_str);
+ }
+
+ /* if selections owner locates here, then disown selections */
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ {
+ Boolean have_find;
+ int i, j;
+
+ have_find = go_table((XtPointer)w, CompareCells, STUFF(tw),
+ row, row, 0, COLUMNS(tw)-1,
+ XawTABLE_RIGHT_DOWN, &i, &j,
+ (XtPointer)tw->table.cell_own);
+ if (have_find) {
+ for (; 0 < tw->table.num_selections;)
+ XtDisownSelection (w,
+ tw->table.selections[--(tw->table.num_selections)],
+ XtLastTimestampProcessed(XtDisplay(w)));
+
+ tw->table.cell_own = (XawTableCell)NULL;
+ }
+ }
+
+ if (row == 0)
+ STUFF(tw) = (XawTableCell)get_cell(STUFF(tw), 1, 0);
+
+ if (--ROWS(tw) == 0)
+ STUFF(tw) = (XawTableCell)NULL;
+
+ WalkForCells(w, (XawTableProc)DeleteCell, row, row, 0, COLUMNS(tw)-1);
+
+ row_delete(cell);
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ if (row < tw->table.edit_row){
+ MoveEditCell (tw, --(tw->table.edit_row), tw->table.edit_column);
+ }
+ else if (row == tw->table.edit_row){
+ UNMANAGE_EDIT(tw);
+ tw->table.edit_row = InRange (tw->table.edit_row, 0, ROWS(tw)-1);
+ XawTableSetEdit (w, tw->table.edit_row, tw->table.edit_column);
+ }
+ tw->table.no_redraw--;
+ }
+
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ return ACCEPT;
+}
+
+
+
+/**************************************************************
+ *
+ *
+ *
+ * COLUMN routines
+ *
+ *
+ *
+ **************************************************************/
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTablePrependColumn (Widget w, int width)
+#else
+XawTablePrependColumn (w, width)
+ Widget w;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int j;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "prependColumn", "XawTablePrependColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_before(STUFF(tw), sizeof(XawTableCellRec));
+ COLUMNS(tw)++;
+
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, ROWS(tw)-1, 0, 0);
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ for(j = COLUMNS(tw)-2; j >= 0; j--)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j+1]), (char*)&(COLUMN_DATA(tw)[j]),
+ sizeof(XawTableColumnRec));
+
+ COLUMN_DATA(tw)[0].flag |= _CL_width;
+ COLUMN_DATA(tw)[0].width = width;
+
+
+ if (XawTableIsEditManaged(w))
+ MoveEditCell (tw, tw->table.edit_row, ++(tw->table.edit_column));
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableAppendColumn (Widget w, int width)
+#else
+XawTableAppendColumn (w, width)
+ Widget w;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int j;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "addingColumn", "XawTableAppendColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, COLUMNS(tw)-1);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_after(get_cell(STUFF(tw), 0, COLUMNS(tw)-1),
+ sizeof(XawTableCellRec));
+
+ COLUMNS(tw)++;
+
+ WalkForCells(w, (XawTableProc)InitCell,
+ 0, ROWS(tw)-1, COLUMNS(tw)-1, COLUMNS(tw)-1);
+
+
+
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ COLUMN_DATA(tw)[COLUMNS(tw)-1].flag |= _CL_width;
+ COLUMN_DATA(tw)[COLUMNS(tw)-1].width = width;
+
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, COLUMNS(tw)-1);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = COLUMNS(tw)-1;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableInsertColumn (Widget w, int column, int width)
+#else
+XawTableInsertColumn(w, column, width)
+ Widget w;
+ int column;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int j;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertColumn", "XawTableInsertColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (column != InRange(column, 0, COLUMNS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertColumn", "XawTableInsertColumn","XawToolkitError",
+ "It detected incorrect value of column in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_before (get_cell ((XtPointer)STUFF(tw), 0, column),
+ sizeof(XawTableCellRec));
+ COLUMNS(tw)++;
+
+ if (column == 0)
+ STUFF(tw) = (XawTableCell) get_table (STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, ROWS(tw)-1, column, column);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ for(j = COLUMNS(tw)-2; j >= column; j--)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j+1]), (char*)&(COLUMN_DATA(tw)[j]),
+ sizeof(XawTableColumnRec));
+
+ COLUMN_DATA(tw)[column].flag |= _CL_width;
+ COLUMN_DATA(tw)[column].width = width;
+
+ /*
+ * move the edit cell
+ */
+
+ if (XawTableIsEditManaged(w) && column <= tw->table.edit_column){
+ tw->table.no_redraw++;
+ MoveEditCell (tw, tw->table.edit_row, ++(tw->table.edit_column));
+ tw->table.no_redraw--;
+ }
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableDeleteColumn (Widget w, int column)
+#else
+XawTableDeleteColumn(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int j;
+ XawTableCallbackStruct callback_str;
+
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteColumn", "XawTableDeleteColumn","XawToolkitError",
+ "An attempt to delete a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (column != InRange(column, 0, COLUMNS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteColumn", "XawTableDeleteColumn","XawToolkitError",
+ "It detected incorrect value of column in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ALLOW_DELETE_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNdeleteColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_DELETE_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNdeleteColumn, (XtPointer)&callback_str);
+ }
+
+ /* if selections owner locates here, then disown selections */
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ {
+ Boolean have_find;
+ int i, j;
+
+ have_find = go_table((XtPointer)w, CompareCells, STUFF(tw),
+ 0, ROWS(tw)-1, column, column,
+ XawTABLE_RIGHT_DOWN, &i, &j,
+ (XtPointer)tw->table.cell_own);
+ if (have_find) {
+ for (; 0 < tw->table.num_selections;)
+ XtDisownSelection (w,
+ tw->table.selections[--(tw->table.num_selections)],
+ XtLastTimestampProcessed(XtDisplay(w)));
+
+ tw->table.cell_own = (XawTableCell)NULL;
+ }
+ }
+
+ if (column == 0)
+ STUFF(tw) = (XawTableCell)get_cell(STUFF(tw), 0, 1);
+
+ if (--COLUMNS(tw) == 0)
+ STUFF(tw) = (XawTableCell)NULL;
+
+
+ WalkForCells(w, (XawTableProc)DeleteCell, 0, ROWS(tw)-1, column, column);
+
+ column_delete(cell);
+
+ /*
+ * shrink column data list
+ */
+
+ if (COLUMNS(tw) == 0) {
+ XtFree((XtPointer)tw->table.column_data);
+ tw->table.column_data = NULL;
+ }
+ else
+ {
+ for(j = column; j < COLUMNS(tw); j++)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j]),(char*)&(COLUMN_DATA(tw)[j+1]),
+ sizeof(XawTableColumnRec));
+
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+
+
+ /*
+ * shift the edit cell
+ */
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ if (column < tw->table.edit_column){
+ MoveEditCell (tw, tw->table.edit_row, --(tw->table.edit_column));
+ }
+ else if (column == tw->table.edit_column){
+ UNMANAGE_EDIT(tw);
+ tw->table.edit_column = InRange (tw->table.edit_column,0,COLUMNS(tw)-1);
+ XawTableSetEdit (w, tw->table.edit_row, tw->table.edit_column);
+ }
+ tw->table.no_redraw--;
+ }
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ return ACCEPT;
+}
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableIsEditManaged (Widget w)
+#else
+XawTableIsEditManaged (w)
+ Widget w;
+#endif
+{
+ return XtIsManaged(((XawTableWidget)w)->table.edit);
+}
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetLabel (Widget w, int row, int column, char *raw_label)
+#else
+XawTableSetLabel(w, row, column, raw_label)
+ Widget w;
+ int row;
+ int column;
+ char *raw_label;
+#endif
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ char* label = NULL;
+ XawTableCellRec new;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange(row, 0, ROWS(tw)-1)) ||
+ (column != InRange(column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetLabel", "XawTableSetLabel","XawToolkitError",
+"XawTableSetLabel\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (raw_label == (char*)NULL)
+ label = DummyString();
+ else
+ label = CopyOnlyPrintable(raw_label);
+
+ if (streq(label,CELL(label))) {
+ XtFree(label); /* XtMalloc in CopyOnlyPrintable */
+ return ACCEPT;
+ }
+
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.label = label;
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it != True) {
+ XtFree(label);
+ return REJECT;
+ }
+
+
+ if (CELL(label))
+ XtFree(CELL(label));
+
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ SetLabelWidth (tw, row, column);
+ Reposition (tw, cell, row, column);
+
+ if (IsEditInRowColumn (tw, row, column))
+ {
+ XtVaSetValues (EDIT(w), "string", CELL(label), NULL);
+ }
+ else if (XtIsRealized (w) && w->core.visible && !tw->table.no_redraw)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ XClearArea (XtDisplay(w), XtWindow(w), x, y, width, height, FALSE);
+ (void) PaintCell (w, row, column, (XtPointer)cell, (XtPointer)NULL);
+ }
+ return ACCEPT;
+}
+
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellColours (Widget w, int row, int column,
+ Pixel fore, Pixel back)
+#else
+XawTableSetCellColours (w, row, column, fore, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel fore;
+ Pixel back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellColours","XawToolkitError",
+"XawTableSetCellColours\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return REJECT;
+ }
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && fore == CELL(fore) && back == CELL(back))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.back = back;
+ new.fore = fore;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, fore, back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible &&
+ !tw->table.no_redraw && !tw->table.no_refigure) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, fore, back);
+ ReleaseShadowGC(w, back);
+ return REJECT;
+ }
+}
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellDefaultColours (Widget w, int row, int column)
+#else
+XawTableSetCellDefaultColours (w, row, column)
+ Widget w;
+ int row;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellDefaultColours","XawToolkitError",
+"XawTableSetCellDefaultColours\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (!CELL(special_colour))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = False;
+ new.fore = tw->table.foreground;
+ new.back = tw->core.background_pixel;
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ return REJECT;
+ }
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellBackground (Widget w, int row, int column, Pixel back)
+#else
+XawTableSetCellBackground (w, row, column, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellBackground","XawToolkitError",
+"XawTableSetCellBackground\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && back == CELL(back))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.back = back;
+
+ if (!CELL(special_colour))
+ new.fore = tw->table.foreground;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, new.fore, back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, new.fore, back);
+ ReleaseShadowGC(w, back);
+ return REJECT;
+ }
+
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellForeground (Widget w, int row, int column, Pixel fore)
+#else
+XawTableSetCellForeground (w, row, column, fore)
+ Widget w;
+ int row;
+ int column;
+ Pixel fore;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellBackground","XawToolkitError",
+"XawTableSetCellBackground\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && fore == CELL(fore))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.fore = fore;
+
+ if (!CELL(special_colour))
+ new.back = tw->core.background_pixel;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, fore, new.back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, new.back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, fore, new.back);
+ ReleaseShadowGC(w, new.back);
+ return REJECT;
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetCellColours (Widget w, int row, int column,
+ Pixel *fore, Pixel *back)
+#else
+XawTableGetCellColours (w, row, column, fore, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel *fore;
+ Pixel *back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+
+ if (cell && cell->special_colour) {
+ *fore = cell->fore;
+ *back = cell->back;
+ }
+ else {
+ *fore = tw->table.foreground;
+ *back = tw->core.background_pixel;
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetCellColoursByCell (Widget w, XawTableCell cell,
+ Pixel *fore, Pixel *back)
+#else
+XawTableGetCellColoursByCell (w, cell, fore, back)
+ Widget w;
+ XawTableCell cell;
+ Pixel *fore;
+ Pixel *back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (cell && cell->special_colour) {
+ *fore = cell->fore;
+ *back = cell->back;
+ }
+ else {
+ *fore = tw->table.foreground;
+ *back = tw->core.background_pixel;
+ }
+}
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Defaults #*/
+/*# #*/
+/*#########################################################################*/
+
+#ifdef notdef
+/* ARGSUSED */
+static Boolean PaintCellWithClear(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell = (XawTableCell) call_data;
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,j);
+ unsigned int height = (unsigned int) tw->table.row_height;
+ Position x;
+ Position y;
+
+
+ x = GetX(tw,j);
+ y = GetY(tw,i);
+
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+
+ PaintLabel (w, i, j, x, y, cell);
+ PaintShadow (w, i, j, x, y, cell);
+
+ XFlush(XtDisplay(w));
+ return False;
+}
+#endif
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetColumnJustify (Widget w, int column, XtJustify justify)
+#else
+XawTableSetColumnJustify (w, column, justify)
+ Widget w;
+ int column;
+ XtJustify justify;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int i, j;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return;
+
+ COLUMN_DATA(tw)[column].flag |= _CL_justify;
+ COLUMN_DATA(tw)[column].justify = justify;
+
+ for(i = 0; i < ROWS(tw); i++)
+ Reposition(tw, NULL, i, column);
+
+ if (XtIsRealized(w) && w->core.visible &&
+ !tw->table.no_redraw && !tw->table.no_refigure)
+ {
+ (void)go_table((XtPointer)w, PaintCell, STUFF(tw),
+ 0, ROWS(tw)-1, column, column,
+ XawTABLE_DOWN_RIGHT,
+ &i, &j, (XtPointer)NULL);
+ XFlush(XtDisplay(w));
+ }
+}
+
+
+XtJustify
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnJustify (Widget w, int column)
+#else
+XawTableGetColumnJustify (w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return XtJustifyCenter;
+
+ if (COLUMN_DATA(tw)[column].flag & _CL_justify)
+ return COLUMN_DATA(tw)[column].justify;
+
+ return XtJustifyCenter;
+}
+
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetColumnWidth (Widget w, int column, int width)
+#else
+XawTableSetColumnWidth(w, column, width)
+ Widget w;
+ int column;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ register int row;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return;
+
+ if ((COLUMN_DATA(tw)[column].flag & _CL_width) &&
+ COLUMN_DATA(tw)[column].width == width)
+ return;
+
+ COLUMN_DATA(tw)[column].flag |= _CL_width;
+ COLUMN_DATA(tw)[column].width = width;
+
+ for(row = 0; row < ROWS(tw); row++)
+ Reposition(tw, NULL, row, column);
+
+ UpdateTable(tw);
+
+ callback_str.reason = XawTABLE_CHANGED_COLUMN_WIDTH;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedColumnWidth, callback_str);
+}
+
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetMultiColumnWidths (Widget w, int *columns, int *widths, int ncols)
+#else
+XawTableSetMultiColumnWidths (w, columns, widths, ncols)
+ Widget w;
+ int *columns;
+ int *widths;
+ int ncols;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ register int i, row, col, width;
+
+ for (i=0; i < ncols; i++ ) {
+ if (columns[i] != InRange (columns[i], 0, COLUMNS(tw)-1))
+ return;
+ }
+
+ for (i=0; i < ncols; i++ ) {
+ if ((COLUMN_DATA(tw)[columns[i]].flag & _CL_width) &&
+ COLUMN_DATA(tw)[columns[i]].width == widths[i])
+ return;
+
+ COLUMN_DATA(tw)[columns[i]].flag |= _CL_width;
+ COLUMN_DATA(tw)[columns[i]].width = widths[i];
+
+ for(row = 0; row < ROWS(tw); row++)
+ Reposition(tw, NULL, row, columns[i]);
+ }
+
+ UpdateTable(tw);
+
+/*
+ callback_str.reason = XawTABLE_CHANGED_COLUMN_WIDTH;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedColumnWidth, callback_str);
+*/
+}
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnWidth (Widget w, int column)
+#else
+XawTableGetColumnWidth(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return tw->table.column_default_width;
+
+ if ((COLUMN_DATA(tw)[column].flag & _CL_width))
+ return COLUMN_DATA(tw)[column].width;
+
+ return tw->table.column_default_width;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnPixelWidth (Widget w, int column)
+#else
+XawTableGetColumnPixelWidth(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int width;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ width = tw->table.column_default_width;
+ else if ((COLUMN_DATA(tw)[column].flag & _CL_width))
+ width = COLUMN_DATA(tw)[column].width;
+ else
+ width = tw->table.column_default_width;
+
+ if (tw->table.literal) {
+ width = width * tw->table.literal_width + 2 * tw->table.internal_width;
+ }
+
+ return width;
+}
+
+char *
+#ifdef Xraw_NEED_PROTO
+XawTableGetLabelByPosition (Widget w, int i, int j)
+#else
+ XawTableGetLabelByPosition(w,i,j)
+ Widget w;
+ int i,j;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (i != InRange(i, 0, ROWS(tw)-1)) ||
+ (j != InRange(j, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", i);
+ sprintf(subs[1], "%5d", j);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "GetLabelByPosition", "XawTableGetLabelByPosition","XawToolkitError",
+"XawTableGetLabelByPosition\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return NULL;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), i, j);
+ return GET_CELL_LABEL;
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableUnsetEdit (Widget w)
+#else
+ XawTableUnsetEdit(w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ char* label;
+ XawTableCell cell;
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ UNMANAGE_EDIT(tw);
+ tw->table.no_redraw--;
+
+ XtVaGetValues(EDIT(w), "string", &label, NULL);
+
+ label = CopyOnlyPrintable(label);
+
+ cell = (XawTableCell)
+ get_cell(STUFF(tw),tw->table.edit_row, tw->table.edit_column);
+
+ if (!streq(label,CELL(label)))
+ XawTableSetLabel(w, tw->table.edit_row, tw->table.edit_column, label);
+
+ XtFree(label); /* XtMalloc in CopyOnlyPrintable */
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetEdit (Widget w, int row, int column)
+#else
+ XawTableSetEdit(w, row, column)
+ Widget w;
+ int row;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+
+ if (IsEditInRowColumn(tw, row, column) || STUFF(tw) == NULL)
+ return;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange(row, 0, ROWS(tw)-1)) ||
+ (column != InRange(column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetEdit", "XawTableSetEdit","XawToolkitError",
+"XawTableSetEdit\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return;
+ }
+
+ XawTableUnsetEdit(w);
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(label) == NULL)
+ XtVaSetValues(EDIT(tw), "string", Dummy, NULL);
+ else
+ XtVaSetValues(EDIT(tw), "string", CELL(label), NULL);
+
+ tw->table.edit_row = row;
+ tw->table.edit_column = column;
+
+ MoveEditCell (tw, tw->table.edit_row, tw->table.edit_column);
+
+ MANAGE_EDIT(tw);
+}
+
+/******************************************************************
+ *
+ * Actions
+ *
+ ******************************************************************/
+
+static void HighlightCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int row, column;
+ Position x,y;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ if (*num_params == 2)
+ {
+ row = atoi(params[0]);
+ column = atoi(params[1]);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ ExtractPosition(event, &x, &y , &tm);
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+ }
+ else
+ {
+ return;
+ }
+
+ cell = (XawTableCell) get_cell (STUFF(tw), row, column);
+
+ if (CELL(highlight))
+ return ;
+
+ CELL(highlight) = True;
+
+ x = GetX(tw,column);
+ y = GetY(tw,row);
+
+ PaintLabel(w, row, column, x, y, cell);
+ XFlush(XtDisplay(w));
+}
+
+/* ARGSUSED */
+static void UnhighlightCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int row, column;
+ Position x,y;
+ Time tm;
+ unsigned int width;
+ unsigned int height;
+
+ if (!tw->table.editable)
+ return;
+
+ if (*num_params == 2)
+ {
+ row = atoi(params[0]);
+ column = atoi(params[1]);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ ExtractPosition(event, &x, &y , &tm);
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+ }
+ else
+ {
+ return;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (!CELL(highlight))
+ return ;
+
+ CELL(highlight) = False;
+
+ width = (unsigned int) COLUMN_WIDTH(tw, column) +
+ 2 * tw->table.label_shadow_thickness;
+ height = (unsigned int) tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness;
+
+ XClearArea(XtDisplay(w), XtWindow(w),
+ (int)GetX(tw,column),
+ (int)GetY(tw,row),
+ width, height, FALSE);
+
+ PaintLabel(w, row, column, x, y, cell);
+
+ XFlush(XtDisplay(w));
+
+}
+
+/* ARGSUSED */
+static void WhatCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ Time tm;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y , &tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ cell = (XawTableCell) get_cell (STUFF(tw), row, column);
+
+ callback_str.reason = XawTABLE_WHAT_CELL;
+ callback_str.event = event;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNwhatCell, callback_str);
+}
+
+/* ARGSUSED */
+static void KeyReturn(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ Widget tw;
+ KeySym ksSymbol;
+
+ ksSymbol = XtGetActionKeysym(event, (Modifiers*)NULL);
+
+ if (ksSymbol == XK_Return || ksSymbol == XK_Linefeed)
+ {
+ XtVaGetValues(w, XtNuserData, &tw, NULL);
+ XawTableUnsetEdit(tw);
+ }
+
+}
+
+static Atom FetchAtom(w, name)
+ Widget w;
+ String name;
+{
+ Atom a;
+ XrmValue source, dest;
+
+ source.size = strlen(name)+1;
+ source.addr = name;
+ dest.size = sizeof(Atom);
+ dest.addr = (XtPointer) &a;
+
+ (void) XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
+ return a;
+}
+
+/* ARGSUSED */
+static Boolean DeliverSelection(w, selection, target,
+ type, value, length, format)
+ Widget w;
+ Atom *selection, *target, *type;
+ XtPointer *value;
+ unsigned long *length;
+ int *format;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static Atom targets = 0;
+
+ if (targets == 0) {
+ targets = FetchAtom(w, "TARGETS");
+ }
+
+ if (*target == targets) {
+ *type = XA_ATOM;
+ *value = (XtPointer) CALLOC(1, Atom);
+ *(Atom *) *value = XA_STRING;
+ *length = 1;
+ *format = 32;
+ return TRUE;
+ }
+
+ if (*target == XA_STRING) {
+ *type = XA_STRING;
+ *value = (XtPointer) XtNewString(tw->table.cell_own->label);
+ *length = tw->table.cell_own->label_len;
+ *format = 8;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* ARGSUSED */
+static void LoseSelection(w, selection)
+ Widget w;
+ Atom *selection;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell;
+ int row, column;
+ int x,y;
+ unsigned int width, height;
+
+ cell = tw->table.cell_own;
+ tw->table.cell_own = (XawTableCell)NULL;
+
+ if (!CELL(highlight))
+ return ;
+
+ get_cell_positions(cell, &row, &column);
+
+ CELL(highlight) = False;
+
+ x = GetX(tw,column) + tw->table.label_shadow_thickness;
+ y = GetY(tw,row) + tw->table.label_shadow_thickness;
+ width = (unsigned int) COLUMN_WIDTH(tw, column);
+ height = (unsigned int) tw->table.row_height;
+
+ XClearArea(XtDisplay(w), XtWindow(w), x, y, width, height, FALSE);
+ (void)PaintCell(w, row, column, (XtPointer)cell, (XtPointer)NULL);
+
+ XFlush(XtDisplay(w));
+}
+
+static int GetCutBufferNumber();
+
+static void StoreBuffer(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* selections in precedence order */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x, y;
+ int row, column;
+ int i, buffer;
+ Time tm;
+ Atom selection;
+
+ if (!tw->table.editable)
+ return;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y ,&tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ LoseSelection(w, (Atom*)NULL);
+
+ tw->table.cell_own = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ for(i=0; i<(int)*num_params; i++) {
+ selection = FetchAtom(w, *(String *)(params+i));
+
+ buffer = GetCutBufferNumber(selection);
+
+ if (buffer >= 0) {
+ if (buffer == 0) {
+
+#define Create(buffer) \
+ XChangeProperty(XtDisplay(w), DefaultRootWindow(XtDisplay(w)),\
+ buffer,XA_STRING, 8,PropModeAppend, NULL, 0)
+
+ Create(XA_CUT_BUFFER0);
+ Create(XA_CUT_BUFFER1);
+ Create(XA_CUT_BUFFER2);
+ Create(XA_CUT_BUFFER3);
+ Create(XA_CUT_BUFFER4);
+ Create(XA_CUT_BUFFER5);
+ Create(XA_CUT_BUFFER6);
+ Create(XA_CUT_BUFFER7);
+#undef Create
+
+ XRotateBuffers(XtDisplay(w), 1);
+ }
+
+ XStoreBuffer(XtDisplay(w), tw->table.cell_own->label,
+ (int)MIN(tw->table.cell_own->label_len, MAXCUT), buffer);
+
+ } else {
+ tw->table.selections[tw->table.num_selections++] = selection;
+
+ XtOwnSelection (w, selection, tm,
+ DeliverSelection, LoseSelection,
+ (XtSelectionDoneProc) NULL);
+ }
+ }
+}
+
+
+/* ARGSUSED */
+static void CallEdit(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ ExtractPosition(event, &x, &y , &tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ XawTableSetEdit(w, row, column);
+}
+
+
+
+typedef struct {
+ Widget w;
+ Atom *selections;
+ Time time;
+ int row;
+ int column;
+ int count;
+ int num;
+}RowColumn;
+
+static void GetProc();
+
+static void GetSelection (rc)
+ RowColumn *rc;
+{
+ Atom selection;
+ int buffer;
+ int nbytes;
+ char *label;
+
+ selection = *(rc->selections + rc->num);
+
+ if (rc->num < rc->count){
+
+ buffer = GetCutBufferNumber(selection);
+
+ if (buffer >= 0) {
+ label = XFetchBuffer(XtDisplay(rc->w), &nbytes, buffer);
+ XawTableSetLabel(rc->w, rc->row, rc->column, label);
+ XtFree((XtPointer)rc->selections);
+ XtFree((XtPointer)rc);
+ }else {
+ XtGetSelectionValue(rc->w, selection, XA_STRING, GetProc,
+ (XtPointer)rc, rc->time);
+ rc->num++;
+ }
+ }
+}
+
+/* ARGSUSED */
+static void GetProc(w, client_data, selection,
+ type, value, length, format)
+ Widget w;
+ XtPointer client_data;
+ Atom *selection;
+ Atom *type;
+ XtPointer value;
+ unsigned long *length;
+ int *format;
+{
+ RowColumn *rc = (RowColumn*)client_data;
+
+ if ((*type == XA_STRING) && (value != NULL)) {
+ XawTableSetLabel(w, rc->row, rc->column, (char*)value);
+ XtFree((XtPointer)value);
+ XtFree((XtPointer)client_data);
+ }else {
+ GetSelection(rc);
+ }
+
+}
+
+static void InsertSelection(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* selections in precedence order */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ RowColumn *rc;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y ,&tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ if (*num_params > 0) {
+
+ rc = XtNew(RowColumn);
+
+ rc->time = tm;
+ rc->w = w;
+ rc->row = row;
+ rc->column = column;
+ rc->count = (int)*num_params;
+ rc->num = 0;
+
+ if (*num_params > (Cardinal)0) {
+ rc->selections = CALLOC(*num_params, Atom);
+ XmuInternStrings(XtDisplay(w), params, *num_params, rc->selections);
+ } else {
+ rc->selections = XtNew(Atom);
+ *rc->selections = FetchAtom(w, "PRIMARY");
+ }
+ GetSelection(rc);
+ }
+}
+
+
+static int GetCutBufferNumber(atom)
+ register Atom atom;
+{
+ if (atom == XA_CUT_BUFFER0) return(0);
+ if (atom == XA_CUT_BUFFER1) return(1);
+ if (atom == XA_CUT_BUFFER2) return(2);
+ if (atom == XA_CUT_BUFFER3) return(3);
+ if (atom == XA_CUT_BUFFER4) return(4);
+ if (atom == XA_CUT_BUFFER5) return(5);
+ if (atom == XA_CUT_BUFFER6) return(6);
+ if (atom == XA_CUT_BUFFER7) return(7);
+ return(-1);
+}
+
+
+/* ARGSUSED */
+static void DoingNothing(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ /* doing nothing */
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/Table.h b/vendor/x11iraf/obm/ObmW/Table.h
new file mode 100644
index 00000000..4c7ab5cf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Table.h
@@ -0,0 +1,539 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _XawTable_h
+#define _XawTable_h
+
+#include <X11/Xmu/Converters.h>
+
+#include <X11/Xraw/Simple.h>
+#include <X11/Xraw/XawInit.h>
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resources #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XawTextEncoding8bit
+#define XawTextEncoding8bit 0
+#endif
+#ifndef XawTextEncodingChar2b
+#define XawTextEncodingChar2b 1
+#endif
+
+#ifndef XtNliteral
+#define XtNliteral "literal"
+#endif
+
+#ifndef XtNrows
+#define XtNrows "rows"
+#endif
+
+#ifndef XtNcolumns
+#define XtNcolumns "columns"
+#endif
+
+
+#ifndef XtNmaskNumber
+#define XtNmaskNumber "maskNumber"
+#endif
+
+#ifndef XtNrowOriented
+#define XtNrowOriented "rowOriented"
+#endif
+
+#ifndef XtNeditForeground
+#define XtNeditForeground "editForeground"
+#endif
+
+#ifndef XtNeditBackground
+#define XtNeditBackground "editBackground"
+#endif
+
+#ifndef XtNcolumnForeground
+#define XtNcolumnForeground "columnForeground"
+#endif
+
+#ifndef XtNrowForeground
+#define XtNrowForeground "rowForeground"
+#endif
+
+#ifndef XtNvetricalScroll
+#define XtNvetricalScroll "vetricalScroll"
+#endif
+
+#ifndef XtNhorizontalScroll
+#define XtNhorizontalScroll "horizontalScroll"
+#endif
+
+#ifndef XtNcolumnsWidth
+#define XtNcolumnsWidth "columnsWidth"
+#endif
+
+#ifndef XtNrowHeight
+#define XtNrowHeight "rowHeight"
+#endif
+
+#ifndef XtNdefaultWidth
+#define XtNdefaultWidth "defaultWidth"
+#endif
+
+#ifndef XtNeditable
+#define XtNeditable "editable"
+#endif
+
+#ifndef XtNliteralWidth
+#define XtNliteralWidth "literalWidth"
+#endif
+
+#ifndef XtNtableMargin
+#define XtNtableMargin "tableMargin"
+#endif
+
+#ifndef XtNrowMargin
+#define XtNrowMargin "rowMargin"
+#endif
+
+#ifndef XtNcolumnMargin
+#define XtNcolumnMargin "columnMargin"
+#endif
+
+#ifndef XtNlabelShadowWidth
+#define XtNlabelShadowWidth "labelShadowWidth"
+#endif
+
+#ifndef XtNencoding
+#define XtNencoding "encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Classes #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtCLiteral
+#define XtCLiteral "Literal"
+#endif
+
+#ifndef XtCColumns
+#define XtCColumns "Columns"
+#endif
+
+#ifndef XtCMaskNumber
+#define XtCMaskNumber "MaskNumber"
+#endif
+
+#ifndef XtCScroll
+#define XtCScroll "Scroll"
+#endif
+
+#ifndef XtCColumnsWidth
+#define XtCColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowHeight
+#define XtCRowHeight "RowHeight"
+#endif
+
+#ifndef XtCDefaultWidth
+#define XtCDefaultWidth "DefaultWidth"
+#endif
+
+#ifndef XtCEditable
+#define XtCEditable "Editable"
+#endif
+
+#ifndef XtCLiteralWidth
+#define XtCLiteralWidth "LiteralWidth"
+#endif
+
+#ifndef XtCRows
+#define XtCRows "Rows"
+#endif
+
+#ifndef XtCTableMargin
+#define XtCTableMargin "TableMargin"
+#endif
+
+#ifndef XtCRowMargin
+#define XtCRowMargin "RowMargin"
+#endif
+
+#ifndef XtCColumnMargin
+#define XtCColumnMargin "ColumnMargin"
+#endif
+
+#ifndef XtCLabelShadowWidth
+#define XtCLabelShadowWidth "LabelShadowWidth"
+#endif
+
+#ifndef XtCEncoding
+#define XtCEncoding "Encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Types #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtRColumnsWidth
+#define XtRColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowOriented
+#define XtCRowOriented "RowOriented"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Allowance Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNallowAddColumn
+#define XtNallowAddColumn "allowAddColumn"
+#endif
+
+#ifndef XtNallowAddRow
+#define XtNallowAddRow "allowAddRow"
+#endif
+
+#ifndef XtNallowDeleteColumn
+#define XtNallowDeleteColumn "allowDeleteColumn"
+#endif
+
+#ifndef XtNallowDeleteRow
+#define XtNallowDeleteRow "allowDeleteRow"
+#endif
+
+#ifndef XtNallowDeleteTable
+#define XtNallowDeleteTable "allowDeleteTable"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Information Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNaddColumn
+#define XtNaddColumn "addColumn"
+#endif
+
+#ifndef XtNaddRow
+#define XtNaddRow "addRow"
+#endif
+
+#ifndef XtNchangedCell
+#define XtNchangedCell "changedCell"
+#endif
+
+#ifndef XtNchangedColumnWidth
+#define XtNchangedColumnWidth "changedColumnWidth"
+#endif
+
+#ifndef XtNchangedRowHeight
+#define XtNchangedRowHeight "changedRowHeight"
+#endif
+
+#ifndef XtNcreateTable
+#define XtNcreateTable "createTable"
+#endif
+
+#ifndef XtNdeleteColumn
+#define XtNdeleteColumn "deleteColumn"
+#endif
+
+#ifndef XtNdeleteRow
+#define XtNdeleteRow "deleteRow"
+#endif
+
+#ifndef XtNdeleteTable
+#define XtNdeleteTable "deleteTable"
+#endif
+
+#ifndef XtNwhatCell
+#define XtNwhatCell "whatCell"
+#endif
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# XawTableCell & XawTableColumn #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct _XawTableCellRec *XawTableCell; /* opaque to outside */
+
+typedef struct _XawTableColumnRec *XawTableColumn; /* opaque to outside */
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routine and Direction Types #*/
+/*# #*/
+/*#########################################################################*/
+typedef Boolean (*XawTableProc) Xraw_PROTO((Widget,
+ int,
+ int,
+ XawTableCell,
+ XtPointer));
+enum XawTableBypassDirection{
+ XawTABLE_RIGHT_DOWN,
+ XawTABLE_DOWN_RIGHT
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Reasons #*/
+/*# #*/
+/*#########################################################################*/
+enum XawTableReasons{
+ XawTABLE_ALLOW_ADD_COLUMN = Xraw_TABLE,
+ XawTABLE_ALLOW_ADD_ROW,
+ XawTABLE_ALLOW_CREATE_TABLE,
+ XawTABLE_ALLOW_DELETE_COLUMN,
+ XawTABLE_ALLOW_DELETE_ROW,
+ XawTABLE_ALLOW_DELETE_TABLE,
+
+ XawTABLE_ADD_COLUMN,
+ XawTABLE_ADD_ROW,
+ XawTABLE_CHANGED_CELL,
+ XawTABLE_CHANGED_COLUMN_WIDTH,
+ XawTABLE_CHANGED_ROW_HEIGHT,
+ XawTABLE_CREATE_TABLE,
+ XawTABLE_DELETE_COLUMN,
+ XawTABLE_DELETE_ROW,
+ XawTABLE_DELETE_TABLE,
+ XawTABLE_WHAT_CELL
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Structure #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct {
+ int reason;
+ XEvent *event;
+ XawTableCell old_cell;
+ XawTableCell new_cell;
+ int row;
+ int column;
+ Boolean do_it;
+}XawTableCallbackStruct;
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Layout Control Routine #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableDoLayout Xraw_PROTO((Widget w,
+ Boolean do_layout));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Stuff Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetNewSize Xraw_PROTO((Widget w,
+ int rows,
+ int columns));
+
+extern void XawTableGetSize Xraw_PROTO((Widget w,
+ int *rows,
+ int *columns));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Row Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependRow Xraw_PROTO((Widget w));
+
+extern int XawTableAppendRow Xraw_PROTO((Widget w));
+
+extern int XawTableInsertRow Xraw_PROTO((Widget w, int row));
+
+extern int XawTableDeleteRow Xraw_PROTO((Widget w, int row));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableAppendColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableInsertColumn Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableDeleteColumn Xraw_PROTO((Widget w, int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Label Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern char *XawTableGetLabelByCell Xraw_PROTO((XawTableCell cell));
+
+extern char *XawTableGetLabelByPosition Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetLabel Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ char *label));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableWalk Xraw_PROTO((Widget w,
+ XawTableProc proc,
+ int b_row,
+ int e_row,
+ int b_column,
+ int e_column,
+ int direction,
+ int *row, int *column,
+ XtPointer client_data));
+
+extern Boolean XawTableSearchLabel Xraw_PROTO((Widget w,
+ char *name,
+ int *row,
+ int *column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Edit Cell Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableIsEditManaged Xraw_PROTO((Widget w));
+
+extern void XawTableGetEditPosition Xraw_PROTO((Widget w,
+ int *row,
+ int *column));
+
+extern void XawTableUnsetEdit Xraw_PROTO((Widget w));
+
+extern void XawTableSetEdit Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Colour Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetCellBackground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel background));
+
+extern int XawTableSetCellForeground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground));
+
+extern int XawTableSetCellDefaultColours Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground,
+ Pixel background));
+
+
+extern void XawTableGetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel *foreground,
+ Pixel *background));
+
+extern void XawTableGetCellColoursByCell Xraw_PROTO((Widget w,
+ XawTableCell cell,
+ Pixel *foreground,
+ Pixel *background));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Deta #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableSetColumnJustify Xraw_PROTO((Widget w,
+ int column,
+ XtJustify justify));
+
+extern XtJustify XawTableGetColumnJustify Xraw_PROTO((Widget w,
+ int column));
+
+extern void XawTableSetColumnWidth Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableGetColumnWidth Xraw_PROTO((Widget w,
+ int column));
+
+extern int XawTableGetColumnPixelWidth Xraw_PROTO((Widget w,
+ int column));
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass tableWidgetClass;
+
+typedef struct _TableClassRec *XawTableWidgetClass;
+typedef struct _TableRec *XawTableWidget;
+
+
+#endif /* _XawTable_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Table3d.c b/vendor/x11iraf/obm/ObmW/Table3d.c
new file mode 100644
index 00000000..06fedd0b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Table3d.c
@@ -0,0 +1,924 @@
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/color.h>
+
+#define WHITE WhitePixelOfScreen
+#define BLACK BlackPixelOfScreen
+#define SWITCH(a,b) (top_or_bottom == TOP ? a : b)
+
+#define DEPTH_SCREEN(w) DefaultDepthOfScreen(XtScreen(w))
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define TOP_VALUE_RATIO (1.3)
+#define BOT_VALUE_RATIO (0.6)
+#define ARM_VALUE_RATIO (0.85)
+
+#define Top_Cash (1<<0L)
+#define Bot_Cash (1<<1L)
+#define Arm_Cash (1<<2L)
+
+typedef struct _ColorCashRec {
+ struct _ColorCashRec* nxt;
+ XColor col;
+ RGB rgb[1];
+ HSV hsv[1];
+ RGB top[1];
+ RGB bot[1];
+ RGB arm[1];
+ unsigned int set;
+}ColorCashRec, *ColorCash;
+
+static ColorCashRec* color_cash = NULL;
+static void GetTopShadow();
+
+
+static void GetTopShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Top_Cash)
+ {
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= TOP_VALUE_RATIO;
+ cash->hsv[0].v = MIN(cash->hsv[0].v, 1.0);
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->top);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+
+ cash->set |= Top_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= TOP_VALUE_RATIO;
+ cash->hsv[0].v = MIN(cash->hsv[0].v, 1.0);
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->top);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+
+ cash->set = Top_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+static void GetBotShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Bot_Cash)
+ {
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= BOT_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->bot);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+
+ cash->set |= Bot_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= BOT_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->bot);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+
+ cash->set = Bot_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+static void GetArmShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Arm_Cash)
+ {
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= ARM_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->arm);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+
+ cash->set |= Arm_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= ARM_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->arm);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+
+ cash->set = Arm_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+unsigned int shadowpm_width = 8;
+unsigned int shadowpm_height= 8;
+
+static unsigned char shadow_bits[] = {
+ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
+
+static unsigned char mtshadowpm_bits[] = {
+ 0x92, 0x24, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
+
+static unsigned char mbshadowpm_bits[] = {
+ 0x6d, 0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d, 0xdb};
+
+
+GC
+#ifdef Xraw_NEED_PROTO
+AllocGCFromPixmap (Widget w, Pixmap pixmap)
+#else
+AllocGCFromPixmap(w, pixmap)
+ Widget w;
+ Pixmap pixmap;
+#endif
+{
+ XGCValues values;
+
+ if (pixmap != None) {
+ values.tile = pixmap;
+ values.fill_style = FillTiled;
+ return XtGetGC(w, (XtGCMask)(GCTile | GCFillStyle), &values);
+ }
+
+ return XtGetGC(w, (XtGCMask)0, (XGCValues *)NULL);
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+AllocGCFromPixel (Widget w, Pixel fore)
+#else
+AllocGCFromPixel(w, fore)
+ Widget w;
+ Pixel fore;
+#endif
+{
+ XGCValues values;
+
+ values.foreground = fore;
+ return XtGetGC(w, GCForeground, &values);
+}
+
+static Pixmap Depth_1_ShadowPixmap (w, top_or_bottom)
+ Widget w;
+ int top_or_bottom;
+{
+ Screen *scn = XtScreen (w);
+
+ if (DEPTH_SCREEN(w) == 1)
+ return XCreatePixmapFromBitmapData (XtDisplay (w),
+ RootWindowOfScreen (scn),
+ (char *)shadow_bits,
+ shadowpm_width,
+ shadowpm_height,
+ SWITCH(BLACK (scn), WHITE (scn)),
+ SWITCH(WHITE (scn), BLACK (scn)),
+ 1);
+ else
+ return None;
+}
+
+static Pixmap Depth_NOT_1_ShadowPixmap (w, colour, top_or_bottom)
+ Widget w;
+ Pixel colour;
+ int top_or_bottom;
+{
+ Display *dpy = XtDisplay (w);
+ Screen *scn = XtScreen (w);
+ unsigned long fore;
+ unsigned long back;
+ char *pm_data;
+ int depth = DEPTH_SCREEN(w);
+
+ if (depth == 1)
+ return None;
+
+ if (colour == WHITE (scn) || colour == BLACK (scn)) {
+ fore = WHITE (scn);
+ back = BLACK (scn);
+ pm_data = SWITCH((char *)mtshadowpm_bits, (char *)mbshadowpm_bits);
+ } else {
+ fore = colour;
+ back = SWITCH (WHITE (scn), BLACK (scn));
+ pm_data = (char *)shadow_bits;
+ }
+
+ return XCreatePixmapFromBitmapData (dpy,
+ RootWindowOfScreen (scn),
+ (char *)pm_data,
+ shadowpm_width,
+ shadowpm_height,
+ fore,
+ back,
+ depth);
+}
+
+Pixmap
+#ifdef Xraw_NEED_PROTO
+CreateShadowPixmap (Widget w, Pixel colour, int top_or_bottom)
+#else
+CreateShadowPixmap (w, colour, top_or_bottom)
+ Widget w;
+ Pixel colour;
+ int top_or_bottom;
+#endif
+{
+ if (DEPTH_SCREEN(w) == 1)
+ return Depth_1_ShadowPixmap (w, top_or_bottom);
+ else
+ return Depth_NOT_1_ShadowPixmap (w, colour, top_or_bottom);
+}
+
+#define _MIN(x,y) (unsigned short) ((x) < (y)) ? (x) : (y)
+#define _MAX(x,y) (unsigned short) ((x) < (y)) ? (y) : (x)
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XrawAllocShadowPixel (
+ Widget w,
+ Pixel base,
+ int brightness,
+ Pixel *result)
+#else
+XrawAllocShadowPixel (w, base, brightness, result)
+ Widget w;
+ Pixel base;
+ int brightness;
+ Pixel *result; /* RETURN */
+#endif
+{
+ XColor set;
+ XColor get;
+ double mult;
+ Colormap cmap= ((CoreWidget)w)->core.colormap;
+ unsigned short red;
+ unsigned short green;
+ unsigned short blue;
+
+ get.pixel = base;
+ XQueryColor (XtDisplay (w), cmap, &get);
+ mult = (double)(100 + brightness) / ((double) 100.0);
+
+ red = mult * (double)get.red;
+ green = mult * (double)get.green;
+ blue = mult * (double)get.blue;
+
+ set.red = _MAX(0,_MIN (65535, red));
+ set.green = _MAX(0,_MIN (65535, green));
+ set.blue = _MAX(0,_MIN (65535, blue));
+
+#define EQ(field) (set.field == get.field)
+ if (EQ(red) && EQ(green) && EQ(blue))
+#undef EQ
+ return False;
+
+ if (XAllocColor (XtDisplay (w), cmap, &set) != 0) {
+ *result = set.pixel;
+ return True;
+ } else
+ return False;
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeGC (Widget w,
+ Pixel base,
+ int brightness,
+ Boolean pseudo,
+ int top_or_bottom)
+#else
+MakeGC(w, base, brightness, pseudo, top_or_bottom)
+ Widget w;
+ Pixel base;
+ int brightness;
+ Boolean pseudo;
+ int top_or_bottom;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (pseudo) {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ } else {
+ if (XrawAllocShadowPixel(w, base, brightness, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ }
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeTopShadowGC (Widget w, Pixel base)
+#else
+MakeTopShadowGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (TopShadowColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, TOP);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, TOP);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeBottomShadowGC (Widget w, Pixel base)
+#else
+MakeBottomShadowGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (BottomShadowColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeArmedGC (Widget w, Pixel base)
+#else
+MakeArmedGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (ArmedColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawDrawFrame (Widget gw,
+ Position x,
+ Position y,
+ Dimension w,
+ Dimension h,
+ XawFrameType frame_type,
+ Dimension t,
+ GC lightgc,
+ GC darkgc)
+#else
+XawDrawFrame (gw, x, y, w, h, frame_type, t, lightgc, darkgc)
+ Widget gw;
+ Position x;
+ Position y;
+ Dimension w;
+ Dimension h;
+ XawFrameType frame_type;
+ Dimension t;
+ GC lightgc;
+ GC darkgc;
+#endif
+{
+ XPoint top_polygon[6];
+ XPoint bottom_polygon[6];
+ XPoint points[3];
+
+
+ if (t == 0 || w == 0 || h == 0)
+ return;
+
+ if( lightgc == (GC)NULL ){
+ XtWarning("XawDrawFrame: lightgc is NULL in XawDrawFrame.");
+ return;
+ }
+
+ if( darkgc == (GC)NULL ){
+ XtWarning("XawDrawFrame: darkgc is NULL in XawDrawFrame.");
+ return;
+ }
+
+ if (!XtIsRealized(gw)) {
+ XtWarning("XawDrawFrame: widget is not realized!!!");
+ return;
+ }
+
+#define topPolygon(i,xx,yy) \
+ top_polygon[i].x = (short) (xx); \
+ top_polygon[i].y = (short) (yy)
+
+#define bottomPolygon(i,xx,yy) \
+ bottom_polygon[i].x = (short) (xx); \
+ bottom_polygon[i].y = (short) (yy)
+
+
+ if (frame_type == XawTACK && t <= 2)
+ frame_type = XawLEDGED;
+
+ switch (frame_type) {
+
+ case XawRAISED :
+ case XawSUNKEN :
+
+ topPolygon (0,x ,y ); bottomPolygon (0,x+w ,y+h );
+ topPolygon (1,x+w ,y ); bottomPolygon (1,x ,y+h );
+ topPolygon (2,x+w-t,y+t ); bottomPolygon (2,x+t ,y+h-t);
+ topPolygon (3,x+t ,y+t ); bottomPolygon (3,x+w-t,y+h-t);
+ topPolygon (4,x+t ,y+h-t); bottomPolygon (4,x+w-t,y+t );
+ topPolygon (5,x ,y+h ); bottomPolygon (5,x+w ,y );
+
+ if (frame_type == XawSUNKEN)
+ {
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+ }
+ else if (frame_type == XawRAISED)
+ {
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+ }
+
+ break;
+
+ case XawTACK :
+
+ t -= 2;
+
+ topPolygon (0,x ,y ); bottomPolygon (0,x+w ,y+h );
+ topPolygon (1,x+w ,y ); bottomPolygon (1,x ,y+h );
+ topPolygon (2,x+w-t,y+t ); bottomPolygon (2,x+t ,y+h-t);
+ topPolygon (3,x+t ,y+t ); bottomPolygon (3,x+w-t,y+h-t);
+ topPolygon (4,x+t ,y+h-t); bottomPolygon (4,x+w-t,y+t );
+ topPolygon (5,x ,y+h ); bottomPolygon (5,x+w ,y );
+
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+
+ points[0].x = x + t + 1; points[0].y = y + h - t - 2;
+ points[1].x = x + t + 1; points[1].y = y + t + 1;
+ points[2].x = x + w - t - 2; points[2].y = y + t + 1;
+
+ XDrawLines (XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ points, 3, CoordModeOrigin);
+
+ /* points[0].x = x + t + 1; points[0].y = y + h -t - 1; */
+ points[1].x = x + w - t - 2; points[1].y = y + h - t - 2;
+ /* points[2].x = x + w - t - 1; points[2].y = y + t + 1; */
+
+ XDrawLines (XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ points, 3, CoordModeOrigin);
+
+ break;
+
+ case XawLEDGED :
+
+ XawDrawFrame(gw, x, y, w, h, XawRAISED, t/2, lightgc, darkgc);
+ XawDrawFrame(gw, (Position)(x + t/2), (Position)(y + t/2),
+ (Dimension)(w - 2 * (t/2)), (Dimension)(h - 2 * (t/2)),
+ XawSUNKEN, t/2, lightgc, darkgc);
+ break;
+
+ case XawCHISELED :
+
+ XawDrawFrame(gw, x, y, w, h, XawSUNKEN, t/2, lightgc, darkgc);
+ XawDrawFrame(gw, (Position)(x + t/2),(Position)(y + t/2),
+ (Dimension)(w - 2 * (t/2)), (Dimension)(h - 2 * (t/2)),
+ XawRAISED, t/2, lightgc, darkgc);
+ break;
+
+ default :
+ break;
+
+ }
+
+#undef topPolygon
+#undef bottomPolygon
+}
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+BottomShadowColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+BottomShadowColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetBotShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+TopShadowColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+TopShadowColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetTopShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+ArmedColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+ArmedColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetArmShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+
+
+#undef assign_max
+#undef assign_min
+
+
+void
+#ifdef Xraw_NEED_PROTO
+DrawRhombus (
+ Widget w,
+ short x,
+ short y,
+ short g,
+ short t,
+ GC top_shadow_GC,
+ GC foreground_gc,
+ GC bottom_shadow_GC,
+ Boolean state )
+#else
+DrawRhombus(w, x, y, g, t,
+ top_shadow_GC, foreground_gc, bottom_shadow_GC, state)
+ Widget w;
+ short x;
+ short y;
+ short g;
+ short t;
+ GC top_shadow_GC;
+ GC foreground_gc;
+ GC bottom_shadow_GC;
+ Boolean state;
+#endif
+{
+ XPoint top_shade[6];
+ XPoint bot_shade[6];
+ XPoint center[4];
+
+#define topPolygon(i,a,b) top_shade[i].x = a; top_shade[i].y = b
+#define bottomPolygon(i,a,b) bot_shade[i].x = a; bot_shade[i].y = b
+#define centerPolygon(i,a,b) center[i].x = a; center[i].y = b
+
+ topPolygon(0, x-g , y ); bottomPolygon(0, x-g , y );
+ topPolygon(1, x-g+t, y ); bottomPolygon(1, x-g+t, y );
+ topPolygon(2, x , y-g+t); bottomPolygon(2, x , y+g-t);
+ topPolygon(3, x+g-t, y ); bottomPolygon(3, x+g-t, y );
+ topPolygon(4, x+g , y ); bottomPolygon(4, x+g , y );
+ topPolygon(5, x , y-g ); bottomPolygon(5, x , y+g );
+
+ if (state)
+ {
+ if (foreground_gc)
+ {
+ centerPolygon(0, x-g+t, y );
+ centerPolygon(1, x , y-g+t);
+ centerPolygon(2, x+g-t, y );
+ centerPolygon(3, x , y+g-t);
+
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), foreground_gc,
+ center, XtNumber(center),
+ Convex, CoordModeOrigin);
+ }
+
+ if (bottom_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), bottom_shadow_GC,
+ top_shade, XtNumber(top_shade), Nonconvex, CoordModeOrigin);
+
+ if (top_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), top_shadow_GC,
+ bot_shade, XtNumber(bot_shade), Nonconvex, CoordModeOrigin);
+ }else{
+
+ if (top_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), top_shadow_GC,
+ top_shade, XtNumber(top_shade),
+ Nonconvex, CoordModeOrigin);
+
+ if (bottom_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), bottom_shadow_GC,
+ bot_shade, XtNumber(bot_shade),
+ Nonconvex, CoordModeOrigin);
+ }
+
+#undef topPolygon
+#undef bottomPolygon
+#undef centerPolygon
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+FetchPixel (Widget w, String name, Pixel* pixel)
+#else
+FetchPixel(w, name, pixel)
+ Widget w;
+ String name;
+ Pixel* pixel;
+#endif
+{
+ XrmValue source, dest;
+
+ source.size = strlen(name)+1;
+ source.addr = name;
+ dest.size = sizeof(Pixel);
+ dest.addr = (caddr_t) pixel;
+
+ return XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Table3d.h b/vendor/x11iraf/obm/ObmW/Table3d.h
new file mode 100644
index 00000000..61125ceb
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Table3d.h
@@ -0,0 +1,145 @@
+#ifndef _3d_h_
+#define _3d_h_
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xraw/XawInit.h>
+
+typedef enum {
+ XawRAISED = Xraw_3d,
+ XawSUNKEN,
+ XawCHISELED,
+ XawLEDGED,
+ XawTACK
+} XawFrameType;
+
+#define TOP (1)
+#define BOTTOM (2)
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean ArmedColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+
+
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+
+extern Pixmap CreateShadowPixmap Xraw_PROTO((Widget ,
+ Pixel ,
+ int ));
+
+
+extern Boolean XrawAllocShadowPixel Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Pixel * ));
+
+
+extern GC MakeGC Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Boolean ,
+ int ));
+
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern void XawDrawFrame Xraw_PROTO((Widget ,
+ Position ,
+ Position ,
+ Dimension ,
+ Dimension ,
+ XawFrameType ,
+ Dimension ,
+ GC ,
+ GC ));
+
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean ArmedColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern void DrawRhombus Xraw_PROTO((Widget ,
+ short ,
+ short ,
+ short ,
+ short ,
+ GC ,
+ GC ,
+ GC ,
+ Boolean ));
+
+extern Boolean FetchPixel Xraw_PROTO((Widget ,
+ String name ,
+ Pixel* ));
+
+#endif /* _3d_h_ */
+
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/TableP.h b/vendor/x11iraf/obm/ObmW/TableP.h
new file mode 100644
index 00000000..352fb278
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TableP.h
@@ -0,0 +1,166 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is desined for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advises, new components and patches of the existing programs.
+Commercial usage is also possible with participation of it's author.
+
+*************************************************************************/
+
+#ifndef _XawTableP_h
+#define _XawTableP_h
+
+/***********************************************************************
+ *
+ * Table Widget Private Data
+ *
+ ***********************************************************************/
+
+
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Table.h>
+#include <X11/Xraw/xraw_table.h>
+
+/* New fields for the Table widget class record */
+
+typedef struct {int foo;} TableClassPart;
+
+/* Full class record declaration */
+typedef struct _TableClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ TableClassPart table_class;
+} TableClassRec;
+
+#define MAX_ROWS 50
+
+typedef struct _NormalReverseGC {
+ int used;
+ Pixel fore;
+ Pixel back;
+ GC normal;
+ GC reverse;
+}NormalReverseGC;
+
+typedef struct _ShadowGC {
+ int used;
+ Pixel back;
+ GC top;
+ GC bottom;
+}ShadowGC;
+
+
+
+/* New fields for the Table widget record */
+typedef struct {
+ /* ------------------------ resources -----------------------*/
+ Pixel row_fore;
+ Pixel column_fore;
+ Pixel edit_fore;
+ Pixel edit_back;
+ Boolean row_oriented;
+ Boolean editable;
+ Boolean literal;
+
+ int mask_number;
+ int columns;
+ int rows;
+ Dimension tab_margin;
+ Dimension row_margin;
+ Dimension col_margin;
+ Dimension internal_width;
+ Dimension internal_height;
+ Dimension label_shadow_thickness;
+ unsigned char encoding;
+
+ /* Default Values */
+ Pixel foreground;
+ XtJustify justify;
+ XFontStruct *font;
+ int width;
+
+ /* Allowance CallbackList */
+ XtCallbackList allow_add_row;
+ XtCallbackList allow_add_column;
+ XtCallbackList allow_delete_column;
+ XtCallbackList allow_delete_row;
+ XtCallbackList allow_delete_table;
+
+ /* Information CallbackList */
+ XtCallbackList add_row;
+ XtCallbackList add_column;
+ XtCallbackList changed_cell;
+ XtCallbackList create_table;
+ XtCallbackList delete_column;
+ XtCallbackList delete_row;
+ XtCallbackList delete_table;
+ XtCallbackList what_cell;
+ XtCallbackList changed_column_width;
+ XtCallbackList changed_row_height;
+
+ Widget v_scroll;
+ Widget h_scroll;
+
+ int row_height;
+ int column_default_width;
+ int literal_width;
+
+ /* ------------------------ private state -----------------------*/
+
+ int no_refigure; /* no re-layout while > 0 */
+ int no_redraw; /* no re-draw while > 0 */
+ Boolean was_resized;
+
+
+ XawTableColumn column_data;
+
+ Dimension prefer_width;
+ Dimension prefer_height;
+ Widget edit;
+ int edit_row;
+ int edit_column;
+ XawTableCell cell_own;
+ XawTableCell table_stuff;
+
+ GC row_gc; /* Intrinsics sharedable GC */
+ GC column_gc; /* Intrinsics sharedable GC */
+
+ GC normal; /* Table sharedable GC */
+ GC reverse; /* Table sharedable GC */
+ GC top;
+ GC bottom;
+
+ GC edit_top;
+ GC edit_bottom;
+
+ NormalReverseGC *normal_hash_table;
+ ShadowGC *shadow_hash_table;
+ int mask_hash_table;
+
+ Atom selections[30];
+ int num_selections;
+} TablePart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TableRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ TablePart table;
+} TableRec;
+
+extern TableClassRec tableClassRec;
+
+#endif /* _XawTableP_h */
diff --git a/vendor/x11iraf/obm/ObmW/TableUtil.c b/vendor/x11iraf/obm/ObmW/TableUtil.c
new file mode 100644
index 00000000..27fa3129
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TableUtil.c
@@ -0,0 +1,919 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#include <X11/Xraw/TableUtil.h>
+#include <X11/Xraw/xraw_table.h>
+
+#ifdef EBUG_XRAW_MALLOC
+#include <dbmalloc/malloc.h>
+#endif
+
+/************************************************************************
+ *
+ * TABLE IS A GRID OF POINTER BINDED NODES
+ *
+ ************************************************************************/
+
+#define null (XawTableNode)NULL
+#define FREE(t) if((t) != null)XtFree((char*)(t))
+
+static void vert_tab_node_insert(f,s,p)
+ register XawTableNode f; /* insert after */
+ register XawTableNode s; /* insert before */
+ register XawTableNode p; /* to be inserted */
+{
+ if (f != null) f->b = p;
+ if (s != null) s->t = p;
+ if (p != null) {p->t = f; p->b = s;}
+}
+
+static void horiz_tab_node_insert(f,s,p)
+ register XawTableNode f; /* insert after */
+ register XawTableNode s; /* insert before */
+ register XawTableNode p; /* to be inserted */
+{
+ if (f != null) f->r = p;
+ if (s != null) s->l = p;
+ if (p != null) {p->l = f; p->r = s;}
+}
+
+static void vert_tab_node_reject(p)
+ register XawTableNode p;
+{
+ if (p == null) return;
+
+ if (p->t != null) p->t->b = p->b;
+ if (p->b != null) p->b->t = p->t;
+}
+
+static void horiz_tab_node_reject(p)
+ register XawTableNode p;
+{
+ if (p == null) return;
+
+ if (p->r != null) p->r->l = p->l;
+ if (p->l != null) p->l->r = p->r;
+}
+
+/* ARGSUSED */
+static XawTableProc del_cell (w, i, j, call_data, client_data)
+ XtPointer w;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ XtFree((char*)call_data);
+ return False;
+}
+
+/*
+** Function name : row_delete
+**
+** Description : delete row which the node belongs to
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+row_delete (XtPointer f)
+#else
+row_delete(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return;
+
+ /* Go to left edge */
+ for(; p->l != null; p=p->l )
+ /*EMPTY*/;
+
+ /* Go to right with dettaching cell */
+ for(; p->r != null; p=p->r){
+ vert_tab_node_reject(p->l);
+ FREE(p->l);
+ }
+
+ /* Detach last but one cell in the row */
+ if (p->l != null){
+ vert_tab_node_reject(p->l);
+ FREE(p->l);
+ }
+
+ /* Detach very last cell in the row */
+ vert_tab_node_reject(p);
+ FREE(p);
+}
+
+/*
+** Function name : column_delete
+**
+** Description : delete column which the node belongs to
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+column_delete (XtPointer f)
+#else
+column_delete(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return;
+
+ /* Go up to the edge */
+ for(; p->t != null; p=p->t )
+ /*EMPTY*/;
+
+ /* Go down with dettaching cell */
+ for(; p->b != null; p=p->b){
+ horiz_tab_node_reject(p->t);
+ FREE(p->t);
+ }
+
+ /* Detach bottom but one cell in the column */
+ if (p->t != null){
+ horiz_tab_node_reject(p->t);
+ FREE(p->t);
+ }
+
+ /* Detach very bottom cell in the column */
+ horiz_tab_node_reject(p);
+ FREE(p);
+}
+
+
+
+/*
+** Function name : row_insert_after
+**
+** Description : insert row down to the row which the node belongs to
+** Input : poiter to the node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+row_insert_after (XtPointer d, int node_size)
+#else
+row_insert_after(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode left;
+
+ if (f == null)
+ return False;
+
+ /* go left till row edge */
+ for(; f->l != null; f=f->l )
+ /*EMPTY*/;
+
+ /* save very left node */
+ left = f;
+
+ /* go right and attach new cells via vertical ponters */
+ for(; f->r != null; f=f->r){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->b);
+ FREE(left->b);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f, f->b, p);
+ }
+
+ /* attach vertically very right cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->b);
+ FREE(left->b);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f, f->b, p);
+
+ /* if only one column */
+ if ( f->l == null ) {
+ f->b->l = f->b->r = null;
+ return True;
+ }
+
+ /* attach horizontally very right cell */
+ horiz_tab_node_insert(f->l->b,null,f->b);
+
+ /* bind via horizontal ponters */
+ for(f=f->l; f->l != null; f=f->l )
+ horiz_tab_node_insert(f->l->b,f->r->b,f->b);
+
+ /* attach horizontally very left cell */
+ horiz_tab_node_insert(null,f->r->b,f->b);
+
+ return True;
+}
+
+/*
+** Function name : row_insert_before
+**
+** Description : the same as previous, but only on top from row
+** Input : pointer to the node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+row_insert_before (XtPointer d, int node_size)
+#else
+row_insert_before(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode left;
+
+ if (f == null)
+ return False;
+
+ /* go left till row edge */
+ for(; f->l != null; f=f->l )
+ /*EMPTY*/;
+
+ /* save very left node */
+ left = f;
+
+ /* go right and attach new cells via vertical ponters */
+ for(; f->r != null; f=f->r){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->t);
+ FREE(left->t);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f->t, f, p);
+ }
+
+ /* attach vertically very right cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->t);
+ FREE(left->t);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f->t, f, p);
+
+ /* if only one column */
+ if ( f->l == null ) {
+ f->t->l = f->t->r = null;
+ return True;
+ }
+
+ /* attach horizontally very right cell */
+ horiz_tab_node_insert(f->l->t,null,f->t);
+
+ /* bind via horizontal ponters */
+ for(f=f->l; f->l != null; f=f->l )
+ horiz_tab_node_insert(f->l->t,f->r->t,f->t);
+
+ /* attach horizontally very left cell */
+ horiz_tab_node_insert(null,f->r->t,f->t);
+
+ return True;
+}
+
+/*
+** Function name : column_insert_after
+**
+** Description : insert column right to the column which the node belongs to
+** Input : pointer to the node, size of node
+** Output : True if successful
+[<*/
+
+Boolean
+#if NeedFunctionPrototypes
+column_insert_after (XtPointer d, int node_size)
+#else
+column_insert_after(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode top;
+
+ if (f == null)
+ return False;
+
+ /* go top till column edge */
+ for(; f->t != null; f=f->t )
+ /*EMPTY*/;
+
+ /* save very top node */
+ top = f;
+
+ /* go down and attach new cells via horizontal ponters */
+ for(; f->b != null; f=f->b){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->r);
+ FREE(top->r);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f, f->r, p);
+ }
+
+ /* attach horizontally very down cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->r);
+ FREE(top->r);
+ }
+ return False;
+ }
+
+ horiz_tab_node_insert(f, f->r, p);
+
+ /* if only one row */
+ if ( f->t == null ) {
+ f->r->t = f->r->b = null;
+ return True;
+ }
+
+ /* attach vertically very down cell */
+ vert_tab_node_insert(f->t->r,null,f->r);
+
+ /* bind via vertical ponters */
+ for(f=f->t; f->t != null; f=f->t )
+ vert_tab_node_insert(f->t->r,f->b->r,f->r);
+
+ /* attach vertically very top cell */
+ vert_tab_node_insert(null,f->b->r,f->r);
+
+ return True;
+}
+
+/*
+** Function name : column_insert_before
+**
+** Description : the same as previous, but only to left from column
+** Input : pointer to node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+column_insert_before (XtPointer d, int node_size)
+#else
+column_insert_before(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode)d;
+ register XawTableNode p;
+ XawTableNode top;
+
+ if (f == null)
+ return False;
+
+ /* go top till column top */
+ for(; f->t != null; f=f->t )
+ /*EMPTY*/;
+
+ /* save very top node */
+ top = f;
+
+ /* go down and attach new cells via horizontal ponters */
+ for(; f->b != null; f=f->b){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->l);
+ FREE(top->l);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f->l, f, p);
+ }
+
+ /* attach horizontally very down cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->l);
+ FREE(top->l);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f->l, f, p);
+
+ /* if only one row */
+ if ( f->t == null ) {
+ f->l->t = f->l->b = null;
+ return True;
+ }
+
+ /* attach vertically very down cell */
+ vert_tab_node_insert(f->t->l, null, f->l);
+
+ /* bind via vertical ponters */
+ for(f=f->t; f->t != null; f=f->t )
+ vert_tab_node_insert(f->t->l, f->b->l, f->l);
+
+ /* attach vertically very top cell */
+ vert_tab_node_insert(null, f->b->l, f->l);
+
+ return True;
+}
+
+/*
+** Function name : get_table
+**
+** Description : spot the node (0,0) in the table
+** Input : pointer to any node in table
+** Output : pointer to the node (0,0)
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+get_table (XtPointer f)
+#else
+get_table(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return (XtPointer)NULL;
+
+ for(; p->t != null; p=p->t)
+ /*EMPTY*/;
+
+ for(; p->l != null; p=p->l)
+ /*EMPTY*/;
+
+ return (XtPointer)p;
+}
+
+/*
+** Function name : get_cell
+**
+** Description : spot the node (i,j) regarding to given node
+** Input : pointer to the node, column, row (may be negative)
+** Output : pointer to the node or NULL
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+get_cell (XtPointer f, register int i, register int j)
+#else
+get_cell (f, i, j)
+ XtPointer f;
+ register int i;
+ register int j;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return (XtPointer)NULL;
+
+ if (i > 0) {
+ for(; i>0; i--)
+ if (p != null) p = p->b;
+ else return (XtPointer)NULL;
+ } else {
+ for(; i<0; i++)
+ if (p != null) p = p->t;
+ else return (XtPointer)NULL;
+ }
+
+ if (j > 0) {
+ for(; j>0; j--)
+ if (p != null) p = p->r;
+ else return (XtPointer)NULL;
+ } else {
+ for(; j<0; j++)
+ if (p != null) p = p->l;
+ else return (XtPointer)NULL;
+ }
+
+ return (XtPointer)p;
+}
+
+#if 0
+static Boolean go_row(w, proc, p, begin_column, end_column, i, j, client_data)
+ XtPointer w;
+ XawTableProc proc;
+ XawTableNode p; /* p == get_cell(table, ... , begin_column) */
+ int begin_column;
+ int end_column;
+ int *i; /* returned */
+ int *j; /* returned */
+ XtPointer client_data;
+{
+ for ((*j) = begin_column; ((*j) <= end_column) && (p != null); (*j)++)
+ {
+ XawTableProc sp = p;
+ p = p->r;
+
+ if (proc(w, *i, *j, (XtPointer)sp, client_data))
+ return True;
+ }
+
+ return False;
+}
+#endif
+
+/*
+** Function name : go_table
+**
+** Description : invoke given rutine for every node in given region
+** Input : rutine, begin/end rows, begin/end columns...
+** Output : True if given rutine returned True for a node,
+** numbers of row and column for that node
+ */
+
+Boolean
+#if NeedFunctionPrototypes
+go_table (
+ XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *i, /* returned */
+ register int *j, /* returned */
+ XtPointer client_data)
+#else
+go_table(w, proc, table, begin_row, end_row, begin_column, end_column,
+ direction, i, j, client_data)
+ XtPointer w;
+ XawTableProc proc;
+ XtPointer table;
+ int begin_row;
+ int end_row;
+ int begin_column;
+ int end_column;
+ int direction;
+ register int *i; /* returned */
+ register int *j; /* returned */
+ XtPointer client_data;
+#endif
+{
+ register XawTableNode p;
+ register XawTableNode n;
+
+ table = get_table(table);
+
+ switch (direction) {
+ case XawTABLE_DOWN_RIGHT :
+ p = (XawTableNode)get_cell(table, begin_row, begin_column);
+
+ for (*j = begin_column; *j <= end_column && p != null; (*j)++)
+ {
+ register XawTableNode sp = p; /* protect against deallocated node !! */
+ p = p->r;
+
+ for (*i = begin_row, n = sp; *i <= end_row && n != null; (*i)++)
+ {
+ register XawTableNode sn = n; /* protect against deallocated node !! */
+ n = n->b;
+
+ if (proc(w, *i, *j, (XtPointer)sn, client_data))
+ return True;
+ }
+ }
+ break;
+ case XawTABLE_RIGHT_DOWN :
+ default :
+ p = (XawTableNode)get_cell(table, begin_row, begin_column);
+
+ for (*i = begin_row; *i <= end_row && p != null; (*i)++)
+ {
+ register XawTableNode sp = p; /* protect against deallocated node !! */
+ p = p->b;
+
+ for (*j = begin_column, n = sp; *j <= end_column && n != null; (*j)++)
+ {
+ register XawTableNode sn = n; /* protect against deallocated node !! */
+ n = n->r;
+
+ if (proc(w, *i, *j, (XtPointer)sn, client_data))
+ return True;
+ }
+ }
+ break;
+ }
+ return False;
+}
+
+/*
+** Function name : get_table_size
+**
+** Description : define dimention on the table
+** Input : pointer to any node in the table
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+get_table_size (XtPointer f,
+ register int *i, /* returned */
+ register int *j) /* returned */
+#else
+get_table_size(f,i,j)
+ XtPointer f;
+ register int *i; /* returned */
+ register int *j; /* returned */
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ if (p == null){
+ *i = 0;
+ *j = 0;
+ }
+
+ p = (XawTableNode)get_table(f);
+
+ for (*i = 1; p->b != null; p = p->b, (*i)++)
+ /*EMPTY*/;
+
+ for (*j = 1; p->r != null; p = p->r, (*j)++)
+ /*EMPTY*/;
+}
+
+/*
+** Function name : delete_table
+**
+** Description : destroy table
+** Input : pointer to any node in the table
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+delete_table (XtPointer f)
+#else
+delete_table(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ int i,j;
+ int end_row, end_column;
+
+ if (p == null)
+ return;
+
+ p = (XawTableNode)get_table(f);
+ get_table_size((XtPointer)p, (int*)&end_row, (int*)&end_column);
+ (void)go_table(NULL, (XawTableProc)del_cell, (XtPointer)p,
+ 0, (int)(end_row-1), 0, (int)(end_column-1),
+ XawTABLE_RIGHT_DOWN,
+ (int*)&i, (int*)&j, NULL);
+}
+
+/*
+** Function name : get_cell_positions
+**
+** Description : define number of row & column for node
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+get_cell_positions (XtPointer f,
+ register int *i, /* returned */
+ register int *j) /* returned */
+#else
+get_cell_positions(f, i, j)
+ XtPointer f;
+ register int *i; /* returned */
+ register int *j; /* returned */
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ if ( p == null )
+ return;
+
+ if ( i != (int*)NULL ) {
+ for (*i = 0; p->t != null; p = p->t, (*i)++)
+ /*EMPTY*/;
+ }
+
+ if ( j != (int*)NULL ) {
+ for (*j = 0; p->l != null; p = p->l, (*j)++)
+ /*EMPTY*/;
+ }
+}
+
+/*
+** Function name : create_table
+**
+** Description : create the table
+** Input : row & column dimestions, size of node
+** Output : pointer to the node (0,0)
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+create_table ( int rows, int columns, int node_size)
+#else
+create_table(rows, columns, node_size)
+ int rows;
+ int columns;
+ int node_size;
+#endif
+{
+ register XawTableNode *area;
+ register XawTableNode p;
+ register int i,j;
+ XawTableNode table;
+
+ if (rows == 0 || columns == 0)
+ return (XtPointer)NULL;
+ else{
+ register XawTableNode *s;
+
+ /* allocate temporary two-dimension array to make first node's binding */
+ if ( (s = area = (XawTableNode*)
+ XtCalloc ((unsigned)(rows * columns), sizeof(XawTableNode))) == NULL)
+ return (XtPointer)NULL;
+
+ /* allocate nodes */
+ for (i = 0, j = rows*columns; i < j; i++)
+ if((*s++ = (XawTableNode) XtMalloc (node_size)) == NULL){
+ int h;
+ for (h = 0, s = area; h < i; h++)
+ XtFree((char*)*s++);
+
+ XtFree((char*)area);
+ return (XtPointer)NULL;
+ }
+ }
+
+#define a(i,j) (XawTableNode)*(area + (i)*columns + (j))
+
+ /* initialize the boundary nodes */
+ for (i = 0; i < rows; i++) {
+ p = a(i,0); p->l = null;
+ p = a(i,columns-1); p->r = null;
+ }
+ for (j = 0; j < columns; j++) {
+ p = a(0,j); p->t = null;
+ p = a(rows-1,j); p->b = null;
+ }
+
+#undef a
+#define a(i,j) (( (i)>=0 && (i)<rows ) && ( (j)>=0 && (j)<columns ) ? \
+ (XawTableNode)*(area + (i)*columns + (j)) : null)
+
+ /* make internode's binding */
+ for (i = 0; i < rows; i++) {
+ for (j = i % 2; j < columns; j += 2) {
+ horiz_tab_node_insert(a(i,j-1), a(i,j+1), a(i,j));
+ vert_tab_node_insert (a(i-1,j), a(i+1,j), a(i,j));
+ }
+ }
+
+#undef a
+
+ table = *area;
+ XtFree((char*)area);
+ return (XtPointer)table;
+}
+
+
+#ifdef EBUG_XRAW_MALLOC
+/* ARGSUSED */
+static Boolean check_cell (w, row, column, call_data, client_data)
+ XtPointer w; /* unused */
+ int row;
+ int column;
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ register XawTableNode p = (XawTableNode)call_data;
+ int real_row, real_column;
+ char *halt = NULL;;
+
+ get_cell_positions(p, &real_row, &real_column);
+
+ if (real_row != row){
+ XtWarning("check_table: wrong initial table row size");
+ *halt = '\0';
+ }
+
+ if (real_column != column){
+ XtWarning("check_table: wrong initial table column size");
+ *halt = '\0';
+ }
+
+ if (p->l != null)
+ if (p->l->r != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->r != null)
+ if (p->r->l != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->t != null)
+ if (p->t->b != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->b != null)
+ if (p->b->t != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+
+ return False;
+}
+
+
+
+void
+#if NeedFunctionPrototypes
+_check_table (XtPointer f, int rows, int columns)
+#else
+_check_table (f, rows, columns)
+ XtPointer f;
+ int rows;
+ int columns;
+#endif
+{
+ register XawTableNode table = (XawTableNode)f;
+ int real_rows, real_columns;
+ register int i,j;
+ char *halt = NULL;
+
+ if (f == NULL && (rows == 0 || columns == 0))
+ return;
+
+ if (table != get_table(f)){
+ XtWarning("check_table: wrong initial table cell");
+ *halt = '\0';
+ }
+
+ get_table_size (f, &real_rows, &real_columns);
+
+ if (real_rows != rows){
+ XtWarning("check_table: wrong initial table row size");
+ *halt = '\0';
+ }
+
+ if (real_columns != columns){
+ XtWarning("check_table: wrong initial table column size");
+ *halt = '\0';
+ }
+
+
+ (void) go_table (NULL, check_cell, table,
+ 0, rows-1, 0, columns-1,
+ XawTABLE_RIGHT_DOWN,
+ &real_rows, &real_columns, (XtPointer)NULL);
+
+}
+#endif /* EBUG_XRAW_MALLOC */
+
+#undef null
+#undef FREE
+
diff --git a/vendor/x11iraf/obm/ObmW/TableUtil.h b/vendor/x11iraf/obm/ObmW/TableUtil.h
new file mode 100644
index 00000000..a8262f75
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TableUtil.h
@@ -0,0 +1,94 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _table_h_
+#define _table_h_
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xraw/Table.h>
+
+#if __STDC__ || defined(__cplusplus)
+#define F_PROTO(s) s
+#else
+#define F_PROTO(s) ()
+#endif
+
+typedef struct _XawTableNodeRec { /* Node of table grid */
+ struct _XawTableNodeRec *l;
+ struct _XawTableNodeRec *r;
+ struct _XawTableNodeRec *t;
+ struct _XawTableNodeRec *b;
+}XawTableNodeRec, *XawTableNode;
+
+
+extern XtPointer create_table F_PROTO((int rows,
+ int columns,
+ int node_size));
+
+extern Boolean row_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean row_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern Boolean column_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean column_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern XtPointer get_table F_PROTO((XtPointer f));
+
+extern XtPointer get_cell F_PROTO((XtPointer p,
+ int i,
+ int j));
+
+extern void get_table_size F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void get_cell_positions F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void row_delete F_PROTO((XtPointer p));
+
+extern void column_delete F_PROTO((XtPointer p));
+
+extern void delete_table F_PROTO((XtPointer p));
+
+extern Boolean go_table F_PROTO((XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *row,
+ register int *column,
+ XtPointer client_data));
+
+#ifdef EBUG_XRAW_MALLOC
+extern void _check_table F_PROTO((XtPointer table,
+ int rows,
+ int columns));
+#endif
+
+#undef F_PROTO
+
+#endif /* _table_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/Tablist2Tabs.c b/vendor/x11iraf/obm/ObmW/Tablist2Tabs.c
new file mode 100644
index 00000000..800500fc
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Tablist2Tabs.c
@@ -0,0 +1,35 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "TabString.h"
+
+/*
+ * Converts a string list of tabs to an array of tabs
+ */
+int *
+XfwfTablist2Tabs(tablist)
+char *tablist;
+{
+ register int *tabs;
+ register int ntabs = 0;
+
+ if (!tablist)
+ return NULL;
+ for (;;)
+ {
+ /* Skip leading blanks */
+ while (*tablist && *tablist == ' ') ++tablist;
+ if (!*tablist) break;
+
+ /* Allocate space for the new tab */
+ if (ntabs)
+ tabs = (int *) XtRealloc( (char *) tabs,
+ (ntabs+1) * sizeof(int));
+ else
+ tabs = (int *) XtMalloc( (ntabs + 1) * sizeof(int));
+ /* Add it to the list */
+ tabs[ntabs++] = atoi(tablist);
+ /* Skip to the next blank */
+ while (*tablist && *tablist != ' ') ++tablist;
+ }
+ return (tabs);
+}
diff --git a/vendor/x11iraf/obm/ObmW/Tabs.c b/vendor/x11iraf/obm/ObmW/Tabs.c
new file mode 100644
index 00000000..767bd754
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Tabs.c
@@ -0,0 +1,2183 @@
+static char rcsid[] = "$Id: Tabs.c,v 1.27 1999/12/16 18:44:18 falk Exp $" ;
+
+/*
+ * Tabs.c - Index Tabs composite widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: July 29, 1997
+ *
+ *
+ * Overall layout of this widget is as follows:
+ *
+ * ________ ,---------. _________
+ * | label || Label || Label | \ tabs
+ * |________|| ||_________| /
+ * |+----------------------------+| \
+ * || || |
+ * || child widget window || > frame
+ * |+----------------------------+| |
+ * +------------------------------+ /
+ *
+ * The height of the tabs includes the shadow width, top and bottom
+ * margins, and the height of the text.
+ *
+ * The height of the frame includes the top and bottom shadow width and the
+ * size of the child widget window.
+ *
+ * The tabs overlap the frame and each other vertically by the shadow
+ * width, so that when the topmost tab is drawn, it obliterates part of
+ * the frame.
+ *
+ *
+ * $Log: Tabs.c,v $
+ * Revision 1.27 1999/12/16 18:44:18 falk
+ * Added keyboard traversal
+ *
+ * Revision 1.26 1999/12/16 18:01:37 falk
+ * No longer caches child preferred sizes. Now recomputes GC's
+ * after font change. Fixes some layout bugs. Adds safety feature
+ * to make sure that layout() doesn't loop forever.
+ *
+ * Revision 1.25 1999/12/07 19:11:45 falk
+ * Fixed uninitialized variables in resize. Minor cleanups to make
+ * compiler happy.
+ *
+ * Revision 1.24 1999/12/02 08:39:04 falk
+ * deleted dead variables
+ *
+ * Revision 1.23 1999/10/01 20:35:16 falk
+ * Added Motif compatibility
+ *
+ * Revision 1.22 1999/09/22 19:53:23 falk
+ * added more keyboard traversal.
+ *
+ * Revision 1.21 1999/09/08 17:47:02 falk
+ * Now draws text with Y offset when tab is top
+ * Now requires Ansi C
+ *
+ * Revision 1.20 1999/09/07 16:12:01 falk
+ * added keyboard accelerators
+ *
+ * Revision 1.19 1999/08/05 03:17:34 falk
+ * minor changes to make gcc -Wall happy.
+ *
+ * Revision 1.18 1999/07/30 23:01:05 falk
+ * makes sure top tab is managed
+ *
+ * Revision 1.17 1999/07/30 16:17:21 falk
+ * Optimized size calculations by caching results.
+ * Now ignores unmanaged children.
+ * Now handles deletion of top widget properly.
+ *
+ * Revision 1.16 1999/06/28 23:03:20 falk
+ * major updates to geometry management.
+ *
+ * Revision 1.15 1999/06/23 18:17:14 falk
+ * added XtNpopdownCallback resource
+ *
+ * Revision 1.14 1998/10/23 17:41:48 falk
+ * now uses XmuCreateStippledPixmap()
+ *
+ * Revision 1.13 1998/10/12 16:49:52 falk
+ * GC functions seperated out into new file
+ *
+ * Revision 1.12 1998/08/07 01:08:37 falk
+ * got rid of dead code
+ *
+ * Revision 1.11 1998/07/28 16:39:09 falk
+ * now uses XtClass(w) instead of w->core.widget_class
+ *
+ * Revision 1.10 1998/06/26 16:27:42 falk
+ * allocShadowColor now handles failure from XAllocColor
+ *
+ * Revision 1.9 1998/06/25 08:09:03 falk
+ * simplified: got rid of WidgetCmap() and WidgetDepth()
+ *
+ * Revision 1.8 1998/06/18 03:12:42 falk
+ * Added local definition of XtAllocateGC() for X11r4 compatibility
+ *
+ * Revision 1.7 1998/06/17 23:49:24 falk
+ * small changes to make lint happier
+ *
+ * Revision 1.6 1998/06/17 23:39:40 falk
+ * STDC declarations added, prototypes updated accordingly.
+ *
+ * Revision 1.5 1998/06/17 23:05:14 falk
+ * removed last reference to Xaw
+ *
+ * Revision 1.4 1998/06/16 16:22:03 falk
+ * Simplified 3-d look. Removed references to Xaw3d. Added bitmaps
+ *
+ * Revision 1.3 1998/06/11 17:12:57 falk
+ * major style change; too many diffs to list.
+ *
+ * Revision 1.2 1998/02/14 07:24:45 falk
+ * wider tab decorations, re-wrote geometry manager.
+ *
+ * Revision 1.1 1997/08/28 05:36:23 falk
+ * Initial revision
+ *
+ */
+
+/*
+ * TODO: min child height = tab height
+ */
+
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xmu/Misc.h>
+
+#include "TabsP.h"
+#include "Gcs.h"
+
+#ifndef XtExposeNoRegion
+#define XtExposeNoRegion 0x80
+#endif
+
+#define MIN_WID 10
+#define MIN_HGT 10
+#define INDENT 3 /* tabs indented from edge by this much */
+#define SPACING 0 /* distance between tabs */
+#define SHADWID 1 /* default shadow width */
+#define TABDELTA 2 /* top tab grows this many pixels */
+#define TABLDELTA 2 /* top tab label offset this many pixels */
+
+
+/****************************************************************
+ *
+ * IndexTabs Resources
+ *
+ ****************************************************************/
+
+#ifdef SUNOS
+static char defaultTranslations[] = "\
+ <BtnUp>: select() \n\
+ <FocusIn>: highlight() \n\
+ <FocusOut>: unhighlight() \n\
+ <Key> : page(select) \n\
+ " ;
+#else
+static char defaultTranslations[] = "\
+ <BtnUp>: select() \n\
+ <FocusIn>: highlight() \n\
+ <FocusOut>: unhighlight() \n\
+ <Key>Page_Up: page(up) \n\
+ <Key>KP_Page_Up: page(up) \n\
+ <Key>Prior: page(up) \n\
+ <Key>KP_Prior: page(up) \n\
+ <Key>Page_Down: page(down) \n\
+ <Key>KP_Page_Down: page(down) \n\
+ <Key>Next: page(down) \n\
+ <Key>KP_Next: page(down) \n\
+ <Key>Home: page(home) \n\
+ <Key>KP_Home: page(home) \n\
+ <Key>End: page(end) \n\
+ <Key>KP_End: page(end) \n\
+ <Key>Up: highlight(up) \n\
+ <Key>KP_Up: highlight(up) \n\
+ <Key>Down: highlight(down) \n\
+ <Key>KP_Down: highlight(down) \n\
+ <Key> : page(select) \n\
+ " ;
+#endif
+
+#ifdef SUNOS
+static char accelTable[] = " #augment\n\
+ <Key> : page(select) \n\
+ " ;
+#else
+static char accelTable[] = " #augment\n\
+ <Key>Page_Up: page(up) \n\
+ <Key>KP_Page_Up: page(up) \n\
+ <Key>Prior: page(up) \n\
+ <Key>KP_Prior: page(up) \n\
+ <Key>Page_Down: page(down) \n\
+ <Key>KP_Page_Down: page(down) \n\
+ <Key>Next: page(down) \n\
+ <Key>KP_Next: page(down) \n\
+ <Key>Home: page(home) \n\
+ <Key>KP_Home: page(home) \n\
+ <Key>End: page(end) \n\
+ <Key>KP_End: page(end) \n\
+ <Key>Up: highlight(up) \n\
+ <Key>KP_Up: highlight(up) \n\
+ <Key>Down: highlight(down) \n\
+ <Key>KP_Down: highlight(down) \n\
+ <Key> : page(select) \n\
+ " ;
+#endif
+static XtAccelerators defaultAccelerators ;
+
+#define offset(field) XtOffsetOf(TabsRec, tabs.field)
+static XtResource resources[] = {
+
+ {XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, sizeof(Boolean),
+ offset(selectInsensitive), XtRImmediate, (XtPointer) True},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ offset(font), XtRString, (XtPointer) XtDefaultFont},
+ {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ offset(internalWidth), XtRImmediate, (XtPointer)4 },
+ {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
+ offset(internalHeight), XtRImmediate, (XtPointer)4 },
+ {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width),
+ XtRImmediate, (XtPointer)0},
+ {XtNtopWidget, XtCTopWidget, XtRWidget, sizeof(Widget),
+ offset(topWidget), XtRImmediate, NULL},
+ {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(callbacks), XtRCallback, NULL},
+ {XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(popdownCallbacks), XtRCallback, NULL},
+ {XtNbeNiceToColormap, XtCBeNiceToColormap, XtRBoolean, sizeof(Boolean),
+ offset(be_nice_to_cmap), XtRImmediate, (XtPointer) True},
+ {XtNtopShadowContrast, XtCTopShadowContrast, XtRInt, sizeof(int),
+ offset(top_shadow_contrast), XtRImmediate, (XtPointer) 20},
+ {XtNbottomShadowContrast, XtCBottomShadowContrast, XtRInt, sizeof(int),
+ offset(bot_shadow_contrast), XtRImmediate, (XtPointer) 40},
+ {XtNinsensitiveContrast, XtCInsensitiveContrast, XtRInt, sizeof(int),
+ offset(insensitive_contrast), XtRImmediate, (XtPointer) 33},
+ {XtNaccelerators, XtCAccelerators, XtRAcceleratorTable,sizeof(XtTranslations),
+ XtOffsetOf(TabsRec,core.accelerators), XtRString, accelTable},
+};
+#undef offset
+
+
+
+ /* constraint resources */
+
+#define offset(field) XtOffsetOf(TabsConstraintsRec, tabs.field)
+static XtResource tabsConstraintResources[] = {
+ {XtNtabLabel, XtCLabel, XtRString, sizeof(String),
+ offset(label), XtRString, NULL},
+ {XtNtabLeftBitmap, XtCLeftBitmap, XtRBitmap, sizeof(Pixmap),
+ offset(left_bitmap), XtRImmediate, None},
+ {XtNtabForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(foreground), XtRString, (XtPointer) XtDefaultForeground},
+ {XtNresizable, XtCResizable, XtRBoolean, sizeof(Boolean),
+ offset(resizable), XtRImmediate, (XtPointer) True},
+} ;
+#undef offset
+
+
+
+
+#if !NeedFunctionPrototypes
+
+ /* FORWARD REFERENCES: */
+
+ /* member functions */
+
+static void TabsClassInit();
+static void TabsInit();
+static void TabsResize();
+static void TabsExpose();
+static void TabsDestroy();
+static void TabsRealize();
+static Boolean TabsSetValues();
+static Boolean TabsAcceptFocus();
+static XtGeometryResult TabsQueryGeometry();
+static XtGeometryResult TabsGeometryManager();
+static void TabsChangeManaged();
+static void TabsConstraintInitialize() ;
+static Boolean TabsConstraintSetValues() ;
+
+ /* action procs */
+
+static void TabsSelect() ;
+static void TabsPage() ;
+static void TabsHighlight() ;
+static void TabsUnhighlight() ;
+
+ /* internal privates */
+
+static void TabsAllocGCs() ; /* get rendering GCs */
+static void TabsFreeGCs() ; /* return rendering GCs */
+static void DrawTabs() ; /* draw all tabs */
+static void DrawTab() ; /* draw one index tab */
+static void DrawFrame() ; /* draw frame around contents */
+static void DrawTrim() ; /* draw trim around a tab */
+static void DrawBorder() ; /* draw border */
+static void DrawHighlight() ; /* draw highlight */
+static void UndrawTab() ; /* undraw interior of a tab */
+static void TabWidth() ; /* recompute tab size */
+static void GetPreferredSizes() ; /* query all children for their sizes */
+static void MaxChild() ; /* find max preferred child size */
+static int PreferredSize() ; /* compute preferred size */
+static int PreferredSize2() ; /* compute preferred size */
+static int PreferredSize3() ; /* compute preferred size */
+static void MakeSizeRequest() ; /* try to change size */
+static void getBitmapInfo() ;
+static int TabLayout() ; /* lay out tabs */
+static void TabsShuffleRows() ; /* bring current tab to bottom row */
+
+static void TabsAllocFgGC() ;
+static void TabsAllocGreyGC() ;
+
+#else
+
+static void TabsClassInit(void) ;
+static void TabsInit( Widget req, Widget new, ArgList, Cardinal *nargs) ;
+static void TabsConstraintInitialize(Widget, Widget, ArgList, Cardinal *) ;
+static void TabsRealize(Widget, Mask *, XSetWindowAttributes *) ;
+static void TabsDestroy( Widget w) ;
+static void TabsResize( Widget w) ;
+static void TabsExpose( Widget w, XEvent *event, Region region) ;
+static Boolean TabsSetValues(Widget, Widget, Widget, ArgList, Cardinal *) ;
+static Boolean TabsAcceptFocus(Widget, Time *);
+static Boolean TabsConstraintSetValues(Widget, Widget, Widget,
+ ArgList, Cardinal *) ;
+static XtGeometryResult TabsQueryGeometry(Widget,
+ XtWidgetGeometry *, XtWidgetGeometry *) ;
+static XtGeometryResult TabsGeometryManager(Widget,
+ XtWidgetGeometry *, XtWidgetGeometry *) ;
+static void TabsChangeManaged( Widget w) ;
+
+static void TabsSelect(Widget, XEvent *, String *, Cardinal *) ;
+static void TabsPage(Widget, XEvent *, String *, Cardinal *) ;
+static void TabsHighlight(Widget, XEvent *, String *, Cardinal *) ;
+static void TabsUnhighlight(Widget, XEvent *, String *, Cardinal *) ;
+
+static void DrawTabs( TabsWidget tw, Bool labels) ;
+static void DrawTab( TabsWidget tw, Widget child, Bool labels) ;
+static void DrawFrame( TabsWidget tw) ;
+static void DrawTrim( TabsWidget, int x, int y,
+ int wid, int hgt, Bool bottom, Bool undraw) ;
+static void DrawBorder( TabsWidget tw, Widget child, Bool undraw) ;
+static void DrawHighlight( TabsWidget tw, Widget child, Bool undraw) ;
+static void UndrawTab( TabsWidget tw, Widget child) ;
+
+static void TabWidth( Widget w) ;
+static int TabLayout( TabsWidget, int wid, Dimension *r_hgt,
+ Bool query_only) ;
+static void GetPreferredSizes(TabsWidget) ;
+static void MaxChild(TabsWidget, Widget except, Dimension, Dimension) ;
+static void TabsShuffleRows( TabsWidget tw) ;
+static int PreferredSize( TabsWidget,
+ Dimension *reply_width, Dimension *reply_height,
+ Dimension *reply_cw, Dimension *reply_ch) ;
+static int PreferredSize2( TabsWidget, int cw, int ch,
+ Dimension *rw, Dimension *rh) ;
+static int PreferredSize3( TabsWidget, int wid, int hgt,
+ Dimension *rw, Dimension *rh) ;
+static void MakeSizeRequest(TabsWidget) ;
+
+static void TabsAllocGCs(TabsWidget) ;
+static void TabsFreeGCs(TabsWidget) ;
+static void getBitmapInfo( TabsWidget tw, TabsConstraints tab) ;
+static void TabsAllocFgGC( TabsWidget tw) ;
+static void TabsAllocGreyGC( TabsWidget tw) ;
+
+#endif
+
+#define AddRect(i,xx,yy,w,h) \
+ do{rects[(i)].x=(xx); rects[i].y=(yy); \
+ rects[i].width=(w); rects[i].height=(h);}while(0)
+
+static XtActionsRec actionsList[] =
+ {
+ {"select", TabsSelect},
+ {"page", TabsPage},
+ {"highlight", TabsHighlight},
+ {"unhighlight", TabsUnhighlight},
+ } ;
+
+
+/****************************************************************
+*
+* Full class record constant
+*
+****************************************************************/
+
+#ifndef USE_MOTIF
+#define SuperClass (&constraintClassRec)
+#else
+#define SuperClass (&xmManagerClassRec)
+#endif
+
+TabsClassRec tabsClassRec = {
+ {
+/* core_class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class_name */ "Tabs",
+ /* widget_size */ sizeof(TabsRec),
+ /* class_initialize */ TabsClassInit,
+ /* class_part_init */ NULL, /* TODO? */
+ /* class_inited */ FALSE,
+ /* initialize */ TabsInit,
+ /* initialize_hook */ NULL,
+ /* realize */ TabsRealize,
+ /* actions */ actionsList,
+ /* num_actions */ XtNumber(actionsList),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ XtExposeCompressMaximal|XtExposeNoRegion,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ TRUE,
+ /* destroy */ TabsDestroy,
+ /* resize */ TabsResize,
+ /* expose */ TabsExpose,
+ /* set_values */ TabsSetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ TabsAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ TabsQueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ {
+/* composite_class fields */
+ /* geometry_manager */ TabsGeometryManager,
+ /* change_managed */ TabsChangeManaged,
+ /* insert_child */ XtInheritInsertChild, /* TODO? */
+ /* delete_child */ XtInheritDeleteChild, /* TODO? */
+ /* extension */ NULL
+ },
+ {
+/* constraint_class fields */
+ /* subresources */ tabsConstraintResources,
+ /* subresource_count */ XtNumber(tabsConstraintResources),
+ /* constraint_size */ sizeof(TabsConstraintsRec),
+ /* initialize */ TabsConstraintInitialize,
+ /* destroy */ NULL,
+ /* set_values */ TabsConstraintSetValues,
+ /* extension */ NULL,
+ },
+#ifdef USE_MOTIF
+/* Manager Class fields */
+ {
+ /* translations */ NULL,
+ /* syn_resources */ NULL,
+ /* num_syn_resources */ 0,
+ /* syn_constraint_resources */ NULL,
+ /* num_syn_constraint_resources */ 0,
+ /* parent_process */ XmInheritParentProcess,
+ /* extension */ NULL
+ },
+#endif
+ {
+/* Tabs class fields */
+ /* extension */ NULL,
+ }
+};
+
+WidgetClass tabsWidgetClass = (WidgetClass)&tabsClassRec;
+
+
+
+#ifdef DEBUG
+#ifdef __STDC__
+#define assert(e) \
+ if(!(e)) fprintf(stderr,"yak! %s at %s:%d\n",#e,__FILE__,__LINE__)
+#else
+#define assert(e) \
+ if(!(e)) fprintf(stderr,"yak! e at %s:%d\n",__FILE__,__LINE__)
+#endif
+#else
+#define assert(e)
+#endif
+
+
+
+
+/****************************************************************
+ *
+ * Member Procedures
+ *
+ ****************************************************************/
+
+static void
+TabsClassInit(void)
+{
+ defaultAccelerators = XtParseAcceleratorTable(accelTable) ;
+ /* TODO: register converter for labels? */
+}
+
+
+
+ /* Init a newly created tabs widget. Compute height of tabs
+ * and optionally compute size of widget. */
+
+/* ARGSUSED */
+
+static void
+TabsInit(Widget request, Widget new, ArgList args, Cardinal *num_args)
+{
+ TabsWidget newTw = (TabsWidget)new;
+
+ newTw->tabs.numRows = 0 ;
+
+ GetPreferredSizes(newTw) ;
+
+ /* height is easy, it's the same for all tabs:
+ * TODO: font height + height of tallest bitmap.
+ */
+ newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ;
+
+ if( newTw->tabs.font != NULL )
+ newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent +
+ newTw->tabs.font->max_bounds.descent ;
+
+ /* GC allocation is deferred until XtRealize() */
+
+ /* if size not explicitly set, set it to our preferred size now. */
+
+ if( request->core.width == 0 || request->core.height == 0 )
+ {
+ Dimension w,h ;
+ PreferredSize(newTw, &w, &h, NULL,NULL) ;
+ if( request->core.width == 0 ) new->core.width = w ;
+ if( request->core.height == 0 ) new->core.height = h ;
+ XtClass(new)->core_class.resize(new) ;
+ }
+
+ /* defer GC allocation, etc., until Realize() time. */
+ newTw->tabs.foregroundGC =
+ newTw->tabs.backgroundGC =
+ newTw->tabs.greyGC =
+ newTw->tabs.topGC =
+ newTw->tabs.botGC = None ;
+
+ newTw->tabs.grey50 = None ;
+
+ newTw->tabs.needs_layout = False ;
+
+ newTw->tabs.hilight = NULL ;
+
+#ifdef USE_MOTIF
+ newTw->manager.navigation_type = XmTAB_GROUP ;
+ newTw->manager.traversal_on = True ;
+#endif
+}
+
+
+ /* Init the constraint part of a new tab child. Compute the
+ * size of the tab.
+ */
+/* ARGSUSED */
+static void
+TabsConstraintInitialize(Widget request, Widget new,
+ ArgList args, Cardinal *num_args)
+{
+ TabsConstraints tab = (TabsConstraints) new->core.constraints ;
+ tab->tabs.greyAlloc = False ; /* defer allocation of pixel */
+
+ getBitmapInfo((TabsWidget)XtParent(new), tab) ;
+ TabWidth(new) ;
+}
+
+
+
+ /* Called when tabs widget first realized. Create the window
+ * and allocate the GCs
+ */
+
+static void
+TabsRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
+{
+ TabsWidget tw = (TabsWidget) w;
+
+ attributes->bit_gravity = NorthWestGravity;
+ *valueMask |= CWBitGravity;
+
+ SuperClass->core_class.realize(w, valueMask, attributes);
+
+ TabsAllocGCs(tw) ;
+}
+
+
+
+static void
+TabsDestroy(Widget w)
+{
+ TabsFreeGCs((TabsWidget)w) ;
+}
+
+
+ /* Parent has resized us. This will require that the tabs be
+ * laid out again.
+ */
+
+static void
+TabsResize(Widget w)
+{
+ TabsWidget tw = (TabsWidget) w;
+ int i ;
+ int num_children = tw->composite.num_children ;
+ Widget *childP ;
+ TabsConstraints tab ;
+ Dimension cw,ch,bw ;
+
+ /* Our size has now been dictated by the parent. Lay out the
+ * tabs, lay out the frame, lay out the children. Remember
+ * that the tabs overlap each other and the frame by shadowWidth.
+ * Also, the top tab is larger than the others, so if there's only
+ * one row, the widget must be made taller to accomodate this.
+ *
+ * Once the tabs are laid out, if there is more than one
+ * row, we may need to shuffle the rows to bring the top tab
+ * to the bottom row.
+ */
+
+ tw->tabs.needs_layout = False ;
+
+ if( num_children > 0 && tw->composite.children != NULL )
+ {
+ /* Loop through the tabs and assign rows & x positions */
+ (void) TabLayout(tw, tw->core.width, NULL, False) ;
+
+ /* assign a top widget, bring it to bottom row. */
+ TabsShuffleRows(tw) ;
+
+ /* now assign child positions & sizes. Positions are all the
+ * same: just inside the frame. Sizes are also all the same.
+ */
+
+ tw->tabs.child_width = cw = tw->core.width - 2 * SHADWID ;
+ tw->tabs.child_height = ch =
+ tw->core.height - tw->tabs.tab_total - 2 * SHADWID ;
+
+
+ for(i=0, childP=tw->composite.children;
+ i < num_children;
+ ++i, ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ tab = (TabsConstraints) (*childP)->core.constraints ;
+ bw = (*childP)->core.border_width ;
+ XtConfigureWidget(*childP, SHADWID,tw->tabs.tab_total+SHADWID,
+ cw-bw*2,ch-bw*2, bw) ;
+ }
+ if( XtIsRealized(w) ) {
+ XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ;
+#ifdef COMMENT
+ /* should not be necessary to explicitly repaint after a
+ * resize, but XEmacs folks tell me it is.
+ */
+ XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ;
+#endif /* COMMENT */
+ }
+ }
+} /* Resize */
+
+
+
+ /* Redraw entire Tabs widget */
+
+/* ARGSUSED */
+static void
+TabsExpose(Widget w, XEvent *event, Region region)
+{
+ TabsWidget tw = (TabsWidget) w;
+
+ if( tw->tabs.needs_layout )
+ XtClass(w)->core_class.resize(w) ;
+
+ DrawTabs(tw, True) ;
+}
+
+
+ /* Called when any Tabs widget resources are changed. */
+
+/* ARGSUSED */
+static Boolean
+TabsSetValues(Widget current, Widget request, Widget new,
+ ArgList args, Cardinal *num_args)
+{
+ TabsWidget curtw = (TabsWidget) current ;
+ TabsWidget tw = (TabsWidget) new ;
+ Boolean needRedraw = False ;
+ Widget *childP ;
+ int i ;
+
+
+ if( tw->tabs.font != curtw->tabs.font ||
+ tw->tabs.internalWidth != curtw->tabs.internalWidth ||
+ tw->tabs.internalHeight != curtw->tabs.internalHeight )
+ {
+ tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID ;
+
+ if( tw->tabs.font != NULL )
+ tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent +
+ tw->tabs.font->max_bounds.descent ;
+
+ /* Tab size has changed. Resize all tabs and request a new size */
+ for(i=0, childP=tw->composite.children;
+ i < tw->composite.num_children;
+ ++i, ++childP)
+ if( XtIsManaged(*childP) )
+ TabWidth(*childP) ;
+ PreferredSize(tw, &tw->core.width, &tw->core.height, NULL,NULL) ;
+ needRedraw = True ;
+ tw->tabs.needs_layout = True ;
+ }
+
+ /* TODO: if any color changes, need to recompute GCs and redraw */
+
+ if( tw->core.background_pixel != curtw->core.background_pixel ||
+ tw->core.background_pixmap != curtw->core.background_pixmap ||
+ tw->tabs.font != curtw->tabs.font )
+ if( XtIsRealized(new) )
+ {
+ TabsFreeGCs(tw) ;
+ TabsAllocGCs(tw) ;
+ needRedraw = True ;
+ }
+
+ if( tw->core.sensitive != curtw->core.sensitive )
+ needRedraw = True ;
+
+ /* If top widget changes, need to change stacking order, redraw tabs.
+ * Window system will handle the redraws.
+ */
+
+ if( tw->tabs.topWidget != curtw->tabs.topWidget )
+ {
+ if( XtIsRealized(tw->tabs.topWidget) )
+ {
+ Widget w = tw->tabs.topWidget ;
+ TabsConstraints tab = (TabsConstraints) w->core.constraints ;
+
+ XRaiseWindow(XtDisplay(w), XtWindow(w)) ;
+#ifdef USE_MOTIF
+ XtVaSetValues(curtw->tabs.topWidget, XmNtraversalOn, False, 0) ;
+ XtVaSetValues(w, XmNtraversalOn, True, 0) ;
+#endif
+
+ if( tab->tabs.row != tw->tabs.numRows-1 )
+ TabsShuffleRows(tw) ;
+
+ needRedraw = True ;
+ }
+ else
+ tw->tabs.needs_layout = True ;
+ }
+
+ return needRedraw ;
+}
+
+
+ /* Called when any child constraint resources change. */
+
+/* ARGSUSED */
+static Boolean
+TabsConstraintSetValues(Widget current, Widget request, Widget new,
+ ArgList args, Cardinal *num_args)
+{
+ TabsWidget tw = (TabsWidget) XtParent(new) ;
+ TabsConstraints ctab = (TabsConstraints) current->core.constraints ;
+ TabsConstraints tab = (TabsConstraints) new->core.constraints ;
+
+
+ /* if label changes, need to re-layout the entire widget */
+ /* if foreground changes, need to redraw tab label */
+
+ /* TODO: only need resize of new bitmap has different dimensions
+ * from old bitmap.
+ */
+
+ if( tab->tabs.label != ctab->tabs.label || /* Tab size has changed. */
+ tab->tabs.left_bitmap != ctab->tabs.left_bitmap )
+ {
+ TabWidth(new) ;
+ tw->tabs.needs_layout = True ;
+
+ if( tab->tabs.left_bitmap != ctab->tabs.left_bitmap )
+ getBitmapInfo(tw, tab) ;
+
+ /* If there are no subclass ConstraintSetValues procedures remaining
+ * to be invoked, and if the preferred size has changed, ask
+ * for a resize.
+ */
+ if( XtClass((Widget)tw) == tabsWidgetClass )
+ MakeSizeRequest(tw) ;
+ }
+
+
+ /* The child widget itself never needs a redisplay, but the parent
+ * Tabs widget might.
+ */
+
+ if( XtIsRealized(new) )
+ {
+ if( tw->tabs.needs_layout ) {
+ XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ;
+ XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ;
+ }
+
+ else if( tab->tabs.foreground != ctab->tabs.foreground )
+ DrawTab(tw, new, True) ;
+ }
+
+ return False ;
+}
+
+
+static Boolean
+TabsAcceptFocus(Widget w, Time *t)
+{
+ if( !w->core.being_destroyed && XtIsRealized(w) &&
+ XtIsSensitive(w) && XtIsManaged(w) && w->core.visible )
+ {
+ Widget p ;
+ for(p = XtParent(w); !XtIsShell(p); p = XtParent(p)) ;
+ XtSetKeyboardFocus(p,w) ;
+ return True ;
+ }
+ else
+ return False ;
+}
+
+
+
+/*
+ * Return preferred size. Happily accept anything >= our preferred size.
+ * (TODO: is that the right thing to do? Should we always return "almost"
+ * if offerred more than we need?)
+ */
+
+static XtGeometryResult
+TabsQueryGeometry(Widget w,
+ XtWidgetGeometry *intended, XtWidgetGeometry *preferred)
+{
+ register TabsWidget tw = (TabsWidget)w ;
+ XtGeometryMask mode = intended->request_mode ;
+
+ preferred->request_mode = CWWidth | CWHeight ;
+ PreferredSize(tw, &preferred->width, &preferred->height, NULL,NULL) ;
+
+ if( (!(mode & CWWidth) || intended->width == w->core.width) &&
+ (!(mode & CWHeight) || intended->height == w->core.height) )
+ return XtGeometryNo ;
+
+ if( (!(mode & CWWidth) || intended->width >= preferred->width) &&
+ (!(mode & CWHeight) || intended->height >= preferred->height) )
+ return XtGeometryYes;
+
+ return XtGeometryAlmost;
+}
+
+
+
+/*
+ * Geometry Manager; called when a child wants to be resized.
+ */
+
+static XtGeometryResult
+TabsGeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *reply)
+{
+ TabsWidget tw = (TabsWidget) XtParent(w);
+ Dimension s = SHADWID ;
+ TabsConstraints tab = (TabsConstraints)w->core.constraints;
+ XtGeometryResult result ;
+ Dimension rw, rh ;
+
+ /* Position request always denied */
+
+ if( ((req->request_mode & CWX) && req->x != w->core.x) ||
+ ((req->request_mode & CWY) && req->y != w->core.y) ||
+ !tab->tabs.resizable )
+ return XtGeometryNo ;
+
+ /* Make all three fields in the request valid */
+ if( !(req->request_mode & CWWidth) )
+ req->width = w->core.width;
+ if( !(req->request_mode & CWHeight) )
+ req->height = w->core.height;
+ if( !(req->request_mode & CWBorderWidth) )
+ req->border_width = w->core.border_width;
+
+ if( req->width == w->core.width &&
+ req->height == w->core.height &&
+ req->border_width == w->core.border_width )
+ return XtGeometryNo ;
+
+ rw = req->width + 2 * req->border_width ;
+ rh = req->height + 2 * req->border_width ;
+
+ /* find out how big the children want to be now */
+ MaxChild(tw, w, rw, rh) ;
+
+
+ /* Size changes must see if the new size can be accomodated.
+ * The Tabs widget keeps all of its children the same
+ * size. A request to shrink will be accepted only if the
+ * new size is still big enough for all other children. A
+ * request to shrink that is not big enough for all children
+ * returns an "almost" response with the new proposed size
+ * or a "no" response if unable to shrink at all.
+ *
+ * A request to grow will be accepted only if the Tabs parent can
+ * grow to accomodate.
+ *
+ * TODO:
+ * We could get fancy here and re-arrange the tabs if it is
+ * necessary to compromise with the parent, but we'll save that
+ * for another day.
+ */
+
+ if (req->request_mode & (CWWidth | CWHeight | CWBorderWidth))
+ {
+ Dimension cw,ch ; /* children's preferred size */
+ Dimension aw,ah ; /* available size we can give child */
+ Dimension th ; /* space used by tabs */
+ Dimension wid,hgt ; /* Tabs widget size */
+
+ cw = tw->tabs.max_cw ;
+ ch = tw->tabs.max_ch ;
+
+ /* find out what *my* resulting preferred size would be */
+
+ PreferredSize2(tw, cw, ch, &wid, &hgt) ;
+
+ /* Would my size change? If so, ask to be resized. */
+
+ if( wid != tw->core.width || hgt != tw->core.height )
+ {
+ Dimension oldWid = tw->core.width, oldHgt = tw->core.height ;
+ XtWidgetGeometry myrequest, myreply ;
+
+ myrequest.width = wid ;
+ myrequest.height = hgt ;
+ myrequest.request_mode = CWWidth | CWHeight ;
+
+ /* If child is only querying, or if we're going to have to
+ * offer the child a compromise, then make this a query only.
+ */
+
+ if( (req->request_mode & XtCWQueryOnly) || rw < cw || rh < ch )
+ myrequest.request_mode |= XtCWQueryOnly ;
+
+ result = XtMakeGeometryRequest((Widget)tw, &myrequest, &myreply) ;
+
+ /* !$@# Athena Box widget changes the core size even if QueryOnly
+ * is set. I'm convinced this is a bug. At any rate, to work
+ * around the bug, we need to restore the core size after every
+ * query geometry request. This is only partly effective,
+ * as there may be other boxes further up the tree.
+ */
+ if( myrequest.request_mode & XtCWQueryOnly ) {
+ tw->core.width = oldWid ;
+ tw->core.height = oldHgt ;
+ }
+
+ /* based on the parent's response, determine what the
+ * resulting Tabs widget size would be.
+ */
+
+ switch( result ) {
+ case XtGeometryYes:
+ case XtGeometryDone:
+ tw->tabs.needs_layout = True ;
+ break ;
+
+ case XtGeometryNo:
+ wid = tw->core.width ;
+ hgt = tw->core.height ;
+ break ;
+
+ case XtGeometryAlmost:
+ wid = myreply.width ;
+ hgt = myreply.height ;
+ tw->tabs.needs_layout = True ;
+ break ;
+ }
+ }
+
+ /* Within the constraints imposed by the parent, what is
+ * the max size we can give the child?
+ */
+ (void) TabLayout(tw, wid, &th, True) ;
+ aw = wid - 2*s ;
+ ah = hgt - th - 2*s ;
+
+ /* OK, make our decision. If requested size is >= max sibling
+ * preferred size, AND requested size <= available size, then
+ * we accept. Otherwise, we offer a compromise.
+ */
+
+ if( rw == aw && rh == ah )
+ {
+ /* Acceptable. If this wasn't a query, change *all* children
+ * to this size.
+ */
+ if( req->request_mode & XtCWQueryOnly )
+ return XtGeometryYes ;
+ else
+ {
+ Widget *childP = tw->composite.children ;
+ int i,bw ;
+ w->core.border_width = req->border_width ;
+ for(i=tw->composite.num_children; --i >= 0; ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ bw = (*childP)->core.border_width ;
+ XtConfigureWidget(*childP, s,tw->tabs.tab_total+s,
+ rw-2*bw, rh-2*bw, bw) ;
+ }
+#ifdef COMMENT
+ /* TODO: under what conditions will we need to redraw? */
+ XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ;
+ XtClass(tw)->core_class.expose((Widget)tw,NULL,NULL) ;
+#endif /* COMMENT */
+ return XtGeometryDone ;
+ }
+ }
+
+ /* Cannot grant child's request. Describe what we *can* do
+ * and return counter-offer.
+ */
+ reply->width = aw - 2 * req->border_width ;
+ reply->height = ah - 2 * req->border_width ;
+ reply->border_width = req->border_width ;
+ reply->request_mode = CWWidth | CWHeight | CWBorderWidth ;
+ return XtGeometryAlmost ;
+ }
+
+ return XtGeometryYes ;
+}
+
+
+
+
+ /* The number of children we manage has changed; recompute
+ * size from scratch.
+ */
+
+static void
+TabsChangeManaged(Widget w)
+{
+ TabsWidget tw = (TabsWidget)w ;
+ Widget *childP = tw->composite.children ;
+ int i ;
+
+ if( tw->tabs.topWidget != NULL &&
+ ( !XtIsManaged(tw->tabs.topWidget) ||
+ tw->tabs.topWidget->core.being_destroyed ) )
+ tw->tabs.topWidget = NULL ;
+
+ GetPreferredSizes(tw) ;
+ MakeSizeRequest(tw) ;
+
+ XtClass(w)->core_class.resize(w) ;
+ if( XtIsRealized(w) )
+ {
+ Display *dpy = XtDisplay(w) ;
+ XClearWindow(dpy, XtWindow(w)) ;
+ XtClass(w)->core_class.expose(w,NULL,NULL) ;
+
+ /* make sure the top widget stays on top. This requires
+ * making sure that all new children are realized first.
+ */
+ if( tw->tabs.topWidget != NULL && XtIsRealized(tw->tabs.topWidget) )
+ {
+ for(i=tw->composite.num_children; --i >= 0; ++childP)
+ if( !XtIsRealized(*childP) )
+ XtRealizeWidget(*childP) ;
+
+ XRaiseWindow(dpy, XtWindow(tw->tabs.topWidget)) ;
+ }
+ }
+
+#ifdef USE_MOTIF
+ /* Only top widget may receive input */
+
+ for(childP = tw->composite.children, i=tw->composite.num_children;
+ --i >= 0;
+ ++childP)
+ {
+ XtVaSetValues(*childP, XmNtraversalOn, False, 0) ;
+ }
+
+ if( tw->tabs.topWidget != NULL )
+ XtVaSetValues(tw->tabs.topWidget, XmNtraversalOn, True, 0) ;
+#endif
+}
+
+
+
+
+/****************************************************************
+ *
+ * Action Procedures
+ *
+ ****************************************************************/
+
+
+ /* User clicks on a tab, figure out which one it was. */
+
+/* ARGSUSED */
+static void
+TabsSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ TabsWidget tw = (TabsWidget) w ;
+ Widget *childP ;
+ Position x,y ;
+ Dimension h = tw->tabs.tab_height ;
+ int i ;
+
+#ifdef USE_MOTIF
+ XmProcessTraversal (w, XmTRAVERSE_CURRENT) ;
+#endif
+
+ /* TODO: is there an Xmu function or something to do this instead? */
+ switch( event->type ) {
+ case ButtonPress:
+ case ButtonRelease:
+ x = event->xbutton.x ; y = event->xbutton.y ; break ;
+ case KeyPress:
+ case KeyRelease:
+ x = event->xkey.x ; y = event->xkey.y ; break ;
+ default:
+ return ;
+ }
+
+ /* TODO: determine which tab was clicked, if any. Set that
+ * widget to be top of stacking order with XawTabsSetTop().
+ */
+ for(i=0, childP=tw->composite.children;
+ i < tw->composite.num_children;
+ ++i, ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ TabsConstraints tab = (TabsConstraints)(*childP)->core.constraints;
+ if( x > tab->tabs.x && x < tab->tabs.x + tab->tabs.width &&
+ y > tab->tabs.y && y < tab->tabs.y + h )
+ {
+ if( *childP != tw->tabs.topWidget &&
+ (XtIsSensitive(*childP) || tw->tabs.selectInsensitive) )
+ XawTabsSetTop(*childP, True) ;
+ break ;
+ }
+ }
+}
+
+
+ /* User hits a key */
+
+static void
+TabsPage(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ TabsWidget tw = (TabsWidget) w ;
+ Widget newtop ;
+ Widget *childP ;
+ int idx ;
+ int nc = tw->composite.num_children ;
+
+ if( nc <= 0 )
+ return ;
+
+ if( *num_params < 1 ) {
+ XtAppWarning(XtWidgetToApplicationContext(w),
+ "Tabs: page() action called with no arguments") ;
+ return ;
+ }
+
+ if( tw->tabs.topWidget == NULL )
+ tw->tabs.topWidget = tw->composite.children[0] ;
+
+ for(idx=0, childP=tw->composite.children; idx < nc; ++idx, ++childP )
+ if( tw->tabs.topWidget == *childP )
+ break ;
+
+ switch( params[0][0] ) {
+ case 'u': /* up */
+ case 'U':
+ if( --idx < 0 )
+ idx = nc-1 ;
+ newtop = tw->composite.children[idx] ;
+ break ;
+
+ case 'd': /* down */
+ case 'D':
+ if( ++idx >= nc )
+ idx = 0 ;
+ newtop = tw->composite.children[idx] ;
+ break ;
+
+ case 'h':
+ case 'H':
+ default:
+ newtop = tw->composite.children[0] ;
+ break ;
+
+ case 'e':
+ case 'E':
+ newtop = tw->composite.children[nc-1] ;
+ break ;
+
+ case 's': /* selected */
+ case 'S':
+ if( (newtop = tw->tabs.hilight) == NULL )
+ return ;
+ break ;
+ }
+
+ XawTabsSetTop(newtop, True) ;
+}
+
+
+ /* User hits up/down key */
+
+static void
+TabsHighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ TabsWidget tw = (TabsWidget) w ;
+ Widget newhl ;
+ Widget *childP ;
+ int idx ;
+ int nc = tw->composite.num_children ;
+
+ if( nc <= 0 )
+ return ;
+
+ if( *num_params < 1 )
+ {
+ if( tw->tabs.hilight != NULL )
+ DrawHighlight(tw, tw->tabs.hilight, False) ;
+ return ;
+ }
+
+ if( tw->tabs.hilight == NULL )
+ newhl = tw->composite.children[0] ;
+
+ else
+ {
+ /* find index of currently highlit child */
+ for(idx=0, childP=tw->composite.children; idx < nc; ++idx, ++childP )
+ if( tw->tabs.hilight == *childP )
+ break ;
+
+ switch( params[0][0] ) {
+ case 'u': /* up */
+ case 'U':
+ if( --idx < 0 )
+ idx = nc-1 ;
+ newhl = tw->composite.children[idx] ;
+ break ;
+
+ case 'd': /* down */
+ case 'D':
+ if( ++idx >= nc )
+ idx = 0 ;
+ newhl = tw->composite.children[idx] ;
+ break ;
+
+ case 'h':
+ case 'H':
+ newhl = tw->composite.children[0] ;
+ break ;
+
+ case 'e':
+ case 'E':
+ newhl = tw->composite.children[nc-1] ;
+ break ;
+
+ default:
+ newhl = tw->tabs.hilight ;
+ break ;
+ }
+ }
+
+ XawTabsSetHighlight(w, newhl) ;
+}
+
+
+
+static void
+TabsUnhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ TabsWidget tw = (TabsWidget) w ;
+ int nc = tw->composite.num_children ;
+
+ if( nc <= 0 )
+ return ;
+
+ if( tw->tabs.hilight != NULL )
+ DrawHighlight(tw, tw->tabs.hilight, True) ;
+}
+
+
+
+
+
+/****************************************************************
+ *
+ * Public Procedures
+ *
+ ****************************************************************/
+
+
+ /* Set the top tab, optionally call all callbacks. */
+void
+XawTabsSetTop(Widget w, Bool callCallbacks)
+{
+ TabsWidget tw = (TabsWidget)w->core.parent ;
+ TabsConstraints tab ;
+ Widget oldtop = tw->tabs.topWidget ;
+
+ if( !XtIsSubclass(w->core.parent, tabsWidgetClass) )
+ {
+ char line[256] ;
+ sprintf(line, "XawTabsSetTop: widget \"%.64s\" is not the child of a tabs widget.", XtName(w)) ;
+ XtAppWarning(XtWidgetToApplicationContext(w), line) ;
+ return ;
+ }
+
+ if( callCallbacks )
+ XtCallCallbackList(w, tw->tabs.popdownCallbacks,
+ (XtPointer)tw->tabs.topWidget) ;
+
+ if( !XtIsRealized(w) ) {
+ tw->tabs.topWidget = w ;
+ tw->tabs.needs_layout = True ;
+ return ;
+ }
+
+ XRaiseWindow(XtDisplay(w), XtWindow(w)) ;
+#ifdef USE_MOTIF
+ XtVaSetValues(oldtop, XmNtraversalOn, False, 0) ;
+ XtVaSetValues(w, XmNtraversalOn, True, 0) ;
+#endif
+
+ tab = (TabsConstraints) w->core.constraints ;
+ if( tab->tabs.row == 0 )
+ {
+ /* Easy case; undraw current top, undraw new top, assign new
+ * top, redraw all borders.
+ * We *could* just erase and execute a full redraw, but I like to
+ * reduce screen flicker.
+ */
+ UndrawTab(tw, oldtop) ; /* undraw old */
+ DrawBorder(tw, oldtop, True) ;
+ UndrawTab(tw, w) ; /* undraw new */
+ DrawBorder(tw, w, True) ;
+ tw->tabs.topWidget = w ;
+ DrawTab(tw, oldtop, True) ; /* redraw old */
+ DrawTab(tw, w, True) ; /* redraw new */
+ DrawTabs(tw, False) ;
+ }
+ else
+ {
+ tw->tabs.topWidget = w ;
+ TabsShuffleRows(tw) ;
+ XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ;
+ XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ;
+ }
+
+ XawTabsSetHighlight((Widget)tw, w) ;
+
+ if( callCallbacks )
+ XtCallCallbackList(w, tw->tabs.callbacks, (XtPointer)w) ;
+}
+
+
+ /* Set the top tab, optionally call all callbacks. */
+void
+XawTabsSetHighlight(Widget t, Widget w)
+{
+ TabsWidget tw = (TabsWidget)t ;
+
+ if( !XtIsSubclass(t, tabsWidgetClass) )
+ return ;
+
+ if( XtIsRealized(t) && w != tw->tabs.hilight )
+ {
+ if( tw->tabs.hilight != NULL )
+ DrawHighlight(tw, tw->tabs.hilight, True) ;
+ if( w != NULL )
+ DrawHighlight(tw, w, False) ;
+ }
+
+ tw->tabs.hilight = w ;
+}
+
+
+
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+
+static void
+TabsAllocGCs(TabsWidget tw)
+{
+ TabsAllocFgGC(tw) ;
+ TabsAllocGreyGC(tw) ;
+ tw->tabs.backgroundGC = AllocBackgroundGC((Widget)tw, None) ;
+ tw->tabs.topGC = AllocTopShadowGC((Widget)tw,
+ tw->tabs.top_shadow_contrast, tw->tabs.be_nice_to_cmap) ;
+ tw->tabs.botGC = AllocBotShadowGC((Widget)tw,
+ tw->tabs.bot_shadow_contrast, tw->tabs.be_nice_to_cmap) ;
+}
+
+
+static void
+TabsFreeGCs(TabsWidget tw)
+{
+ Widget w = (Widget) tw;
+
+ XtReleaseGC(w, tw->tabs.foregroundGC) ;
+ XtReleaseGC(w, tw->tabs.greyGC) ;
+ XtReleaseGC(w, tw->tabs.backgroundGC) ;
+ XtReleaseGC(w, tw->tabs.topGC) ;
+ XtReleaseGC(w, tw->tabs.botGC) ;
+#ifdef USE_XMU_STIPPLE
+ XmuReleaseStippledPixmap(XtScreen(w), tw->tabs.grey50) ;
+#else
+/* XFreePixmap(XtDisplay(w), tw->tabs.grey50 );*/
+ ;
+#endif
+}
+
+
+
+
+
+ /* Redraw entire Tabs widget */
+
+static void
+DrawTabs(TabsWidget tw, Bool labels)
+{
+ Widget *childP ;
+ int i,j ;
+ Dimension s = SHADWID ;
+ Dimension th = tw->tabs.tab_height ;
+ Position y ;
+ TabsConstraints tab ;
+
+ /* draw tabs and frames by row except for the top tab, which
+ * is drawn last. (This is inefficiently written, but should not
+ * be too slow as long as there are not a lot of rows.)
+ */
+
+ y = tw->tabs.numRows == 1 ? TABDELTA : 0 ;
+ for(i=0; i<tw->tabs.numRows; ++i, y += th)
+ {
+ for( j=tw->composite.num_children, childP=tw->composite.children;
+ --j >= 0; ++childP )
+ if( XtIsManaged(*childP) )
+ {
+ tab = (TabsConstraints)(*childP)->core.constraints;
+ if( tab->tabs.row == i && *childP != tw->tabs.topWidget )
+ DrawTab(tw, *childP, labels) ;
+ }
+ if( i != tw->tabs.numRows -1 )
+ DrawTrim(tw, 0,y+th, tw->core.width, th+s, False,False) ;
+ }
+
+ DrawFrame(tw) ;
+
+ /* and now the top tab */
+ if( tw->tabs.topWidget != NULL )
+ DrawTab(tw, tw->tabs.topWidget, labels) ;
+}
+
+
+
+/* Draw one tab. Corners are rounded very slightly. */
+
+static void
+DrawTab(TabsWidget tw, Widget child, Bool labels)
+{
+ GC gc ;
+ int x,y ;
+
+ DrawBorder(tw, child, False) ;
+
+ if( labels )
+ {
+ TabsConstraints tab = (TabsConstraints)child->core.constraints;
+ Display *dpy = XtDisplay((Widget)tw) ;
+ Window win = XtWindow((Widget)tw) ;
+ String lbl = tab->tabs.label != NULL ?
+ tab->tabs.label : XtName(child) ;
+
+ if( XtIsSensitive(child) )
+ {
+ gc = tw->tabs.foregroundGC ;
+ XSetForeground(dpy, gc, tab->tabs.foreground) ;
+ }
+ else
+ {
+ /* grey pixel allocation deferred until now */
+ if( !tab->tabs.greyAlloc )
+ {
+ if( tw->tabs.be_nice_to_cmap || tw->core.depth == 1 )
+ tab->tabs.grey = tab->tabs.foreground ;
+ else
+ tab->tabs.grey = AllocGreyPixel((Widget)tw,
+ tab->tabs.foreground,
+ tw->core.background_pixel,
+ tw->tabs.insensitive_contrast ) ;
+ tab->tabs.greyAlloc = True ;
+ }
+ gc = tw->tabs.greyGC ;
+ XSetForeground(dpy, gc, tab->tabs.grey) ;
+ }
+
+ x = tab->tabs.x ;
+ y = tab->tabs.y ;
+ if( child == tw->tabs.topWidget )
+ y -= TABLDELTA ;
+
+ if( tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0 )
+ {
+ if( tab->tabs.lbm_depth == 1 )
+ XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc,
+ 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height,
+ x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L) ;
+ else
+ XCopyArea(dpy, tab->tabs.left_bitmap, win,gc,
+ 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height,
+ x+tab->tabs.lbm_x, y+tab->tabs.lbm_y) ;
+ }
+
+ if( lbl != NULL && tw->tabs.font != NULL )
+ XDrawString(dpy,win,gc,
+ x+tab->tabs.l_x, y+tab->tabs.l_y,
+ lbl, (int)strlen(lbl)) ;
+ }
+
+ if( child == tw->tabs.hilight )
+ DrawHighlight(tw, child, False) ;
+}
+
+
+ /* draw frame all the way around the child windows. */
+
+static void
+DrawFrame(TabsWidget tw)
+{
+ GC topgc = tw->tabs.topGC ;
+ GC botgc = tw->tabs.botGC ;
+ Dimension s = SHADWID ;
+ Dimension ch = tw->tabs.child_height ;
+
+ Draw3dBox((Widget)tw, 0,tw->tabs.tab_total,
+ tw->core.width, ch+2*s, s, topgc, botgc) ;
+}
+
+
+ /* draw trim around a tab or underneath a row of tabs */
+
+static void
+DrawTrim(TabsWidget tw, /* widget */
+ int x, /* upper-left corner */
+ int y,
+ int wid, /* total size */
+ int hgt,
+ Bool bottom, /* draw bottom? */
+ Bool undraw) /* undraw all */
+{
+ Display *dpy = XtDisplay((Widget)tw) ;
+ Window win = XtWindow((Widget)tw) ;
+ GC bggc = tw->tabs.backgroundGC ;
+ GC topgc = undraw ? bggc : tw->tabs.topGC ;
+ GC botgc = undraw ? bggc : tw->tabs.botGC ;
+
+ if( bottom )
+ XDrawLine(dpy,win,bggc, x,y+hgt-1, x+wid-1,y+hgt-1) ; /* bottom */
+ XDrawLine(dpy,win,topgc, x,y+2, x,y+hgt-2) ; /* left */
+ XDrawPoint(dpy,win,topgc, x+1,y+1) ; /* corner */
+ XDrawLine(dpy,win,topgc, x+2,y, x+wid-3,y) ; /* top */
+ XDrawLine(dpy,win,botgc, x+wid-2,y+1, x+wid-2,y+hgt-2) ; /* right */
+ XDrawLine(dpy,win,botgc, x+wid-1,y+2, x+wid-1,y+hgt-2) ; /* right */
+}
+
+
+/* Draw one tab border. */
+
+static void
+DrawBorder(TabsWidget tw, Widget child, Bool undraw)
+{
+ TabsConstraints tab = (TabsConstraints)child->core.constraints;
+ Position x = tab->tabs.x ;
+ Position y = tab->tabs.y ;
+ Dimension twid = tab->tabs.width ;
+ Dimension thgt = tw->tabs.tab_height ;
+
+ /* top tab requires a little special attention; it overlaps
+ * neighboring tabs slightly, so the background must be cleared
+ * in the region of the overlap to partially erase those neighbors.
+ * TODO: is this worth doing with regions instead?
+ */
+ if( child == tw->tabs.topWidget )
+ {
+ Display *dpy = XtDisplay((Widget)tw) ;
+ Window win = XtWindow((Widget)tw) ;
+ GC bggc = tw->tabs.backgroundGC ;
+ XRectangle rects[3] ;
+ x -= TABDELTA ;
+ y -= TABDELTA ;
+ twid += TABDELTA*2 ;
+ thgt += TABDELTA ;
+ AddRect(0, x,y+1,twid,TABDELTA) ;
+ AddRect(1, x+1,y,TABDELTA,thgt) ;
+ AddRect(2, x+twid-TABDELTA-1,y,TABDELTA,thgt) ;
+ XFillRectangles(dpy,win,bggc, rects, 3) ;
+ }
+
+ DrawTrim(tw, x,y,twid,thgt+1, child == tw->tabs.topWidget, undraw) ;
+}
+
+
+/* Draw highlight around tab that has focus */
+
+static void
+DrawHighlight(TabsWidget tw, Widget child, Bool undraw)
+{
+ TabsConstraints tab = (TabsConstraints)child->core.constraints;
+ Display *dpy = XtDisplay((Widget)tw) ;
+ Window win = XtWindow((Widget)tw) ;
+ GC gc ;
+ Position x = tab->tabs.x ;
+ Position y = tab->tabs.y ;
+ Dimension wid = tab->tabs.width ;
+ Dimension hgt = tw->tabs.tab_height ;
+ XPoint points[6] ;
+
+ /* top tab does not have a highlight */
+
+ if( child == tw->tabs.topWidget )
+ return ;
+
+ if( undraw )
+ gc = tw->tabs.backgroundGC ;
+
+ else if( XtIsSensitive(child) )
+ {
+ gc = tw->tabs.foregroundGC ;
+ XSetForeground(dpy, gc, tab->tabs.foreground) ;
+ }
+ else
+ {
+ gc = tw->tabs.greyGC ;
+ XSetForeground(dpy, gc, tab->tabs.grey) ;
+ }
+
+ points[0].x = x+1 ; points[0].y = y+hgt-1 ;
+ points[1].x = x+1 ; points[1].y = y+2 ;
+ points[2].x = x+2 ; points[2].y = y+1 ;
+ points[3].x = x+wid-4 ; points[3].y = y+1 ;
+ points[4].x = x+wid-3 ; points[4].y = y+2 ;
+ points[5].x = x+wid-3 ; points[5].y = y+hgt-1 ;
+
+ XDrawLines(dpy,win,gc, points,6, CoordModeOrigin) ;
+}
+
+
+/* Undraw one tab interior */
+
+static void
+UndrawTab(TabsWidget tw, Widget child)
+{
+ TabsConstraints tab = (TabsConstraints)child->core.constraints;
+ Position x = tab->tabs.x ;
+ Position y = tab->tabs.y ;
+ Dimension twid = tab->tabs.width ;
+ Dimension thgt = tw->tabs.tab_height ;
+ Display *dpy = XtDisplay((Widget)tw) ;
+ Window win = XtWindow((Widget)tw) ;
+ GC bggc = tw->tabs.backgroundGC ;
+
+ XFillRectangle(dpy,win,bggc, x,y, twid,thgt) ;
+}
+
+
+
+
+
+ /* GEOMETRY UTILITIES */
+
+ /* Overview:
+ *
+ * MaxChild(): ask all children (except possibly one) their
+ * preferred sizes, set max_cw, max_ch accordingly.
+ *
+ * GetPreferredSizes(): ask all children their preferred sizes,
+ * set max_cw, max_ch accordingly.
+ *
+ * PreferredSize(): given max_cw, max_ch, return tabs widget
+ * preferred size. Iterate with other widths in order to get
+ * a reasonable aspect ratio.
+ *
+ * PreferredSize2(): Given child dimensions, return Tabs
+ * widget dimensions.
+ *
+ * PreferredSize3(): Same, except given child dimensions plus
+ * shadow.
+ */
+
+
+ /* Compute the width of one child's tab. Positions will be computed
+ * elsewhere.
+ *
+ * height: font height + vertical_space*2 + shadowWid*2
+ * width: string width + horizontal_space*2 + shadowWid*2
+ *
+ * All tabs are the same height, so that is computed elsewhere.
+ */
+
+static void
+TabWidth(Widget w)
+{
+ TabsConstraints tab = (TabsConstraints) w->core.constraints ;
+ TabsWidget tw = (TabsWidget)XtParent(w) ;
+ String lbl = tab->tabs.label != NULL ?
+ tab->tabs.label : XtName(w) ;
+ XFontStruct *font = tw->tabs.font ;
+ int iw = tw->tabs.internalWidth ;
+
+ tab->tabs.width = iw + SHADWID*2 ;
+ tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ;
+
+ if( tab->tabs.left_bitmap != None )
+ {
+ tab->tabs.width += tab->tabs.lbm_width + iw ;
+ tab->tabs.l_x += tab->tabs.lbm_width + iw ;
+ tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ;
+ }
+
+ if( lbl != NULL && font != NULL )
+ {
+ tab->tabs.width += XTextWidth( font, lbl, (int)strlen(lbl) ) + iw ;
+ tab->tabs.l_y = (tw->tabs.tab_height +
+ tw->tabs.font->max_bounds.ascent -
+ tw->tabs.font->max_bounds.descent)/2 ;
+ }
+}
+
+
+
+ /* Lay out tabs to fit in given width. Compute x,y position and
+ * row number for each tab. Return number of rows and total height
+ * required by all tabs. If there is only one row, add TABDELTA
+ * height to the total. Rows are assigned bottom to top.
+ *
+ * Tabs are indented from the edges by INDENT.
+ *
+ * TODO: if they require more than two rows and the total height:width
+ * ratio is more than 2:1, then try something else.
+ */
+
+static int
+TabLayout(TabsWidget tw, int wid, Dimension *reply_height, Bool query_only)
+{
+ int i, row ;
+ int num_children = tw->composite.num_children ;
+ Widget *childP ;
+ Dimension w ;
+ Position x,y ;
+ TabsConstraints tab ;
+
+ /* Algorithm: loop through children, assign X positions. If a tab
+ * would extend beyond the right edge, start a new row. After all
+ * rows are assigned, make a second pass and assign Y positions.
+ */
+
+ if( num_children > 0 )
+ {
+ /* Loop through the tabs and see how much space they need. */
+
+ row = 0 ;
+ x = INDENT ;
+ y = 0 ;
+ wid -= INDENT ;
+ for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ tab = (TabsConstraints) (*childP)->core.constraints ;
+ w = tab->tabs.width ;
+ if( x + w > wid ) { /* new row */
+ ++row ;
+ x = INDENT ;
+ y += tw->tabs.tab_height ;
+ }
+ if( !query_only ) {
+ tab->tabs.x = x ;
+ tab->tabs.y = y ;
+ tab->tabs.row = row ;
+ }
+ x += w + SPACING ;
+ }
+ /* If there was only one row, increse the height by TABDELTA */
+ if( ++row == 1 )
+ {
+ y = TABDELTA ;
+ if( !query_only )
+ for(i=num_children, childP=tw->composite.children;
+ --i >= 0 ; ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ tab = (TabsConstraints) (*childP)->core.constraints ;
+ tab->tabs.y = y ;
+ }
+ }
+ y += tw->tabs.tab_height ;
+ }
+ else
+ row = y = 0 ;
+
+ if( !query_only ) {
+ tw->tabs.tab_total = y ;
+ tw->tabs.numRows = row ;
+ }
+
+ if( reply_height != NULL )
+ *reply_height = y ;
+
+ return row ;
+}
+
+
+
+ /* Find max preferred child size. Returned sizes include child
+ * border widths.
+ */
+
+static void
+GetPreferredSizes(TabsWidget tw)
+{
+ MaxChild(tw, NULL, 0,0) ;
+}
+
+
+
+ /* Find max preferred child size. Returned sizes include child
+ * border widths. If except is non-null, don't ask that one.
+ */
+
+static void
+MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch)
+{
+ int i ;
+ Widget *childP = tw->composite.children ;
+ XtWidgetGeometry preferred ;
+
+ for(i=tw->composite.num_children; --i >=0; ++childP)
+ if( XtIsManaged(*childP) && *childP != except )
+ {
+ (void) XtQueryGeometry(*childP, NULL, &preferred) ;
+ cw = Max(cw, preferred.width + preferred.border_width * 2 ) ;
+ ch = Max(ch, preferred.height + preferred.border_width * 2 ) ;
+ }
+
+ tw->tabs.max_cw = cw ;
+ tw->tabs.max_ch = ch ;
+}
+
+
+
+ /* rotate row numbers to bring current widget to bottom row,
+ * compute y positions for all tabs
+ */
+
+static void
+TabsShuffleRows(TabsWidget tw)
+{
+ TabsConstraints tab ;
+ int move ;
+ int nrows ;
+ Widget *childP ;
+ Dimension th = tw->tabs.tab_height ;
+ Position bottom ;
+ int i ;
+
+ /* There must be a top widget. If not, assign one. */
+ if( tw->tabs.topWidget == NULL && tw->composite.children != NULL )
+ for(i=tw->composite.num_children, childP=tw->composite.children;
+ --i >= 0;
+ ++childP)
+ if( XtIsManaged(*childP) ) {
+ tw->tabs.topWidget = *childP ;
+ break ;
+ }
+
+ if( tw->tabs.topWidget != NULL )
+ {
+ nrows = tw->tabs.numRows ;
+ assert( nrows > 0 ) ;
+
+ if( nrows > 1 )
+ {
+ tab = (TabsConstraints) tw->tabs.topWidget->core.constraints ;
+ assert( tab != NULL ) ;
+
+ /* how far to move top row */
+ move = nrows - tab->tabs.row ;
+ bottom = tw->tabs.tab_total - th ;
+
+ for(i=tw->composite.num_children, childP=tw->composite.children;
+ --i >= 0;
+ ++childP)
+ if( XtIsManaged(*childP) )
+ {
+ tab = (TabsConstraints) (*childP)->core.constraints ;
+ tab->tabs.row = (tab->tabs.row + move) % nrows ;
+ tab->tabs.y = bottom - tab->tabs.row * th ;
+ }
+ }
+ }
+}
+
+
+ /* Find preferred size. Ask children, find size of largest,
+ * add room for tabs & return. This can get a little involved,
+ * as we don't want to have too many rows of tabs; we may widen
+ * the widget to reduce # of rows.
+ *
+ * This function requires that max_cw, max_ch already be set.
+ */
+
+static int
+PreferredSize(
+ TabsWidget tw,
+ Dimension *reply_width, /* total widget size */
+ Dimension *reply_height,
+ Dimension *reply_cw, /* child widget size */
+ Dimension *reply_ch)
+{
+ Dimension cw,ch ; /* child width, height */
+ Dimension wid,hgt ;
+ Dimension rwid,rhgt ;
+ int nrow ;
+
+ wid = cw = tw->tabs.max_cw ;
+ hgt = ch = tw->tabs.max_ch ;
+
+ nrow = PreferredSize2(tw, wid,hgt, &rwid, &rhgt) ;
+
+ /* Check for absurd results (more than 2 rows, high aspect
+ * ratio). Try wider size if needed.
+ * TODO: make sure this terminates.
+ */
+
+ if( nrow > 2 && rhgt > rwid )
+ {
+ Dimension w0, w1 ;
+ int maxloop = 20 ;
+
+ /* step 1: start doubling size until it's too big */
+ do {
+ w0 = wid ;
+ wid = Max(wid*2, wid+20) ;
+ nrow = PreferredSize2(tw, wid,hgt, &rwid,&rhgt) ;
+ } while( nrow > 2 && rhgt > rwid ) ;
+ w1 = wid ;
+
+ /* step 2: use Newton's method to find ideal size. Stop within
+ * 8 pixels.
+ */
+ while( --maxloop > 0 && w1 > w0 + 8 )
+ {
+ wid = (w0+w1)/2 ;
+ nrow = PreferredSize2(tw, wid,hgt, &rwid,&rhgt) ;
+ if( nrow > 2 && rhgt > rwid )
+ w0 = wid ;
+ else
+ w1 = wid ;
+ }
+ wid = w1 ;
+ }
+
+ *reply_width = rwid ;
+ *reply_height = rhgt ;
+ if( reply_cw != NULL ) *reply_cw = cw ;
+ if( reply_ch != NULL ) *reply_ch = ch ;
+ return nrow ;
+}
+
+
+ /* Find preferred size, given size of children. */
+
+static int
+PreferredSize2(
+ TabsWidget tw,
+ int cw, /* child width, height */
+ int ch,
+ Dimension *reply_width, /* total widget size */
+ Dimension *reply_height)
+{
+ Dimension s = SHADWID ;
+
+ /* make room for shadow frame */
+ cw += s*2 ;
+ ch += s*2 ;
+
+ return PreferredSize3(tw, cw, ch, reply_width, reply_height) ;
+}
+
+
+ /* Find preferred size, given size of children+shadow. */
+
+static int
+PreferredSize3(
+ TabsWidget tw,
+ int wid, /* child width, height */
+ int hgt,
+ Dimension *reply_width, /* total widget size */
+ Dimension *reply_height)
+{
+ Dimension th ; /* space used by tabs */
+ int nrows ;
+
+ if( tw->composite.num_children > 0 )
+ nrows = TabLayout(tw, wid, &th, True) ;
+ else {
+ th = 0 ;
+ nrows = 0 ;
+ }
+
+ *reply_width = Max(wid, MIN_WID) ;
+ *reply_height = Max(th+hgt, MIN_HGT) ;
+
+ return nrows ;
+}
+
+
+static void
+MakeSizeRequest(TabsWidget tw)
+{
+ Widget w = (Widget)tw ;
+ XtWidgetGeometry request, reply ;
+ XtGeometryResult result ;
+ Dimension cw,ch ;
+
+ request.request_mode = CWWidth | CWHeight ;
+ PreferredSize(tw, &request.width, &request.height, &cw, &ch) ;
+
+ if( request.width == tw->core.width &&
+ request.height == tw->core.height )
+ return ;
+
+ result = XtMakeGeometryRequest(w, &request, &reply) ;
+
+ if( result == XtGeometryAlmost )
+ {
+ /* Bugger. Didn't get what we want, but were offered a
+ * compromise. If the width was too small, recompute
+ * based on the too-small width and try again.
+ * If the height was too small, make a wild-ass guess
+ * at a wider width and try again.
+ */
+
+ if( reply.width < request.width && reply.height >= request.height )
+ {
+ Dimension s = SHADWID ;
+ ch += s*2 ;
+ PreferredSize3(tw, reply.width,ch, &request.width, &request.height);
+ result = XtMakeGeometryRequest(w, &request, &reply) ;
+ if( result == XtGeometryAlmost )
+ (void) XtMakeGeometryRequest(w, &reply, NULL) ;
+ }
+
+ else
+ (void) XtMakeGeometryRequest(w, &reply, NULL) ;
+ }
+}
+
+
+static void
+getBitmapInfo(TabsWidget tw, TabsConstraints tab)
+{
+ Window root ;
+ int x,y ;
+ unsigned int bw ;
+
+ if( tab->tabs.left_bitmap == None ||
+ !XGetGeometry(XtDisplay(tw), tab->tabs.left_bitmap, &root, &x, &y,
+ &tab->tabs.lbm_width, &tab->tabs.lbm_height,
+ &bw, &tab->tabs.lbm_depth) )
+ tab->tabs.lbm_width = tab->tabs.lbm_height = 0 ;
+}
+
+
+
+
+ /* Code copied & modified from Gcs.c. This version has dynamic
+ * foreground.
+ */
+
+static void
+TabsAllocFgGC(TabsWidget tw)
+{
+ Widget w = (Widget) tw;
+ XGCValues values ;
+
+ values.background = tw->core.background_pixel ;
+ values.font = tw->tabs.font->fid ;
+ values.line_style = LineOnOffDash ;
+ values.line_style = LineSolid ;
+
+ tw->tabs.foregroundGC =
+ XtAllocateGC(w, w->core.depth,
+ GCBackground|GCFont|GCLineStyle, &values,
+ GCForeground,
+ GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode) ;
+}
+
+static void
+TabsAllocGreyGC(TabsWidget tw)
+{
+ Widget w = (Widget) tw;
+ XGCValues values ;
+#ifndef USE_XMU_STIPPLE
+ Screen *screen = XtScreen((Widget)tw);
+ Display *display = XtDisplay((Widget)tw);
+ int pixmap_width = 2, pixmap_height = 2;
+ static unsigned char pixmap_bits[] = {
+ 0x02, 0x01,
+ };
+#endif
+
+ values.background = tw->core.background_pixel ;
+ values.font = tw->tabs.font->fid ;
+
+ if( tw->tabs.be_nice_to_cmap || w->core.depth == 1)
+ {
+ values.fill_style = FillStippled ;
+#ifdef USE_XMU_STIPPLE
+ tw->tabs.grey50 =
+ values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1);
+#else
+ tw->tabs.grey50 =
+ values.stipple = XCreatePixmapFromBitmapData (display,
+ RootWindowOfScreen(screen),
+ (char *)pixmap_bits,
+ pixmap_width, pixmap_height,
+ 1L, 0L, 1);
+#endif
+
+ tw->tabs.greyGC =
+ XtAllocateGC(w, w->core.depth,
+ GCBackground|GCFont|GCStipple|GCFillStyle, &values,
+ GCForeground,
+ GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode) ;
+ }
+ else
+ {
+ tw->tabs.greyGC =
+ XtAllocateGC(w, w->core.depth,
+ GCFont, &values,
+ GCForeground,
+ GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset|
+ GCDashList|GCArcMode) ;
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Tabs.h b/vendor/x11iraf/obm/ObmW/Tabs.h
new file mode 100644
index 00000000..d53b56ff
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Tabs.h
@@ -0,0 +1,186 @@
+/* $Id: Tabs.h,v 1.6 1999/09/22 19:54:14 falk Exp $
+ *
+ * This widget manages one or more child widgets, exactly one of which is
+ * visible. Above the child widgets is a graphic that looks like index
+ * tabs from file folders. Each tab corresponds to one of the child widgets.
+ * By clicking on a tab, the user can bring the corresponding widget to
+ * the top of the stack.
+ */
+
+
+#ifndef _Tabs_h
+#define _Tabs_h
+
+#include <X11/Constraint.h>
+
+
+/***********************************************************************
+ *
+ * Tabs Widget (subclass of CompositeClass)
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ font Font XFontStruct* XtDefaultFont
+ internalWidth Width Dimension 4 *1
+ internalHeight Height Dimension 2 *1
+ topWidget TopWidget Widget *2
+ callback Callback XtCallbackList NULL *3
+ popdownCallback Callback XtCallbackList NULL *4
+ selectInsensitive SelectInsensitive Boolean True *5
+ beNiceToColormap BeNiceToColormap Boolean False *6
+ topShadowContrast TopShadowContrast int 20
+ bottomShadowContrast BottomShadowContrast int 40
+ insensitiveContrast InsensitiveContrast int 33 *7
+
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ hSpace HSpace Dimension 4
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ orientation Orientation XtOrientation vertical
+ vSpace VSpace Dimension 4
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+ Notes:
+
+ 1 internalWidth, internalHeight specify the margins around the text
+ in the tabs.
+ 2 topWidget identifies the widget which is currently visible.
+ 3 callbacks are called whenever the user selects a tab. Call_data is
+ the new top widget.
+ 4 popdownCallbacks are called whenever the user selects a tab. Call_data is
+ the old (no longer visible) top widget. Note that popdownCallbacks
+ are called before callbacks.
+ 5 SelectInsensitive determines whether or not insensitive children may
+ be selected anyway.
+ 6 BeNiceToColormap causes the Tabs widget to use fewer colors.
+ 7 InsensitiveContrast sets the contrast used for labels of insensitive widgets.
+
+*/
+
+/* Constraint parameters:
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ tabLabel Label String widget name
+ tabLeftBitmap LeftBitmap Pixmap None
+ tabForeground Foreground Pixel XtDefaultForeground
+ resizable Resizable Boolean False
+*/
+
+/* New fields */
+
+#ifndef XtNtabLabel
+#define XtNtabLabel "tabLabel"
+#define XtNtabForeground "tabForeground"
+#endif
+
+#ifndef XtNtabLeftBitmap
+#define XtNtabLeftBitmap "tabLeftBitmap"
+#endif
+
+#ifndef XtCLeftBitmap
+#define XtCLeftBitmap "LeftBitmap"
+#endif
+
+#ifndef XtCResizable
+#define XtCResizable "Resizable"
+#endif
+
+#ifndef XtNselectInsensitive
+#define XtNselectInsensitive "selectInsensitive"
+#define XtCSelectInsensitive "SelectInsensitive"
+#endif
+
+#ifndef XtNnlabels
+#define XtNnlabels "nlabels"
+#define XtCNLabels "NLabels"
+#endif
+#ifndef XtNlabels
+#define XtNlabels "labels"
+#define XtCLabels "Labels"
+#endif
+
+#ifndef XtNtopWidget
+#define XtNtopWidget "topWidget"
+#define XtCTopWidget "TopWidget"
+#endif
+
+#ifndef XtNhSpace
+#define XtNhSpace "hSpace"
+#define XtCHSpace "HSpace"
+#define XtNvSpace "vSpace"
+#define XtCVSpace "VSpace"
+#endif
+
+#ifndef XtNresizable
+#define XtNresizable "resizable"
+#endif
+
+#ifndef XtNinsensitiveContrast
+#define XtNinsensitiveContrast "insensitiveContrast"
+#define XtCInsensitiveContrast "InsensitiveContrast"
+#endif
+
+#ifndef XtNshadowWidth
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#endif
+
+#ifndef XtNtopShadowPixmap
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#endif
+
+#ifndef XtNbeNiceToColormap
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNbeNiceToColourmap "beNiceToColormap"
+#define XtCBeNiceToColourmap "BeNiceToColormap"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass tabsWidgetClass;
+
+typedef struct _TabsClassRec *TabsWidgetClass;
+typedef struct _TabsRec *TabsWidget;
+
+_XFUNCPROTOBEGIN
+
+extern void
+XawTabsSetTop(
+#if NeedFunctionPrototypes
+ Widget w,
+ Bool callCallbacks
+#endif
+) ;
+
+extern void
+XawTabsSetHighlight(
+#if NeedFunctionPrototypes
+ Widget tabs,
+ Widget w
+#endif
+) ;
+
+_XFUNCPROTOEND
+
+#endif /* _Tabs_h */
diff --git a/vendor/x11iraf/obm/ObmW/TabsP.h b/vendor/x11iraf/obm/ObmW/TabsP.h
new file mode 100644
index 00000000..2b77264e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TabsP.h
@@ -0,0 +1,127 @@
+/* $Id: TabsP.h,v 1.8 1999/12/16 18:01:25 falk Exp $
+ *
+ * TabsP.h - Private definitions for Index Tabs widget
+ *
+ */
+
+#ifndef _TabsP_h
+#define _TabsP_h
+
+/***********************************************************************
+ *
+ * Tabs Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/IntrinsicP.h>
+
+#ifdef USE_MOTIF
+#include <Xm/XmP.h>
+#include <Xm/ManagerP.h>
+#endif
+
+#include "Tabs.h"
+
+/* New fields for the Tabs widget class record */
+typedef struct {XtPointer extension;} TabsClassPart;
+
+/* Full class record declaration */
+typedef struct _TabsClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+#ifdef USE_MOTIF
+ XmManagerClassPart manager_class;
+#endif
+ TabsClassPart tabs_class;
+} TabsClassRec;
+
+extern TabsClassRec tabsClassRec;
+
+
+
+/****************************************************************
+ *
+ * instance record declaration
+ *
+ ****************************************************************/
+
+/* New fields for the Tabs widget record */
+typedef struct {
+ /* resources */
+ XFontStruct *font ;
+ Dimension internalHeight, internalWidth ;
+ Widget topWidget ;
+ XtCallbackList callbacks ;
+ XtCallbackList popdownCallbacks ;
+ Boolean selectInsensitive ;
+ Boolean be_nice_to_cmap ;
+ int top_shadow_contrast ;
+ int bot_shadow_contrast ;
+ int insensitive_contrast ;
+
+ /* private state */
+ Widget hilight ;
+ GC foregroundGC ;
+ GC backgroundGC ;
+ GC greyGC ;
+ GC topGC ;
+ GC botGC ;
+ Dimension tab_height ; /* height of tabs (all the same) */
+ /* Note: includes top shadow only */
+ Dimension tab_total ; /* total height of all tabs */
+ Dimension child_width, child_height; /* child size, including borders */
+ Dimension max_cw, max_ch ; /* max child preferred size */
+ Cardinal numRows ;
+ XtGeometryMask last_query_mode;
+ Boolean needs_layout ;
+ Pixmap grey50 ; /* TODO: cache this elsewhere */
+} TabsPart;
+
+
+typedef struct _TabsRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+#ifdef USE_MOTIF
+ XmManagerPart manager;
+#endif
+ TabsPart tabs;
+} TabsRec;
+
+
+
+
+/****************************************************************
+ *
+ * constraint record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TabsConstraintsPart {
+ /* resources */
+ String label ;
+ Pixmap left_bitmap ;
+ Pixel foreground ;
+ Boolean resizable ;
+
+ /* private state */
+ Pixel grey ;
+ Boolean greyAlloc ;
+ Dimension width ; /* tab width */
+ Position x,y ; /* tab base position */
+ short row ; /* tab row */
+ Position l_x, l_y ; /* label position */
+ Position lbm_x, lbm_y ; /* bitmap position */
+ unsigned int lbm_width, lbm_height, lbm_depth ;
+} TabsConstraintsPart ;
+
+typedef struct _TabsConstraintsRec {
+#ifdef USE_MOTIF
+ XmManagerConstraintPart manager;
+#endif
+ TabsConstraintsPart tabs ;
+} TabsConstraintsRec, *TabsConstraints ;
+
+
+#endif /* _TabsP_h */
diff --git a/vendor/x11iraf/obm/ObmW/TextWidth.c b/vendor/x11iraf/obm/ObmW/TextWidth.c
new file mode 100644
index 00000000..b213d198
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/TextWidth.c
@@ -0,0 +1,39 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "TabString.h"
+
+/*
+ * Like TextWidth, except it takes an additional "tabs"
+ * argument, used to specify what horizontal pixel position to
+ * move to when tab characters are present in the string. If
+ * the "tabs" argument is NULL, works exactly like its
+ * counterpart.
+ */
+int
+XfwfTextWidth(font, str, length, tabs)
+ XFontStruct *font;
+ String str;
+ int length;
+ int *tabs;
+{
+ register char *p, *ep;
+ register int tx, tab, rc;
+
+ tab = tx = 0;
+ if (length == 0) return 0;
+ for (p = str; length; )
+ {
+ ep = strnchr(p, '\t', length);
+ if (ep && tabs)
+ {
+ tx = tabs[tab++];
+ length -= ep - p + 1;
+ p = ep + 1;
+ }
+ else
+ {
+ rc = XTextWidth(font, p, length);
+ if (rc < 0) return rc; else return rc + tx;
+ }
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Toggle.c b/vendor/x11iraf/obm/ObmW/Toggle.c
new file mode 100644
index 00000000..6f55305a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Toggle.c
@@ -0,0 +1,290 @@
+/* Generated by wbuild from "Toggle.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Converters.h"
+#include "ToggleP.h"
+static void toggle(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void switch_on(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+static void switch_off(
+#if NeedFunctionPrototypes
+Widget,XEvent*,String*,Cardinal*
+#endif
+);
+
+static XtActionsRec actionsList[] = {
+{"toggle", toggle},
+{"switch_on", switch_on},
+{"switch_off", switch_off},
+};
+
+static char defaultTranslations[] = "\
+<Btn1Down>: set_shadow(sunken) \n\
+<Btn1Up>: toggle() set_shadow() \n\
+<Key>Return: toggle() \n\
+";
+static void _resolve_inheritance(
+#if NeedFunctionPrototypes
+WidgetClass
+#endif
+);
+static void initialize(
+#if NeedFunctionPrototypes
+Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static Boolean set_values(
+#if NeedFunctionPrototypes
+Widget ,Widget ,Widget,ArgList ,Cardinal *
+#endif
+);
+static void expose(
+#if NeedFunctionPrototypes
+Widget,XEvent *,Region
+#endif
+);
+static void create_on_gc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+static void create_off_gc(
+#if NeedFunctionPrototypes
+Widget
+#endif
+);
+/*ARGSUSED*/static void create_on_gc(self)Widget self;
+{
+ XtGCMask mask = GCFillStyle;
+ XGCValues values;
+
+ if (((XfwfToggleWidget)self)->xfwfToggle.on_gc != NULL) XtReleaseGC(self, ((XfwfToggleWidget)self)->xfwfToggle.on_gc);
+ if (((XfwfToggleWidget)self)->xfwfToggle.onIcon && ((XfwfToggleWidget)self)->xfwfToggle.onIcon->pixmap != None) {
+ values.tile = ((XfwfToggleWidget)self)->xfwfToggle.onIcon->pixmap;
+ mask |= GCTile;
+ }
+ if (((XfwfToggleWidget)self)->xfwfToggle.onIcon && ((XfwfToggleWidget)self)->xfwfToggle.onIcon->mask != None) {
+ values.clip_mask = ((XfwfToggleWidget)self)->xfwfToggle.onIcon->mask;
+ mask |= GCClipMask;
+ }
+ values.fill_style = FillTiled;
+ ((XfwfToggleWidget)self)->xfwfToggle.on_gc = XtGetGC(self, mask, &values);
+}
+/*ARGSUSED*/static void create_off_gc(self)Widget self;
+{
+ XtGCMask mask = GCFillStyle;
+ XGCValues values;
+
+ if (((XfwfToggleWidget)self)->xfwfToggle.off_gc != NULL) XtReleaseGC(self, ((XfwfToggleWidget)self)->xfwfToggle.off_gc);
+ if (((XfwfToggleWidget)self)->xfwfToggle.offIcon && ((XfwfToggleWidget)self)->xfwfToggle.offIcon->pixmap != None) {
+ values.tile = ((XfwfToggleWidget)self)->xfwfToggle.offIcon->pixmap;
+ mask |= GCTile;
+ }
+ if (((XfwfToggleWidget)self)->xfwfToggle.offIcon && ((XfwfToggleWidget)self)->xfwfToggle.offIcon->mask != None) {
+ values.clip_mask = ((XfwfToggleWidget)self)->xfwfToggle.offIcon->mask;
+ mask |= GCClipMask;
+ }
+ values.fill_style = FillTiled;
+ ((XfwfToggleWidget)self)->xfwfToggle.off_gc = XtGetGC(self, mask, &values);
+}
+
+static XtResource resources[] = {
+{XtNonCallback,XtCOnCallback,XtRCallback,sizeof(((XfwfToggleRec*)NULL)->xfwfToggle.onCallback),XtOffsetOf(XfwfToggleRec,xfwfToggle.onCallback),XtRImmediate,(XtPointer)NULL },
+{XtNoffCallback,XtCOffCallback,XtRCallback,sizeof(((XfwfToggleRec*)NULL)->xfwfToggle.offCallback),XtOffsetOf(XfwfToggleRec,xfwfToggle.offCallback),XtRImmediate,(XtPointer)NULL },
+{XtNon,XtCOn,XtRBoolean,sizeof(((XfwfToggleRec*)NULL)->xfwfToggle.on),XtOffsetOf(XfwfToggleRec,xfwfToggle.on),XtRImmediate,(XtPointer)False },
+{XtNonIcon,XtCOnIcon,XtRIcon,sizeof(((XfwfToggleRec*)NULL)->xfwfToggle.onIcon),XtOffsetOf(XfwfToggleRec,xfwfToggle.onIcon),XtRString,(XtPointer)"filledsquare"},
+{XtNoffIcon,XtCOffIcon,XtRIcon,sizeof(((XfwfToggleRec*)NULL)->xfwfToggle.offIcon),XtOffsetOf(XfwfToggleRec,xfwfToggle.offIcon),XtRString,(XtPointer)"emptysquare"},
+};
+
+XfwfToggleClassRec xfwfToggleClassRec = {
+{ /* core_class part */
+(WidgetClass) &xfwfButtonClassRec,
+"TextToggle",
+sizeof(XfwfToggleRec),
+NULL,
+_resolve_inheritance,
+FALSE,
+initialize,
+NULL,
+XtInheritRealize,
+actionsList,
+3,
+resources,
+5,
+NULLQUARK,
+False ,
+FALSE ,
+False ,
+False ,
+NULL,
+XtInheritResize,
+expose,
+set_values,
+NULL,
+XtInheritSetValuesAlmost,
+NULL,
+XtInheritAcceptFocus,
+XtVersion,
+NULL,
+defaultTranslations,
+XtInheritQueryGeometry,
+XtInheritDisplayAccelerator,
+NULL
+},
+{ /* composite_class part */
+XtInheritGeometryManager,
+XtInheritChangeManaged,
+XtInheritInsertChild,
+XtInheritDeleteChild,
+NULL
+},
+{ /* XfwfCommon_class part */
+XtInherit_compute_inside,
+XtInherit_highlight_border,
+XtInherit_unhighlight_border,
+XtInherit_would_accept_focus,
+XtInherit_traverse,
+XtInherit_choose_color,
+XtInherit_lighter_color,
+XtInherit_darker_color,
+NULL ,
+},
+{ /* XfwfFrame_class part */
+0
+},
+{ /* XfwfBoard_class part */
+XtInherit_set_abs_location,
+},
+{ /* XfwfLabel_class part */
+XtInherit_set_label,
+},
+{ /* XfwfButton_class part */
+0
+},
+{ /* XfwfToggle_class part */
+0
+},
+};
+WidgetClass xfwfToggleWidgetClass = (WidgetClass) &xfwfToggleClassRec;
+/*ARGSUSED*/
+static void toggle(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ XtVaSetValues(self, "on", !((XfwfToggleWidget)self)->xfwfToggle.on, NULL);
+ XtCallCallbackList(self, ((XfwfToggleWidget)self)->xfwfToggle.on ? ((XfwfToggleWidget)self)->xfwfToggle.onCallback : ((XfwfToggleWidget)self)->xfwfToggle.offCallback, event);
+}
+
+/*ARGSUSED*/
+static void switch_on(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (! ((XfwfToggleWidget)self)->xfwfToggle.on) {
+ XtVaSetValues(self, "on", True, NULL);
+ XtCallCallbackList(self, ((XfwfToggleWidget)self)->xfwfToggle.onCallback, event);
+ }
+}
+
+/*ARGSUSED*/
+static void switch_off(self,event,params,num_params)Widget self;XEvent*event;String*params;Cardinal*num_params;
+{
+ if (((XfwfToggleWidget)self)->xfwfToggle.on) {
+ XtVaSetValues(self, "on", False, NULL);
+ XtCallCallbackList(self, ((XfwfToggleWidget)self)->xfwfToggle.offCallback, event);
+ }
+}
+
+static void _resolve_inheritance(class)
+WidgetClass class;
+{
+ XfwfToggleWidgetClass c = (XfwfToggleWidgetClass) class;
+ XfwfToggleWidgetClass super;
+ static CompositeClassExtensionRec extension_rec = {
+ NULL, NULLQUARK, XtCompositeExtensionVersion,
+ sizeof(CompositeClassExtensionRec), True};
+ CompositeClassExtensionRec *ext;
+ ext = (XtPointer)XtMalloc(sizeof(*ext));
+ *ext = extension_rec;
+ ext->next_extension = c->composite_class.extension;
+ c->composite_class.extension = ext;
+ if (class == xfwfToggleWidgetClass) return;
+ super = (XfwfToggleWidgetClass)class->core_class.superclass;
+}
+/*ARGSUSED*/static void initialize(request,self,args,num_args)Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ int status;
+ Dimension w1, w2, w;
+
+ ((XfwfToggleWidget)self)->xfwfToggle.on_gc = NULL;
+ ((XfwfToggleWidget)self)->xfwfToggle.off_gc = NULL;
+ create_on_gc(self);
+ create_off_gc(self);
+
+ w1 = ((XfwfToggleWidget)self)->xfwfToggle.onIcon ? ((XfwfToggleWidget)self)->xfwfToggle.onIcon->attributes.width : 0;
+ w2 = ((XfwfToggleWidget)self)->xfwfToggle.offIcon ? ((XfwfToggleWidget)self)->xfwfToggle.offIcon->attributes.width : 0;
+ w = max(w1, w2);
+ if (w != 0) XtVaSetValues(self, XtNleftMargin, ((XfwfToggleWidget)self)->xfwfLabel.leftMargin + w, NULL);
+}
+/*ARGSUSED*/static Boolean set_values(old,request,self,args,num_args)Widget old;Widget request;Widget self;ArgList args;Cardinal * num_args;
+{
+ Boolean redraw = False, compute_margin = False;
+ Dimension w1, w2, w;
+
+ if (((XfwfToggleWidget)self)->xfwfToggle.onIcon != ((XfwfToggleWidget)old)->xfwfToggle.onIcon) {
+ create_on_gc(self);
+ compute_margin = True;
+ }
+ if (((XfwfToggleWidget)self)->xfwfToggle.offIcon != ((XfwfToggleWidget)old)->xfwfToggle.offIcon) {
+ create_off_gc(self);
+ compute_margin = True;
+ }
+ if (((XfwfToggleWidget)self)->xfwfToggle.on != ((XfwfToggleWidget)old)->xfwfToggle.on) {
+ redraw = True;
+ }
+ if (compute_margin) {
+ /* Compute w = old margin between icons and text */
+ w1 = ((XfwfToggleWidget)old)->xfwfToggle.onIcon ? ((XfwfToggleWidget)old)->xfwfToggle.onIcon->attributes.width : 0;
+ w2 = ((XfwfToggleWidget)old)->xfwfToggle.offIcon ? ((XfwfToggleWidget)old)->xfwfToggle.offIcon->attributes.width : 0;
+ w = ((XfwfToggleWidget)old)->xfwfLabel.leftMargin - max(w1, w2);
+ /* Compute new left margin w = w + width of icons */
+ w1 = ((XfwfToggleWidget)self)->xfwfToggle.onIcon ? ((XfwfToggleWidget)self)->xfwfToggle.onIcon->attributes.width : 0;
+ w2 = ((XfwfToggleWidget)self)->xfwfToggle.offIcon ? ((XfwfToggleWidget)self)->xfwfToggle.offIcon->attributes.width : 0;
+ w = w + max(w1, w2);
+ if (((XfwfToggleWidget)old)->xfwfLabel.leftMargin != w) {
+ XtVaSetValues(self, XtNleftMargin, w, NULL);
+ redraw = False;
+ } else
+ redraw = True;
+ }
+ return redraw;
+}
+/*ARGSUSED*/static void expose(self,event,region)Widget self;XEvent * event;Region region;
+{
+ Position x, y;
+ Dimension w, h;
+
+ if (! XtIsRealized(self)) return;
+ xfwfButtonClassRec.core_class.expose(self, event, region);
+ ((XfwfToggleWidgetClass)self->core.widget_class)->xfwfCommon_class.compute_inside(self, &x, &y, &w, &h);
+ if (((XfwfToggleWidget)self)->xfwfToggle.on && ((XfwfToggleWidget)self)->xfwfToggle.onIcon) {
+ y = y + (h - ((XfwfToggleWidget)self)->xfwfToggle.onIcon->attributes.height)/2;
+ XSetTSOrigin(XtDisplay(self), ((XfwfToggleWidget)self)->xfwfToggle.on_gc, x, y);
+ XSetClipOrigin(XtDisplay(self), ((XfwfToggleWidget)self)->xfwfToggle.on_gc, x, y);
+ XFillRectangle(XtDisplay(self), XtWindow(self), ((XfwfToggleWidget)self)->xfwfToggle.on_gc, x, y,
+ ((XfwfToggleWidget)self)->xfwfToggle.onIcon->attributes.width,
+ ((XfwfToggleWidget)self)->xfwfToggle.onIcon->attributes.height);
+ } else if (((XfwfToggleWidget)self)->xfwfToggle.offIcon) {
+ y = y + (h - ((XfwfToggleWidget)self)->xfwfToggle.offIcon->attributes.height)/2;
+ XSetTSOrigin(XtDisplay(self), ((XfwfToggleWidget)self)->xfwfToggle.off_gc, x, y);
+ XSetClipOrigin(XtDisplay(self), ((XfwfToggleWidget)self)->xfwfToggle.off_gc, x, y);
+ XFillRectangle(XtDisplay(self), XtWindow(self), ((XfwfToggleWidget)self)->xfwfToggle.off_gc, x, y,
+ ((XfwfToggleWidget)self)->xfwfToggle.offIcon->attributes.width,
+ ((XfwfToggleWidget)self)->xfwfToggle.offIcon->attributes.height);
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/Toggle.h b/vendor/x11iraf/obm/ObmW/Toggle.h
new file mode 100644
index 00000000..fc98c56e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Toggle.h
@@ -0,0 +1,60 @@
+/* Generated by wbuild from "Toggle.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfToggle_H_
+#define _XfwfToggle_H_
+#include "Button.h"
+#ifndef XtNonCallback
+#define XtNonCallback "onCallback"
+#endif
+#ifndef XtCOnCallback
+#define XtCOnCallback "OnCallback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+#ifndef XtNoffCallback
+#define XtNoffCallback "offCallback"
+#endif
+#ifndef XtCOffCallback
+#define XtCOffCallback "OffCallback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+
+#ifndef XtNon
+#define XtNon "on"
+#endif
+#ifndef XtCOn
+#define XtCOn "On"
+#endif
+#ifndef XtRBoolean
+#define XtRBoolean "Boolean"
+#endif
+
+#ifndef XtNonIcon
+#define XtNonIcon "onIcon"
+#endif
+#ifndef XtCOnIcon
+#define XtCOnIcon "OnIcon"
+#endif
+#ifndef XtRIcon
+#define XtRIcon "Icon"
+#endif
+
+#ifndef XtNoffIcon
+#define XtNoffIcon "offIcon"
+#endif
+#ifndef XtCOffIcon
+#define XtCOffIcon "OffIcon"
+#endif
+#ifndef XtRIcon
+#define XtRIcon "Icon"
+#endif
+
+typedef struct _XfwfToggleClassRec *XfwfToggleWidgetClass;
+typedef struct _XfwfToggleRec *XfwfToggleWidget;
+externalref WidgetClass xfwfToggleWidgetClass;
+#endif /*_XfwfToggle_H_*/
diff --git a/vendor/x11iraf/obm/ObmW/Toggle.man b/vendor/x11iraf/obm/ObmW/Toggle.man
new file mode 100644
index 00000000..fa01d492
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Toggle.man
@@ -0,0 +1,538 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfToggle
+.SH DESCRIPTION
+The \fIXfwfToggle\fP is a button that switches states with every activation
+(which is by default with every mouse click). The states are named `on' and
+`off'. The states can be indicated with a $\surd$ before the label Two
+callbacks report the changed state to the application: \fIonCallback\fP is called
+when the button switches to `on', \fIoffCallback\fP is called when the button
+switches back to `off'.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfToggle
+Name Class Type Default
+XtNonCallback XtCOnCallback Callback NULL
+XtNoffCallback XtCOffCallback Callback NULL
+XtNon XtCOn Boolean False
+XtNonIcon XtCOnIcon Icon * "filledsquare"
+XtNoffIcon XtCOffIcon Icon * "emptysquare"
+
+.TE
+.ps
+
+.TP
+.I "XtNonCallback"
+The \fIonCallback\fP is called by the \fItoggle\fP action or by the \fIswitch_on\fP
+action, if the previous state was `off'. The \fIcall_data\fP argument will contain
+the \fIXEvent\fP pointer that trigerred the action function.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList onCallback = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNoffCallback"
+The \fIoffCallback\fP is called from the \fItoggle\fP or \fIswitch_off\fP action, if the
+previous state was `on'. The \fIcall_data\fP argument will be a pointer to the
+\fIXEvent\fP that caused the action.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList offCallback = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNon"
+The variable \fIon\fP records the state of the widget: \fITrue\fP means `on' and
+\fIFalse\fP means `off'.
+
+
+
+.hi
+
+.nf
+Boolean on = False
+.fi
+
+.eh
+
+.TP
+.I "XtNonIcon"
+By default, the button displays a $\surd$ when on and nothing when
+off. The two resources \fIonIcon\fP and \fIoffPIcon\fP can replace these
+two graphics with arbitrary pixmaps. Suggested size for these pixmaps
+is about $16\times18$.
+
+
+
+.hi
+
+.nf
+Icon * onIcon = <String>"filledsquare"
+.fi
+
+.eh
+
+.TP
+.I "XtNoffIcon"
+The \fIoffIcon\fP is displayed when the button is in `off' state. By
+default, nothing is displayed in this state.
+
+
+
+.hi
+
+.nf
+Icon * offIcon = <String>"emptysquare"
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfButton
+Name Class Type Default
+XtNactivate XtCActivate Callback NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfLabel
+Name Class Type Default
+XtNlabel XtCLabel String NULL
+XtNtablist XtCTablist String NULL
+XtNfont XtCFont FontStruct XtDefaultFont
+XtNforeground XtCForeground Pixel XtDefaultForeground
+XtNalignment XtCAlignment Alignment 0
+XtNtopMargin XtCTopMargin Dimension 2
+XtNbottomMargin XtCBottomMargin Dimension 2
+XtNleftMargin XtCLeftMargin Dimension 2
+XtNrightMargin XtCRightMargin Dimension 2
+XtNshrinkToFit XtCShrinkToFit Boolean False
+XtNrvStart XtCRvStart Int 0
+XtNrvLength XtCRvLength Int 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfBoard
+Name Class Type Default
+XtNabs_x XtCAbs_x Position 0
+XtNrel_x XtCRel_x Float "0.0"
+XtNabs_y XtCAbs_y Position 0
+XtNrel_y XtCRel_y Float "0.0"
+XtNabs_width XtCAbs_width Position 0
+XtNrel_width XtCRel_width Float "1.0"
+XtNabs_height XtCAbs_height Position 0
+XtNrel_height XtCRel_height Float "1.0"
+XtNhunit XtCHunit Float "1.0"
+XtNvunit XtCVunit Float "1.0"
+XtNlocation XtCLocation String NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfFrame
+Name Class Type Default
+XtNcursor XtCCursor Cursor None
+XtNframeType XtCFrameType FrameType XfwfRaised
+XtNframeWidth XtCFrameWidth Dimension 0
+XtNouterOffset XtCOuterOffset Dimension 0
+XtNinnerOffset XtCInnerOffset Dimension 0
+XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto
+XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor
+XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor
+XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL
+XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Translations"
+
+The \fItoggle\fP action toggles the widget between `on' and `off'. By
+default it is bound to a click of the left mouse button as well as to
+the Return key.
+
+
+
+.nf
+<Btn1Down>: set_shadow(sunken)
+.fi
+
+.nf
+<Btn1Up>: toggle() set_shadow()
+.fi
+
+.nf
+<Key>Return: toggle()
+.fi
+
+.hi
+.SS "Actions"
+
+.TP
+.I "toggle
+
+The \fItoggle\fP action switches the state. Depending on the resources
+it might change the tickmark. The \fIonCallback\fP or \fIoffCallback\fP
+functions are called, with the event as \fIcall_data\fP argument.
+
+.hi
+
+.nf
+void toggle($, XEvent* event, String* params, Cardinal* num_params)
+{
+ XtVaSetValues($, "on", !$on, NULL);
+ XtCallCallbackList($, $on ? $onCallback : $offCallback, event);
+}
+.fi
+
+.eh
+
+.TP
+.I "switch_on
+
+The \fIswitch_on\fP action switches the button to `on' if it is `off',
+otherwise it does nothing. By default it isn't bound to any event. If
+the widget is changed, the \fIonCallback\fP is called with the event as
+\fIcall_data\fP.
+
+.hi
+
+.nf
+void switch_on($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if (! $on) {
+ XtVaSetValues($, "on", True, NULL);
+ XtCallCallbackList($, $onCallback, event);
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "switch_off
+
+The \fIswitch_off\fP action switches the widget to `off' if the state is
+`on', otherwise it does nothing. When the widget changes states, the
+\fIoffCallback\fP is called, with a pointer to the \fIXEvent\fP structure as
+\fIcall_data\fP argument.
+
+.hi
+
+.nf
+void switch_off($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if ($on) {
+ XtVaSetValues($, "on", False, NULL);
+ XtCallCallbackList($, $offCallback, event);
+ }
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+The Converters file is needed for the \fIIcon\fP type.
+
+.nf
+
+.B incl
+ <Xfwf/Converters.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+The \fIon_gc\fP GC holds the picture of the tick mark for the `on'
+state.
+
+
+
+.nf
+GC on_gc
+.fi
+
+The \fIoff_gc\fP holds the picture for the `off' state.
+
+
+
+.nf
+GC off_gc
+.fi
+
+The previous value of \fIleftMargin\fP is stored in a private variable.
+This value is added to the width of the widest pixmap to give the new
+value of \fIleftMargin\fP.
+
+
+
+.nf
+Dimension saveLeftMargin
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The GC's are created for the first time and the left margin is
+increased to make room for the on and off icons.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ int status;
+ Dimension w1, w2, w;
+
+ $on_gc = NULL;
+ $off_gc = NULL;
+ create_on_gc($);
+ create_off_gc($);
+
+ w1 = $onIcon ? $onIcon->attributes.width : 0;
+ w2 = $offIcon ? $offIcon->attributes.width : 0;
+ w = max(w1, w2);
+ if (w != 0) XtVaSetValues($, XtNleftMargin, $leftMargin + w, NULL);
+}
+.fi
+
+Question: Does the computation of \fIleftMargin\fP have the desired
+effect? Since \fIset_values\fP is downward chained, the Label widget has
+already processed it; changing \fIleftMargin\fP doesn't cause Label to
+recompute the preferred size\dots
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean redraw = False, compute_margin = False;
+ Dimension w1, w2, w;
+
+ if ($onIcon != $old$onIcon) {
+ create_on_gc($);
+ compute_margin = True;
+ }
+ if ($offIcon != $old$offIcon) {
+ create_off_gc($);
+ compute_margin = True;
+ }
+ if ($on != $old$on) {
+ redraw = True;
+ }
+ if (compute_margin) {
+ /* Compute w = old margin between icons and text */
+ w1 = $old$onIcon ? $old$onIcon->attributes.width : 0;
+ w2 = $old$offIcon ? $old$offIcon->attributes.width : 0;
+ w = $old$leftMargin - max(w1, w2);
+ /* Compute new left margin w = w + width of icons */
+ w1 = $onIcon ? $onIcon->attributes.width : 0;
+ w2 = $offIcon ? $offIcon->attributes.width : 0;
+ w = w + max(w1, w2);
+ if ($old$leftMargin != w) {
+ XtVaSetValues($, XtNleftMargin, w, NULL);
+ redraw = False;
+ } else
+ redraw = True;
+ }
+ return redraw;
+}
+.fi
+
+The \fIexpose\fP method uses the \fIexpose\fP method of the superclass to draw the
+button and then possibly adds a tick mark.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ Position x, y;
+ Dimension w, h;
+
+ if (! XtIsRealized($)) return;
+ #expose($, event, region);
+ $compute_inside($, x, y, w, h);
+ if ($on $onIcon) {
+ y = y + (h - $onIcon->attributes.height)/2;
+ XSetTSOrigin(XtDisplay($), $on_gc, x, y);
+ XSetClipOrigin(XtDisplay($), $on_gc, x, y);
+ XFillRectangle(XtDisplay($), XtWindow($), $on_gc, x, y,
+ $onIcon->attributes.width,
+ $onIcon->attributes.height);
+ } else if ($offIcon) {
+ y = y + (h - $offIcon->attributes.height)/2;
+ XSetTSOrigin(XtDisplay($), $off_gc, x, y);
+ XSetClipOrigin(XtDisplay($), $off_gc, x, y);
+ XFillRectangle(XtDisplay($), XtWindow($), $off_gc, x, y,
+ $offIcon->attributes.width,
+ $offIcon->attributes.height);
+ }
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The \fIcreate_on_gc\fP function creates a GC with the \fIonIcon\fP as tile.
+
+.nf
+create_on_gc($)
+{
+ XtGCMask mask = GCFillStyle;
+ XGCValues values;
+
+ if ($on_gc != NULL) XtReleaseGC($, $on_gc);
+ if ($onIcon $onIcon->pixmap != None) {
+ values.tile = $onIcon->pixmap;
+ mask |= GCTile;
+ }
+ if ($onIcon $onIcon->mask != None) {
+ values.clip_mask = $onIcon->mask;
+ mask |= GCClipMask;
+ }
+ values.fill_style = FillTiled;
+ $on_gc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fIcreate_off_gc\fP function creates a GC with the \fIoffIcon\fP as tile.
+
+.nf
+create_off_gc($)
+{
+ XtGCMask mask = GCFillStyle;
+ XGCValues values;
+
+ if ($off_gc != NULL) XtReleaseGC($, $off_gc);
+ if ($offIcon $offIcon->pixmap != None) {
+ values.tile = $offIcon->pixmap;
+ mask |= GCTile;
+ }
+ if ($offIcon $offIcon->mask != None) {
+ values.clip_mask = $offIcon->mask;
+ mask |= GCClipMask;
+ }
+ values.fill_style = FillTiled;
+ $off_gc = XtGetGC($, mask, values);
+}
+.fi
+
+.hi
diff --git a/vendor/x11iraf/obm/ObmW/ToggleP.h b/vendor/x11iraf/obm/ObmW/ToggleP.h
new file mode 100644
index 00000000..20eb26b4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/ToggleP.h
@@ -0,0 +1,50 @@
+/* Generated by wbuild from "Toggle.w"
+** (generator version $Revision: 2.0 $ of $Date: 93/07/06 16:08:04 $)
+*/
+#ifndef _XfwfToggleP_H_
+#define _XfwfToggleP_H_
+#include "ButtonP.h"
+#include "Toggle.h"
+typedef struct {
+/* methods */
+/* class variables */
+int dummy;
+} XfwfToggleClassPart;
+typedef struct _XfwfToggleClassRec {
+CoreClassPart core_class;
+CompositeClassPart composite_class;
+XfwfCommonClassPart xfwfCommon_class;
+XfwfFrameClassPart xfwfFrame_class;
+XfwfBoardClassPart xfwfBoard_class;
+XfwfLabelClassPart xfwfLabel_class;
+XfwfButtonClassPart xfwfButton_class;
+XfwfToggleClassPart xfwfToggle_class;
+} XfwfToggleClassRec;
+
+typedef struct {
+/* resources */
+XtCallbackList onCallback;
+XtCallbackList offCallback;
+Boolean on;
+Icon * onIcon;
+Icon * offIcon;
+/* private state */
+GC on_gc;
+GC off_gc;
+Dimension saveLeftMargin;
+} XfwfTogglePart;
+
+typedef struct _XfwfToggleRec {
+CorePart core;
+CompositePart composite;
+XfwfCommonPart xfwfCommon;
+XfwfFramePart xfwfFrame;
+XfwfBoardPart xfwfBoard;
+XfwfLabelPart xfwfLabel;
+XfwfButtonPart xfwfButton;
+XfwfTogglePart xfwfToggle;
+} XfwfToggleRec;
+
+externalref XfwfToggleClassRec xfwfToggleClassRec;
+
+#endif /* _XfwfToggleP_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/3d.h b/vendor/x11iraf/obm/ObmW/Xraw/3d.h
new file mode 100644
index 00000000..8d09dddf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/3d.h
@@ -0,0 +1,145 @@
+#ifndef _3d_h_
+#define _3d_h_
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xraw/XawInit.h>
+
+typedef enum {
+ XawRAISED = Xraw_3d,
+ XawSUNKEN,
+ XawCHISELED,
+ XawLEDGED,
+ XawTACK
+} XawFrameType;
+
+#define TOP (1)
+#define BOTTOM (2)
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean ArmedColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+
+
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+
+extern Pixmap CreateShadowPixmap Xraw_PROTO((Widget ,
+ Pixel ,
+ int ));
+
+
+extern Boolean AllocShadowPixel Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Pixel * ));
+
+
+extern GC MakeGC Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Boolean ,
+ int ));
+
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern void XawDrawFrame Xraw_PROTO((Widget ,
+ Position ,
+ Position ,
+ Dimension ,
+ Dimension ,
+ XawFrameType ,
+ Dimension ,
+ GC ,
+ GC ));
+
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean ArmedColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern void DrawRhombus Xraw_PROTO((Widget ,
+ short ,
+ short ,
+ short ,
+ short ,
+ GC ,
+ GC ,
+ GC ,
+ Boolean ));
+
+extern Boolean FetchPixel Xraw_PROTO((Widget ,
+ String name ,
+ Pixel* ));
+
+#endif /* _3d_h_ */
+
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h b/vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h
new file mode 100644
index 00000000..cded7fcb
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h
@@ -0,0 +1,33 @@
+/*
+ * $XConsortium: AllWidgets.h,v 1.2 90/02/26 12:00:56 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _XawAllWidgets_h
+#define _XawAllWidgets_h
+
+/*
+ * This file matches the generated AllWidgets.c
+ */
+extern XmuWidgetNode XawWidgetArray[];
+extern int XawWidgetCount;
+
+#endif /* _XawAllWidgets_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Arrow.h b/vendor/x11iraf/obm/ObmW/Xraw/Arrow.h
new file mode 100644
index 00000000..bcc7c113
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Arrow.h
@@ -0,0 +1,144 @@
+#ifndef _XawArrow_h
+#define _XawArrow_h
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback XtCallbackList NULL
+ direction Direction XawDirection XawTop
+ foreground Foreground Pixel XtDefaultBackground
+ height Height Dimension text height
+ insensitiveBorder Insensitive Pixmap Gray
+ mappedWhenManaged MappedWhenManaged Boolean True
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ sensitive Sensitive Boolean True
+ shadowWidht ShadowWidht Dimension 2
+ width Width Dimension 8
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+typedef enum {
+ XawLeft,
+ XawRight,
+ XawTop,
+ XawBottom
+}XawDirection;
+
+
+/* new instance and class names */
+#ifndef XtNdirection
+#define XtNdirection "direction"
+#endif
+
+#ifndef XtCDirection
+#define XtCDirection "Direction"
+#endif
+
+#ifndef XtRDirection
+#define XtRDirection "Direction"
+#endif
+
+#ifndef XtNforeground
+#define XtNforeground "foreground"
+#endif
+#ifndef XtCForeground
+#define XtCForeground "Foreground"
+#endif
+
+#ifndef XtRPixel
+#define XtRPixel "Pixel"
+#endif
+
+#ifndef XtNarrowShadow
+#define XtNarrowShadow "arrowShadow"
+#endif
+#ifndef XtCArrowShadow
+#define XtCArrowShadow "ArrowShadow"
+#endif
+#ifndef XtRDimension
+#define XtRDimension "Dimension"
+#endif
+
+#ifndef XtNinitialDelay
+#define XtNinitialDelay "initialDelay"
+#endif
+#ifndef XtCInitialDelay
+#define XtCInitialDelay "InitialDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNrepeatDelay
+#define XtNrepeatDelay "repeatDelay"
+#endif
+#ifndef XtCRepeatDelay
+#define XtCRepeatDelay "RepeatDelay"
+#endif
+#ifndef XtRCardinal
+#define XtRCardinal "Cardinal"
+#endif
+
+#ifndef XtNcallback
+#define XtNcallback "callback"
+#endif
+#ifndef XtCCallback
+#define XtCCallback "Callback"
+#endif
+#ifndef XtRCallback
+#define XtRCallback "Callback"
+#endif
+ /* external declarations */
+
+typedef struct {
+ XawDirection direction;
+ XPoint p1[3];
+ XPoint p2[4];
+ XPoint p3[4];
+ XPoint p4[4];
+ int a;
+ int a2;
+ int a3;
+}XawDrawArrowStruct;
+
+extern void XawMakeDrawArrowStruct(
+#if NeedFunctionPrototypes
+ int /* x */,
+ int /* y */,
+ unsigned int /* w */,
+ unsigned int /* h */,
+ unsigned int /* thickness */,
+ XawDirection /* direction */,
+ XawDrawArrowStruct * /* result */
+#endif
+);
+
+extern void XawDrawArrow(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ GC /* inner */,
+ GC /* top */,
+ GC /* bottom */,
+ XawDrawArrowStruct * /* draw struct */
+#endif
+);
+
+extern WidgetClass arrowWidgetClass;
+
+typedef struct _ArrowClassRec *ArrowWidgetClass;
+typedef struct _ArrowRec *ArrowWidget;
+
+
+#endif /* _XawArrow_h */
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h b/vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h
new file mode 100644
index 00000000..818e70bf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h
@@ -0,0 +1,45 @@
+#ifndef _XawArrowP_h
+#define _XawArrowP_h
+
+#include <X11/Xraw/RepeaterP.h>
+#include <X11/Xraw/Arrow.h>
+
+#define ARROW(w) ((ArrowWidget) w)->arrow
+
+typedef struct {/* new fields in widget class */
+ int dummy;
+} ArrowClassPart;
+
+typedef struct _ArrowClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ RepeaterClassPart repeater_class;
+ ArrowClassPart arrow_class;
+} ArrowClassRec;
+
+typedef struct {
+ /* resources */
+ Dimension arrowShadow;
+ XawDrawArrowStruct outline;
+ /* private state */
+ GC arrowgc;
+ Boolean set_a2_a3;
+} ArrowPart;
+
+typedef struct _ArrowRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+ CommandPart command;
+ RepeaterPart repeater;
+ ArrowPart arrow;
+} ArrowRec;
+
+/*
+ * external declarations
+ */
+extern ArrowClassRec arrowClassRec;
+
+#endif /* _XawArrowP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h
new file mode 100644
index 00000000..1319da43
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h
@@ -0,0 +1,87 @@
+/*
+ * $XConsortium: AsciiSink.h,v 1.4 90/01/10 16:48:48 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawAsciiSink_h
+#define _XawAsciiSink_h
+
+/***********************************************************************
+ *
+ * AsciiSink Object
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/TextSink.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ echo Output Boolean True
+ displayNonprinting Output Boolean True
+
+*/
+
+#define XtCOutput "Output"
+
+#define XtNdisplayNonprinting "displayNonprinting"
+#define XtNecho "echo"
+
+/* Class record constants */
+
+extern WidgetClass asciiSinkObjectClass;
+
+typedef struct _AsciiSinkClassRec *AsciiSinkObjectClass;
+typedef struct _AsciiSinkRec *AsciiSinkObject;
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+#ifdef XAW_BC
+/************************************************************
+ * For Compatability Only. */
+
+#define XtAsciiSinkCreate XawAsciiSinkCreate
+#define XtAsciiSinkDestroy XawAsciiSinkDestroy
+
+#define XawTextSink Widget
+#define XtTextSink XawTextSink
+
+extern XawTextSink XawAsciiSinkCreate(); /* parent, args, num_args */
+ /* Widget parent; */
+ /* ArgList args; */
+ /* Cardinal num_args; */
+
+#define XawAsciiSinkDestroy XtDestroyWidget
+
+#endif /* XAW_BC */
+
+#endif /* _XawAsciiSrc_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h
new file mode 100644
index 00000000..11b91adf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h
@@ -0,0 +1,93 @@
+/*
+* $XConsortium: AsciiSinkP.h,v 1.2 89/10/04 13:56:34 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * asciiSinkP.h - Private definitions for asciiSink object
+ *
+ */
+
+#ifndef _XawAsciiSinkP_h
+#define _XawAsciiSinkP_h
+
+/***********************************************************************
+ *
+ * AsciiSink Object Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/TextSinkP.h>
+#include <X11/Xraw/AsciiSink.h>
+
+/************************************************************
+ *
+ * New fields for the AsciiSink object class record.
+ *
+ ************************************************************/
+
+typedef struct _AsciiSinkClassPart {
+ int foo;
+} AsciiSinkClassPart;
+
+/* Full class record declaration */
+
+typedef struct _AsciiSinkClassRec {
+ ObjectClassPart object_class;
+ TextSinkClassPart text_sink_class;
+ AsciiSinkClassPart ascii_sink_class;
+} AsciiSinkClassRec;
+
+extern AsciiSinkClassRec asciiSinkClassRec;
+
+/* New fields for the AsciiSink object record */
+typedef struct {
+ /* public resources */
+ Boolean echo;
+ Boolean display_nonprinting;
+
+ /* private state */
+ GC normgc, invgc, xorgc;
+ Pixmap insertCursorOn;
+ XawTextInsertState laststate;
+ short cursor_x, cursor_y; /* Cursor Location. */
+} AsciiSinkPart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _AsciiSinkRec {
+ ObjectPart object;
+ TextSinkPart text_sink;
+ AsciiSinkPart ascii_sink;
+} AsciiSinkRec;
+
+#endif /* _XawAsciiSinkP_h */
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h
new file mode 100644
index 00000000..8021a53e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h
@@ -0,0 +1,190 @@
+/*
+ * $XConsortium: AsciiSrc.h,v 1.5 89/10/05 13:17:30 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ */
+
+
+/*
+ * AsciiSrc.h - Public Header file for Ascii Text Source.
+ *
+ * This is the public header file for the Ascii Text Source.
+ * It is intended to be used with the Text widget, the simplest way to use
+ * this text source is to use the AsciiText Object.
+ *
+ * Date: June 29, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+
+#ifndef _XawAsciiSrc_h
+#define _XawAsciiSrc_h
+
+#include <X11/Xraw/TextSrc.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+
+
+*/
+
+/* Class record constants */
+
+extern WidgetClass asciiSrcObjectClass;
+
+typedef struct _AsciiSrcClassRec *AsciiSrcObjectClass;
+typedef struct _AsciiSrcRec *AsciiSrcObject;
+
+/*
+ * Just to make people's lives a bit easier.
+ */
+
+#define AsciiSourceObjectClass AsciiSrcObjectClass
+#define AsciiSourceObject AsciiSrcObject
+
+/*
+ * Resource Definitions.
+ */
+
+#define XtCDataCompression "DataCompression"
+#define XtCPieceSize "PieceSize"
+#define XtCType "Type"
+#define XtCUseStringInPlace "UseStringInPlace"
+
+#define XtNdataCompression "dataCompression"
+#define XtNpieceSize "pieceSize"
+#define XtNtype "type"
+#define XtNuseStringInPlace "useStringInPlace"
+
+#define XtRAsciiType "AsciiType"
+
+#define XtEstring "string"
+#define XtEfile "file"
+
+typedef enum {XawAsciiFile, XawAsciiString} XawAsciiType;
+
+/************************************************************
+ *
+ * Public routines
+ *
+ ************************************************************/
+
+/* Function Name: XawAsciiSourceFreeString
+ * Description: Frees the string returned by a get values call
+ * on the string when the source is of type string.
+ * Arguments: w - the AsciiSrc object.
+ * Returns: none.
+ */
+
+void XawAsciiSourceFreeString(/* w */);
+/*
+Widget w;
+*/
+
+/* Function Name: XawAsciiSave
+ * Description: Saves all the pieces into a file or string as required.
+ * Arguments: w - the asciiSrc Object.
+ * Returns: TRUE if the save was successful.
+ */
+
+Boolean XawAsciiSave(/* w */);
+/*
+Widget w;
+*/
+
+/* Function Name: XawAsciiSaveAsFile
+ * Description: Save the current buffer as a file.
+ * Arguments: w - the asciiSrc object.
+ * name - name of the file to save this file into.
+ * Returns: True if the save was sucessful.
+ */
+
+Boolean XawAsciiSaveAsFile(/* w, name */);
+/*
+Widget w;
+String name;
+*/
+
+/* Function Name: XawAsciiSourceChanged
+ * Description: Returns true if the source has changed since last saved.
+ * Arguments: w - the asciiSource object.
+ * Returns: a Boolean (see description).
+ */
+
+Boolean XawAsciiSourceChanged(/* w */);
+/*
+Widget w;
+*/
+
+#ifdef XAW_BC
+/*************************************************************
+ *
+ * These functions are only preserved for compatability.
+ */
+
+#define ASCII_STRING /* Turn on R3 AsciiDisk and AsciiString */
+#define ASCII_DISK /* Emulation modes. */
+
+#ifdef ASCII_STRING
+#define XawStringSourceDestroy XtDestroyWidget
+#endif
+
+#ifdef ASCII_DISK
+#define XawDiskSourceDestroy XtDestroyWidget
+#endif
+
+#ifdef ASCII_STRING
+/* Function Name: AsciiStringSourceCreate
+ * Description: Creates a string source.
+ * Arguments: parent - the widget that will own this source.
+ * args, num_args - the argument list.
+ * Returns: a pointer to the new text source.
+ */
+
+Widget XawStringSourceCreate(/* parent, args, num_args */);
+/*
+Widget parent;
+ArgList args;
+Cardinal num_args;
+*/
+#endif /* ASCII_STRING */
+
+#ifdef ASCII_DISK
+/* Function Name: AsciiDiskSourceCreate
+ * Description: Creates a disk source.
+ * Arguments: parent - the widget that will own this source.
+ * args, num_args - the argument list.
+ * Returns: a pointer to the new text source.
+ */
+
+Widget XawDiskSourceCreate(/* parent, args, num_args */);
+/*
+Widget parent;
+ArgList args;
+Cardinal num_args;
+*/
+#endif /* ASCII_DISK */
+#endif /* XAW_BC */
+/*
+ * End of Compatability stuff.
+ *
+ ***************************************************/
+
+#endif /* _XawAsciiSrc_h - Don't add anything after this line. */
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h
new file mode 100644
index 00000000..f2ca6a22
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h
@@ -0,0 +1,133 @@
+/*
+* $XConsortium: AsciiSrcP.h,v 1.6 89/10/05 13:17:39 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * AsciiSrcP.h - Private Header for Ascii Text Source.
+ *
+ * This is the private header file for the Ascii Text Source.
+ * It is intended to be used with the Text widget, the simplest way to use
+ * this text source is to use the AsciiText Object.
+ *
+ * Date: June 29, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+/*
+ * TextSrcP.h - Private definitions for AsciiSrc object
+ *
+ */
+
+#ifndef _XawAsciiSrcP_h
+#define _XawAsciiSrcP_h
+
+#include <X11/Xraw/AsciiSrc.h>
+#include <X11/Xraw/TextSrcP.h>
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+#define TMPSIZ 32 /* bytes to allocate for tmpnam */
+
+#define MAGIC_VALUE ((XawTextPosition) -1) /* Magic value. */
+
+typedef struct _Piece { /* Piece of the text file of BUFSIZ allocated
+ characters. */
+ char * text; /* The text in this buffer. */
+ XawTextPosition used; /* The number of characters of this buffer
+ that have been used. */
+ struct _Piece *prev, *next; /* linked list pointers. */
+} Piece;
+
+/************************************************************
+ *
+ * New fields for the AsciiSrc object class record.
+ *
+ ************************************************************/
+
+typedef struct _AsciiSrcClassPart { char foo; } AsciiSrcClassPart;
+
+/* Full class record declaration */
+typedef struct _AsciiSrcClassRec {
+ ObjectClassPart object_class;
+ TextSrcClassPart text_src_class;
+ AsciiSrcClassPart ascii_src_class;
+} AsciiSrcClassRec;
+
+extern AsciiSrcClassRec asciiSrcClassRec;
+
+/* New fields for the AsciiSrc object record */
+
+typedef struct _AsciiSrcPart {
+
+ /* Resources. */
+
+ char *string; /* either the string, or the
+ file name, depending upon the type. */
+ XawAsciiType type; /* either string or disk. */
+ XawTextPosition piece_size; /* Size of text buffer for each piece. */
+ Boolean data_compression; /* compress to minimum memory automatically
+ on save? */
+ XtCallbackList callback; /* A callback list to call when the source is
+ changed. */
+ Boolean use_string_in_place; /* Use the string passed in place. */
+ int ascii_length; /* length field for ascii string emulation. */
+
+#ifdef ASCII_DISK
+ String filename; /* name of file for Compatability. */
+#endif /* ASCII_DISK */
+
+/* Private data. */
+
+ Boolean is_tempfile; /* Is this a temporary file? */
+ Boolean changes; /* Has this file been edited? */
+ Boolean allocated_string; /* Have I allocated the
+ string in ascii_src->string? */
+ XawTextPosition length; /* length of file */
+ Piece * first_piece; /* first piece of the text. */
+} AsciiSrcPart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _AsciiSrcRec {
+ ObjectPart object;
+ TextSrcPart text_src;
+ AsciiSrcPart ascii_src;
+} AsciiSrcRec;
+
+#endif /* _XawAsciiSrcP_h --- Don't add anything after this line. */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h
new file mode 100644
index 00000000..db543c0a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h
@@ -0,0 +1,110 @@
+/*
+ * $XConsortium: AsciiText.h,v 1.15 89/07/06 16:00:35 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/***********************************************************************
+ *
+ * AsciiText Widget
+ *
+ ***********************************************************************/
+
+/*
+ * AsciiText.c - Public header file for AsciiText Widget.
+ *
+ * This Widget is intended to be used as a simple front end to the
+ * text widget with an ascii source and ascii sink attached to it.
+ *
+ * Date: June 29, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _AsciiText_h
+#define _AsciiText_h
+
+/****************************************************************
+ *
+ * AsciiText widgets
+ *
+ ****************************************************************/
+
+#include <X11/Xraw/Text.h> /* AsciiText is a subclass of Text */
+#include <X11/Xraw/AsciiSrc.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ displayPosition TextPosition int 0
+ editType EditType XawTextEditType XawtextRead
+ font Font XFontStruct* Fixed
+ foreground Foreground Pixel Black
+ height Height Dimension font height
+ insertPosition TextPosition int 0
+ leftMargin Margin Dimension 2
+ mappedWhenManaged MappedWhenManaged Boolean True
+ selectTypes SelectTypes Pointer (internal)
+ selection Selection Pointer empty selection
+ sensitive Sensitive Boolean True
+ string String String NULL
+ textOptions TextOptions int 0
+ width Width Dimension 100
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * Everything else we need is in StringDefs.h or Text.h
+ */
+
+typedef struct _AsciiTextClassRec *AsciiTextWidgetClass;
+typedef struct _AsciiRec *AsciiWidget;
+
+extern WidgetClass asciiTextWidgetClass;
+
+/************************************************************
+ *
+ * Disk and String Emulation Info.
+ *
+ ************************************************************/
+
+#ifdef ASCII_STRING
+extern WidgetClass asciiStringWidgetClass;
+#endif
+
+#ifdef ASCII_DISK
+extern WidgetClass asciiDiskWidgetClass;
+#endif
+
+#endif /* _AsciiText_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h b/vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h
new file mode 100644
index 00000000..0391b597
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h
@@ -0,0 +1,138 @@
+/*
+ * $XConsortium: AsciiTextP.h,v 1.15 89/07/17 18:09:37 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/***********************************************************************
+ *
+ * AsciiText Widget
+ *
+ ***********************************************************************/
+
+/*
+ * AsciiText.c - Private header file for AsciiText Widget.
+ *
+ * This Widget is intended to be used as a simple front end to the
+ * text widget with an ascii source and ascii sink attached to it.
+ *
+ * Date: June 29, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _AsciiTextP_h
+#define _AsciiTextP_h
+
+#include <X11/Xraw/TextP.h>
+#include <X11/Xraw/AsciiSrc.h> /* no need to get private header. */
+#include <X11/Xraw/AsciiText.h>
+
+typedef struct {int empty;} AsciiClassPart;
+
+typedef struct _AsciiTextClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ TextClassPart text_class;
+ AsciiClassPart ascii_class;
+} AsciiTextClassRec;
+
+extern AsciiTextClassRec asciiTextClassRec;
+
+typedef struct { char foo; /* keep compiler happy. */ } AsciiPart;
+
+typedef struct _AsciiRec {
+ CorePart core;
+ SimplePart simple;
+ TextPart text;
+ AsciiPart ascii;
+} AsciiRec;
+
+/************************************************************
+ *
+ * Ascii String Emulation widget.
+ *
+ ************************************************************/
+
+#ifdef ASCII_STRING
+
+typedef struct {int empty;} AsciiStringClassPart;
+
+typedef struct _AsciiStringClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ TextClassPart text_class;
+ AsciiClassPart ascii_class;
+ AsciiStringClassPart string_class;
+} AsciiStringClassRec;
+
+extern AsciiStringClassRec asciiStringClassRec;
+
+typedef struct { char foo; /* keep compiler happy. */ } AsciiStringPart;
+
+typedef struct _AsciiStringRec {
+ CorePart core;
+ SimplePart simple;
+ TextPart text;
+ AsciiPart ascii;
+ AsciiStringPart ascii_str;
+} AsciiStringRec;
+
+#endif /* ASCII_STRING */
+
+#ifdef ASCII_DISK
+
+/************************************************************
+ *
+ * Ascii Disk Emulation widget.
+ *
+ ************************************************************/
+
+typedef struct {int empty;} AsciiDiskClassPart;
+
+typedef struct _AsciiDiskClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ TextClassPart text_class;
+ AsciiClassPart ascii_class;
+ AsciiDiskClassPart disk_class;
+} AsciiDiskClassRec;
+
+extern AsciiDiskClassRec asciiDiskClassRec;
+
+typedef struct { char foo; /* keep compiler happy. */ } AsciiDiskPart;
+
+typedef struct _AsciiDiskRec {
+ CorePart core;
+ SimplePart simple;
+ TextPart text;
+ AsciiPart ascii;
+ AsciiDiskPart ascii_disk;
+} AsciiDiskRec;
+#endif /* ASCII_DISK */
+
+#endif /* _AsciiTextP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Box.h b/vendor/x11iraf/obm/ObmW/Xraw/Box.h
new file mode 100644
index 00000000..ea75e305
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Box.h
@@ -0,0 +1,74 @@
+/*
+* $XConsortium: Box.h,v 1.21 91/05/04 18:58:58 rws Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawBox_h
+#define _XawBox_h
+
+#include <X11/Xmu/Converters.h>
+
+/***********************************************************************
+ *
+ * Box Widget (subclass of CompositeClass)
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ hSpace HSpace Dimension 4
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ orientation Orientation XtOrientation vertical
+ vSpace VSpace Dimension 4
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+/* New fields */
+#ifndef _XtStringDefs_h_
+#define XtNhSpace "hSpace"
+#define XtNvSpace "vSpace"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass boxWidgetClass;
+
+typedef struct _BoxClassRec *BoxWidgetClass;
+typedef struct _BoxRec *BoxWidget;
+
+#endif /* _XawBox_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/BoxP.h b/vendor/x11iraf/obm/ObmW/Xraw/BoxP.h
new file mode 100644
index 00000000..fb92b873
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/BoxP.h
@@ -0,0 +1,90 @@
+/*
+* $XConsortium: BoxP.h,v 1.16 89/11/06 10:51:28 swick Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * BoxP.h - Private definitions for Box widget
+ *
+ */
+
+#ifndef _XawBoxP_h
+#define _XawBoxP_h
+
+/***********************************************************************
+ *
+ * Box Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/Box.h>
+#include <X11/CompositeP.h>
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xmu/Converters.h>
+
+/* New fields for the Box widget class record */
+typedef struct {int empty;} BoxClassPart;
+
+/* Full class record declaration */
+typedef struct _BoxClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ BoxClassPart box_class;
+} BoxClassRec;
+
+extern BoxClassRec boxClassRec;
+
+/* New fields for the Box widget record */
+typedef struct {
+ /* resources */
+ Dimension h_space, v_space;
+ XtOrientation orientation;
+
+ /* private state */
+ Dimension preferred_width, preferred_height;
+ Dimension last_query_width, last_query_height;
+ XtGeometryMask last_query_mode;
+} BoxPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _BoxRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ BoxPart box;
+} BoxRec;
+
+#endif /* _XawBoxP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h b/vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h
new file mode 100644
index 00000000..f7e5f120
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h
@@ -0,0 +1,35 @@
+/* $XConsortium: Cardinals.h,v 1.5 89/03/30 16:05:19 jim Exp $ */
+/*
+
+Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of M.I.T. not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+M.I.T. makes no representations about the suitability of
+this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+*/
+
+#ifndef _Cardinals_h
+#define _Cardinals_h
+
+#define ZERO ((Cardinal)0)
+#define ONE ((Cardinal)1)
+#define TWO ((Cardinal)2)
+#define THREE ((Cardinal)3)
+#define FOUR ((Cardinal)4)
+#define FIVE ((Cardinal)5)
+#define SIX ((Cardinal)6)
+#define SEVEN ((Cardinal)7)
+#define EIGHT ((Cardinal)8)
+#define NINE ((Cardinal)9)
+#define TEN ((Cardinal)10)
+
+#endif /* _Cardinals_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Clock.h b/vendor/x11iraf/obm/ObmW/Xraw/Clock.h
new file mode 100644
index 00000000..d8ef8361
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Clock.h
@@ -0,0 +1,87 @@
+/*
+* $XConsortium: Clock.h,v 1.29 90/10/22 14:43:12 converse Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawClock_h
+#define _XawClock_h
+
+/***********************************************************************
+ *
+ * Clock Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xmu/Converters.h>
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ analog Boolean Boolean True
+ background Background Pixel white
+ backingStore BackingStore BackingStore default
+ border BorderColor Pixel Black
+ borderWidth BorderWidth Dimension 1
+ chime Boolean Boolean False
+ destroyCallback Callback Pointer NULL
+ font Font XFontStruct* fixed
+ foreground Foreground Pixel black
+ hand Foreground Pixel black
+ height Height Dimension 164
+ highlight Foreground Pixel black
+ mappedWhenManaged MappedWhenManaged Boolean True
+ padding Margin int 8
+ update Interval int 60 (seconds)
+ width Width Dimension 164
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/* Resource names used to the clock widget */
+
+ /* color of hands */
+#define XtNhand "hands"
+
+
+ /* Boolean: digital if FALSE */
+#define XtNanalog "analog"
+
+ /* Boolean: */
+#define XtNchime "chime"
+
+ /* Int: amount of space around outside of clock */
+#define XtNpadding "padding"
+
+typedef struct _ClockRec *ClockWidget; /* completely defined in ClockPrivate.h */
+typedef struct _ClockClassRec *ClockWidgetClass; /* completely defined in ClockPrivate.h */
+
+extern WidgetClass clockWidgetClass;
+
+#endif /* _XawClock_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ClockP.h b/vendor/x11iraf/obm/ObmW/Xraw/ClockP.h
new file mode 100644
index 00000000..4f7ac8c3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ClockP.h
@@ -0,0 +1,95 @@
+/*
+* $XConsortium: ClockP.h,v 1.21 90/10/22 14:43:22 converse Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawClockP_h
+#define _XawClockP_h
+
+#include <X11/Xos.h> /* Needed for struct tm. */
+#include <X11/Xraw/Clock.h>
+#include <X11/Xraw/SimpleP.h>
+
+#define SEG_BUFF_SIZE 128
+#define ASCII_TIME_BUFLEN 32 /* big enough for 26 plus slop */
+
+/* New fields for the clock widget instance record */
+typedef struct {
+ Pixel fgpixel; /* color index for text */
+ Pixel Hipixel; /* color index for Highlighting */
+ Pixel Hdpixel; /* color index for hands */
+ XFontStruct *font; /* font for text */
+ GC myGC; /* pointer to GraphicsContext */
+ GC EraseGC; /* eraser GC */
+ GC HandGC; /* Hand GC */
+ GC HighGC; /* Highlighting GC */
+/* start of graph stuff */
+ int update; /* update frequence */
+ Dimension radius; /* radius factor */
+ int backing_store; /* backing store type */
+ Boolean chime;
+ Boolean beeped;
+ Boolean analog;
+ Boolean show_second_hand;
+ Dimension second_hand_length;
+ Dimension minute_hand_length;
+ Dimension hour_hand_length;
+ Dimension hand_width;
+ Dimension second_hand_width;
+ Position centerX;
+ Position centerY;
+ int numseg;
+ int padding;
+ XPoint segbuff[SEG_BUFF_SIZE];
+ XPoint *segbuffptr;
+ XPoint *hour, *sec;
+ struct tm otm ;
+ XtIntervalId interval_id;
+ char prev_time_string[ASCII_TIME_BUFLEN];
+ } ClockPart;
+
+/* Full instance record declaration */
+typedef struct _ClockRec {
+ CorePart core;
+ SimplePart simple;
+ ClockPart clock;
+ } ClockRec;
+
+/* New fields for the Clock widget class record */
+typedef struct {int dummy;} ClockClassPart;
+
+/* Full class record declaration. */
+typedef struct _ClockClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ ClockClassPart clock_class;
+ } ClockClassRec;
+
+/* Class pointer. */
+extern ClockClassRec clockClassRec;
+
+#endif /* _XawClockP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Command.h b/vendor/x11iraf/obm/ObmW/Xraw/Command.h
new file mode 100644
index 00000000..da7c2274
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Command.h
@@ -0,0 +1,104 @@
+/* $XConsortium: Command.h,v 1.27 91/07/28 18:51:35 converse Exp $ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawCommand_h
+#define _XawCommand_h
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Label.h>
+
+/* Command widget resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ accelerators Accelerators AcceleratorTable NULL
+ ancestorSensitive AncestorSensitive Boolean True
+ background Background Pixel XtDefaultBackground
+ backgroundPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ bitmap Pixmap Pixmap None
+ borderColor BorderColor Pixel XtDefaultForeground
+ borderPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ borderWidth BorderWidth Dimension 1
+ callback Callback XtCallbackList NULL
+ colormap Colormap Colormap parent's colormap
+ cornerRoundPercent CornerRoundPercent Dimension 25
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ depth Depth int parent's depth
+ destroyCallback Callback XtCallbackList NULL
+ encoding Encoding UnsignedChar XawTextEncoding8bit
+ font Font XFontStruct* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ highlightThickness Thickness Dimension 0 if shaped, else 2
+ insensitiveBorder Insensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ leftBitmap LeftBitmap Pixmap None
+ mappedWhenManaged MappedWhenManaged Boolean True
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ resize Resize Boolean True
+ screen Screen Screen parent's Screen
+ sensitive Sensitive Boolean True
+ shapeStyle ShapeStyle ShapeStyle Rectangle
+ translations Translations TranslationTable see doc or source
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XtNhighlightThickness "highlightThickness"
+
+
+#define XtNarmedColor "armedColor"
+#define XtCArmedColor "ArmedColor"
+
+#define XtNshapeStyle "shapeStyle"
+#define XtCShapeStyle "ShapeStyle"
+#define XtRShapeStyle "ShapeStyle"
+#define XtNcornerRoundPercent "cornerRoundPercent"
+#define XtCCornerRoundPercent "CornerRoundPercent"
+
+#define XawShapeRectangle XmuShapeRectangle
+#define XawShapeOval XmuShapeOval
+#define XawShapeEllipse XmuShapeEllipse
+#define XawShapeRoundedRectangle XmuShapeRoundedRectangle
+
+
+extern void XawSetCommandColours Xraw_PROTO((Widget /* self */,
+ Pixel /* background */));
+
+extern WidgetClass commandWidgetClass;
+
+typedef struct _CommandClassRec *CommandWidgetClass;
+typedef struct _CommandRec *CommandWidget;
+
+#endif /* _XawCommand_h */
+/* DON'T ADD STUFF AFTER THIS */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/CommandP.h b/vendor/x11iraf/obm/ObmW/Xraw/CommandP.h
new file mode 100644
index 00000000..e41cae41
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/CommandP.h
@@ -0,0 +1,121 @@
+/*
+* $XConsortium: CommandP.h,v 1.30 90/12/01 13:00:10 rws Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * CommandP.h - Private definitions for Command widget
+ *
+ */
+
+#ifndef _XawCommandP_h
+#define _XawCommandP_h
+
+#include <X11/Xraw/Command.h>
+#include <X11/Xraw/LabelP.h>
+
+/***********************************************************************
+ *
+ * Command Widget Private Data
+ *
+ ***********************************************************************/
+
+typedef enum {
+ HighlightNone, /* Do not highlight. */
+ HighlightWhenUnset, /* Highlight only when unset, this is
+ to preserve current command widget
+ functionality. */
+ HighlightAlways /* Always highlight, lets the toggle widget
+ and other subclasses do the right thing. */
+} XtCommandHighlight;
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+
+ /* New fields for the Command widget class record */
+typedef struct _CommandClass
+ {
+ int makes_compiler_happy; /* not used */
+ } CommandClassPart;
+
+ /* Full class record declaration */
+typedef struct _CommandClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+} CommandClassRec;
+
+extern CommandClassRec commandClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+ /* New fields for the Command widget record */
+typedef struct {
+ /* resources */
+ Dimension highlight_thickness;
+ XtCallbackList callbacks;
+ Pixel armed;
+
+ /* private state */
+ Pixmap gray_pixmap;
+ GC normal_GC;
+ GC inverse_GC;
+ GC armed_GC;
+ GC shift_GC; /* used for shifted left bitmat */
+ Boolean set;
+ XtCommandHighlight highlighted;
+ /* more resources */
+ int shape_style;
+ Dimension corner_round;
+ Boolean changed_highlight;
+ Boolean changed_set;
+} CommandPart;
+
+
+/* XtEventsPtr eventTable;*/
+
+
+ /* Full widget declaration */
+typedef struct _CommandRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+ CommandPart command;
+} CommandRec;
+
+#endif /* _XawCommandP_h */
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Container.h b/vendor/x11iraf/obm/ObmW/Xraw/Container.h
new file mode 100644
index 00000000..a6164a9d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Container.h
@@ -0,0 +1,61 @@
+#ifndef _XawContainer_h
+#define _XawContainer_h
+
+
+#include <X11/Xraw/XawInit.h>
+
+/***********************************************************************
+ *
+ * Container Widget (subclass of CompositeClass)
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ hSpace HSpace Dimension 4
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+/* New fields */
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+#define XtNcontainerType "containerType"
+#define XtCContainerType "ContainerType"
+#define XtRContainerType "ContainerType"
+
+/* Class record constants */
+
+extern WidgetClass containerWidgetClass;
+
+typedef struct _ContainerClassRec *ContainerWidgetClass;
+typedef struct _ContainerRec *ContainerWidget;
+
+#endif /* _XawContainer_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h b/vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h
new file mode 100644
index 00000000..25097a74
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h
@@ -0,0 +1,71 @@
+#ifndef _CONTEINER_P_H_
+#define _CONTEINER_P_H_
+
+
+#include <X11/ConstrainP.h>
+#include <X11/Xraw/Container.h>
+
+#define CORE(w) ((Widget)(w))->core
+#define COMPOSITE(w) ((CompositeWidget)(w))->composite
+#define CONTAINER(w) ((ContainerWidget)(w))->container
+
+typedef struct {
+
+ /* public instance variables */
+
+ Pixel foreground;
+
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+
+ Dimension shadow_thickness;
+
+ XtPointer user_data;
+
+ /* private instance variables */
+
+ GC bottom_shadow_GC;
+ GC top_shadow_GC;
+ GC background_GC;
+
+} ContainerPart;
+
+
+typedef struct _ContainerRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+} ContainerRec;
+
+typedef struct _ContainerClassPart{
+ int unused;
+} ContainerClassPart;
+
+
+typedef struct _ContainerClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+} ContainerClassRec;
+
+/* container constraints */
+
+typedef struct _ContainerConstraintPart {
+ int unused;
+} ContainerConstraintPart;
+
+typedef struct _ContainerConstraintRec {
+ ContainerConstraintPart container;
+} ContainerCosntraintRec, *ContainerConstraintPtr;
+
+extern ContainerClassRec containerClassRec;
+
+
+extern void _XawQueryGeometry Xraw_PROTO((Widget widget,
+ XtWidgetGeometry *reply_return));
+
+#endif /* _CONTEINER_P_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Dialog.h b/vendor/x11iraf/obm/ObmW/Xraw/Dialog.h
new file mode 100644
index 00000000..1c678f0a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Dialog.h
@@ -0,0 +1,82 @@
+/* $XConsortium: Dialog.h,v 1.26 91/07/22 19:05:10 converse Exp $ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawDialog_h
+#define _XawDialog_h
+
+#include <X11/Xraw/Form.h>
+
+/***********************************************************************
+ *
+ * Dialog Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ height Height Dimension computed at create
+ icon Icon Pixmap 0
+ label Label String NULL
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ value Value String NULL
+ width Width Dimension computed at create
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XtCIcon "Icon"
+#define XtNicon "icon"
+
+typedef struct _DialogClassRec *DialogWidgetClass;
+typedef struct _DialogRec *DialogWidget;
+
+extern WidgetClass dialogWidgetClass;
+
+extern void XawDialogAddButton(
+#if NeedFunctionPrototypes
+ Widget /* dialog */,
+ char* /* name */,
+ XtCallbackProc /* function */,
+ XtPointer /* client_data */
+#endif
+);
+
+extern char *XawDialogGetValueString(
+#if NeedFunctionPrototypes
+ Widget /* w */
+#endif
+);
+
+#endif /* _XawDialog_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/DialogP.h b/vendor/x11iraf/obm/ObmW/Xraw/DialogP.h
new file mode 100644
index 00000000..85993f59
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/DialogP.h
@@ -0,0 +1,76 @@
+/* $XConsortium: DialogP.h,v 1.12 89/08/25 18:35:37 kit Exp $ */
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* Private definitions for Dialog widget */
+
+#ifndef _DialogP_h
+#define _DialogP_h
+
+#include <X11/Xraw/Dialog.h>
+#include <X11/Xraw/FormP.h>
+
+typedef struct {int empty;} DialogClassPart;
+
+typedef struct _DialogClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ FormClassPart form_class;
+ DialogClassPart dialog_class;
+} DialogClassRec;
+
+extern DialogClassRec dialogClassRec;
+
+typedef struct _DialogPart {
+ /* resources */
+ String label; /* description of the dialog */
+ String value; /* for the user response */
+ Pixmap icon; /* icon bitmap */
+ /* private data */
+ Widget iconW; /* widget to display the icon */
+ Widget labelW; /* widget to display description*/
+ Widget valueW; /* user response TextWidget */
+} DialogPart;
+
+typedef struct _DialogRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ FormPart form;
+ DialogPart dialog;
+} DialogRec;
+
+typedef struct {int empty;} DialogConstraintsPart;
+
+typedef struct _DialogConstraintsRec {
+ FormConstraintsPart form;
+ DialogConstraintsPart dialog;
+} DialogConstraintsRec, *DialogConstraints;
+
+#endif /* _DialogP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Form.h b/vendor/x11iraf/obm/ObmW/Xraw/Form.h
new file mode 100644
index 00000000..cf7b8554
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Form.h
@@ -0,0 +1,142 @@
+/* $XConsortium: Form.h,v 1.28 91/05/04 18:59:10 rws Exp $ */
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawForm_h
+#define _XawForm_h
+
+#include <X11/Xraw/Container.h>
+
+/***********************************************************************
+ *
+ * Form Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ defaultDistance Thickness int 4
+ destroyCallback Callback Pointer NULL
+ height Height Dimension computed at realize
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension computed at realize
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/* Constraint parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ bottom Edge XtEdgeType XtRubber
+ fromHoriz Widget Widget (left edge of form)
+ fromVert Widget Widget (top of form)
+ horizDistance Thickness int defaultDistance
+ left Edge XtEdgeType XtRubber
+ resizable Boolean Boolean False
+ right Edge XtEdgeType XtRubber
+ top Edge XtEdgeType XtRubber
+ vertDistance Thickness int defaultDistance
+
+*/
+
+
+#ifndef _XtStringDefs_h_
+#define XtNtop "top"
+#define XtRWidget "Widget"
+#endif
+
+#define XtNdefaultDistance "defaultDistance"
+#define XtNbottom "bottom"
+#define XtNleft "left"
+#define XtNright "right"
+#define XtNfromHoriz "fromHoriz"
+#define XtNfromVert "fromVert"
+#define XtNhorizDistance "horizDistance"
+#define XtNvertDistance "vertDistance"
+#define XtNresizable "resizable"
+
+#define XtCEdge "Edge"
+#define XtCWidget "Widget"
+
+#ifndef _XawEdgeType_e
+#define _XawEdgeType_e
+typedef enum {
+ XawChainTop, /* Keep this edge a constant distance from
+ the top of the form */
+ XawChainBottom, /* Keep this edge a constant distance from
+ the bottom of the form */
+ XawChainLeft, /* Keep this edge a constant distance from
+ the left of the form */
+ XawChainRight, /* Keep this edge a constant distance from
+ the right of the form */
+ XawRubber, /* Keep this edge a proportional distance
+ from the edges of the form*/
+ XawChainForm
+} XawEdgeType;
+#endif /* _XawEdgeType_e */
+
+/*
+ * Unfortunatly I missed this definition for R4, so I cannot
+ * protect it with XAW_BC, it looks like this particular problem is
+ * one that we will have to live with for a while.
+ *
+ * Chris D. Peterson - 3/23/90.
+ */
+
+#define XtEdgeType XawEdgeType
+
+#define XtChainTop XawChainTop
+#define XtChainBottom XawChainBottom
+#define XtChainLeft XawChainLeft
+#define XtChainRight XawChainRight
+#define XtRubber XawRubber
+#define XtChainForm XawChainForm
+
+typedef struct _FormClassRec *FormWidgetClass;
+typedef struct _FormRec *FormWidget;
+
+extern WidgetClass formWidgetClass;
+
+extern void XawFormDoLayout(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+#if NeedWidePrototypes
+ /* Boolean */ int /* do_layout */
+#else
+ Boolean /* do_layout */
+#endif
+#endif
+);
+
+#endif /* _XawForm_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/FormP.h b/vendor/x11iraf/obm/ObmW/Xraw/FormP.h
new file mode 100644
index 00000000..414f09ed
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/FormP.h
@@ -0,0 +1,126 @@
+/* $XConsortium: FormP.h,v 1.20 91/05/02 16:20:29 swick Exp $ */
+/* Copyright Massachusetts Institute of Technology 1987 */
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* Form widget private definitions */
+
+#ifndef _XawFormP_h
+#define _XawFormP_h
+
+#include <X11/ConstrainP.h>
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Form.h>
+
+#define XtREdgeType "EdgeType"
+
+typedef enum {LayoutPending, LayoutInProgress, LayoutDone} LayoutState;
+#define XtInheritLayout ((Boolean (*)())_XtInherit)
+
+typedef struct {
+ Boolean (*layout)(/* FormWidget, Dimension, Dimension */);
+} FormClassPart;
+
+/*
+ * Layout(
+ * FormWidget w - the widget whose children are to be configured
+ * Dimension w, h - bounding box of layout to be calculated
+ *
+ * Stores preferred geometry in w->form.preferred_{width,height}.
+ * If w->form.resize_in_layout is True, then a geometry request
+ * may be made for the preferred bounding box if necessary.
+ *
+ * Returns True if a geometry request was granted, False otherwise.
+ */
+
+typedef struct _FormClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ FormClassPart form_class;
+} FormClassRec;
+
+extern FormClassRec formClassRec;
+
+typedef struct _FormPart {
+ /* resources */
+ int default_spacing; /* default distance between children */
+ /* private state */
+ Dimension old_width, old_height; /* last known dimensions */
+ int no_refigure; /* no re-layout while > 0 */
+ Boolean needs_relayout; /* next time no_refigure == 0 */
+ Boolean resize_in_layout; /* should layout() do geom request? */
+ Dimension preferred_width, preferred_height; /* cached from layout */
+ Boolean resize_is_no_op; /* Causes resize to take not action. */
+} FormPart;
+
+typedef struct _FormRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ FormPart form;
+} FormRec;
+
+typedef struct _FormConstraintsPart {
+/*
+ * Constraint Resources.
+ */
+ XtEdgeType top, bottom, /* where to drag edge on resize */
+ left, right;
+ int dx; /* desired horiz offset */
+ int dy; /* desired vertical offset */
+ Widget horiz_base; /* measure dx from here if non-null */
+ Widget vert_base; /* measure dy from here if non-null */
+ Boolean allow_resize; /* TRUE if child may request resize */
+
+/*
+ * Private contstraint resources.
+ */
+
+/*
+ * What the size of this child would be if we did not impose the
+ * constraint the width and height must be greater than zero (0).
+ */
+ short virtual_width, virtual_height;
+
+/*
+ * Temporary Storage for children's new possible possition.
+ */
+
+ Position new_x, new_y;
+
+ LayoutState layout_state; /* temporary layout state */
+ Boolean deferred_resize; /* was resized while no_refigure is set */
+} FormConstraintsPart;
+
+typedef struct _FormConstraintsRec {
+ FormConstraintsPart form;
+} FormConstraintsRec, *FormConstraints;
+
+#endif /* _XawFormP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Frame.h b/vendor/x11iraf/obm/ObmW/Xraw/Frame.h
new file mode 100644
index 00000000..3af67dec
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Frame.h
@@ -0,0 +1,163 @@
+/***********************************************************************
+
+ Frame widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _XawFrame_h
+#define _XawFrame_h
+
+
+
+#include <X11/Xraw/3d.h>
+
+/***********************************************************************
+ *
+ * Frame Widget (subclass of CompositeClass)
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ hSpace HSpace Dimension 4
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+/* New fields */
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+#define XtNframeType "frameType"
+#define XtCFrameType "FrameType"
+#define XtRFrameType "FrameType"
+
+
+
+#ifndef XtNhSpace
+#define XtNhSpace "hSpace"
+#endif
+
+#ifndef XtNvSpace
+#define XtNvSpace "vSpace"
+#endif
+
+#ifndef XtCHSpace
+#define XtCHSpace "HSpace"
+#endif
+
+#ifndef XtCVSpace
+#define XtCVSpace "VSpace"
+#endif
+
+#ifndef XtNtop
+#define XtNtop "top"
+#endif
+
+
+#ifndef XtNbottom
+#define XtNbottom "bottom"
+#endif
+
+
+#ifndef XtNleft
+#define XtNleft "left"
+#endif
+
+
+#ifndef XtNright
+#define XtNright "right"
+#endif
+
+#ifndef XtNlayoutPolicy
+#define XtNlayoutPolicy "layoutPolicy"
+#endif
+
+#ifndef XtNxFraction
+#define XtNxFraction "xFraction"
+#endif
+
+#ifndef XtNyFraction
+#define XtNyFraction "yFraction"
+#endif
+
+#ifndef XtCLayoutPolicy
+#define XtCLayoutPolicy "LayoutPolicy"
+#endif
+
+#ifndef XtRLayoutPolicy
+#define XtRLayoutPolicy "LayoutPolicy"
+#endif
+
+
+#ifndef XtNcaptionOn
+#define XtNcaptionOn "captionOn"
+#endif
+
+#ifndef XtCCaptionOn
+#define XtCCaptionOn "CaptionOn"
+#endif
+
+
+#ifndef XtNcaptionLabel
+#define XtNcaptionLabel "captionLabel"
+#endif
+
+#ifndef XtCCaptionLabel
+#define XtCCaptionLabel "CaptionLabel"
+#endif
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass frameWidgetClass;
+
+typedef struct _FrameClassRec *FrameWidgetClass;
+typedef struct _FrameRec *FrameWidget;
+
+typedef enum {
+ XawSINGLE = Xraw_FRAME + 10,
+ XawFRACTION,
+ XawCENTER
+}XawLayoutPolicy;
+
+#endif /* _XawFrame_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/FrameP.h b/vendor/x11iraf/obm/ObmW/Xraw/FrameP.h
new file mode 100644
index 00000000..a88805cc
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/FrameP.h
@@ -0,0 +1,95 @@
+/*
+ * FrameP.h - Private definitions for Frame widget
+ *
+ * Author: Vladimir Romanovski
+ *
+ * Date: Mon Feb 27, 1995
+ */
+
+/***********************************************************************
+ *
+ * Frame Widget Private Data
+ *
+ ***********************************************************************/
+
+#ifndef _XawFrameP_h
+#define _XawFrameP_h
+
+#include <X11/ConstrainP.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Frame.h>
+
+#define FRAME(w) ((FrameWidget)(w))->frame
+
+/* New fields for the Frame widget class record */
+
+typedef struct _FrameClassPart{
+ XtPointer extension;
+} FrameClassPart;
+
+typedef struct _FrameClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ FrameClassPart frame_class;
+} FrameClassRec;
+
+/* New fields for the frame widget. */
+
+typedef struct _FramePart {
+ /* Constraint contstraint resources */
+ Dimension h_space;
+ Dimension v_space;
+
+ XawFrameType frame_type;
+
+ int x_fraction;
+ int y_fraction;
+ XawLayoutPolicy policy;
+
+ char *label;
+ XFontStruct *font;
+ Boolean caption;
+ XtJustify justify;
+ unsigned char encoding;
+
+ /* Private resources. */
+ Dimension preferred_width;
+ Dimension preferred_height;
+
+ GC gc;
+
+} FramePart;
+
+typedef struct _FrameRec{
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ FramePart frame;
+} FrameRec;
+
+typedef struct _FrameConstraintsPart {
+ /* Constraint contstraint resources */
+
+ int left;
+ int right;
+ int top;
+ int bottom;
+
+ /* Private contstraint resources. */
+
+} FrameConstraintsPart;
+
+typedef struct _FrameConstraintsRec {
+ FrameConstraintsPart frame;
+} FrameConstraintsRec, *FrameConstraints;
+
+
+
+extern FrameClassRec frameClassRec;
+
+
+#endif /* _XawFrameP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Grip.h b/vendor/x11iraf/obm/ObmW/Xraw/Grip.h
new file mode 100644
index 00000000..1d832626
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Grip.h
@@ -0,0 +1,83 @@
+/* $XConsortium: Grip.h,v 1.18 91/07/26 19:42:40 converse Exp $ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * Grip.h - Public Definitions for Grip widget (used by VPane Widget)
+ *
+ */
+
+#ifndef _XawGrip_h
+#define _XawGrip_h
+
+#include <X11/Xraw/Simple.h>
+
+/***************************************************************************
+ *
+ * Grip Widget
+ *
+ **************************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ foreground Foreground Pixel XtDefaultForeground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 0
+ callback Callback Pointer GripAction
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 8
+ mappedWhenManaged MappedWhenManaged Boolean True
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ sensitive Sensitive Boolean True
+ width Width Dimension 8
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+#define XtNgripTranslations "gripTranslations"
+#define XtNgripForeground "gripForeground"
+
+typedef struct _XawGripCallData {
+ XEvent *event; /* the event causing the GripAction */
+ String *params; /* the TranslationTable params */
+ Cardinal num_params; /* count of params */
+} XawGripCallDataRec, *XawGripCallData,
+ GripCallDataRec, *GripCallData; /* supported for R4 compatibility */
+
+/* Class Record Constant */
+
+extern WidgetClass gripWidgetClass;
+
+typedef struct _GripClassRec *GripWidgetClass;
+typedef struct _GripRec *GripWidget;
+
+#endif /* _XawGrip_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/GripP.h b/vendor/x11iraf/obm/ObmW/Xraw/GripP.h
new file mode 100644
index 00000000..e3d4248a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/GripP.h
@@ -0,0 +1,79 @@
+/*
+* $XConsortium: GripP.h,v 1.14 89/05/11 01:05:27 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * GripP.h - Private definitions for Grip widget (Used by VPane Widget)
+ *
+ */
+
+#ifndef _XawGripP_h
+#define _XawGripP_h
+
+#include <X11/Xraw/Grip.h>
+#include <X11/Xraw/SimpleP.h>
+
+/*****************************************************************************
+ *
+ * Grip Widget Private Data
+ *
+ *****************************************************************************/
+
+#define DEFAULT_GRIP_SIZE 10
+
+/* New fields for the Grip widget class record */
+typedef struct {int empty;} GripClassPart;
+
+/* Full Class record declaration */
+typedef struct _GripClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ GripClassPart grip_class;
+} GripClassRec;
+
+extern GripClassRec gripClassRec;
+
+/* New fields for the Grip widget record */
+typedef struct {
+ XtCallbackList grip_action;
+} GripPart;
+
+/*****************************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************************/
+
+typedef struct _GripRec {
+ CorePart core;
+ SimplePart simple;
+ GripPart grip;
+} GripRec;
+
+#endif /* _XawGripP_h */
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Label.h b/vendor/x11iraf/obm/ObmW/Xraw/Label.h
new file mode 100644
index 00000000..bbf98f6b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Label.h
@@ -0,0 +1,98 @@
+/* $XConsortium: Label.h,v 1.31 91/07/26 19:51:37 converse Exp $ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawLabel_h
+#define _XawLabel_h
+
+/***********************************************************************
+ *
+ * Label Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/Simple.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback XtCallbackList NULL
+ encoding Encoding unsigned char XawTextEncoding8bit
+ font Font XFontStruct* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ insensitiveBorder Insensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ leftBitmap LeftBitmap Pixmap None
+ mappedWhenManaged MappedWhenManaged Boolean True
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ resize Resize Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XawTextEncoding8bit 0
+#define XawTextEncodingChar2b 1
+
+#define XtNleftBitmap "leftBitmap"
+#define XtCLeftBitmap "LeftBitmap"
+#define XtNencoding "encoding"
+#define XtCEncoding "Encoding"
+
+#ifndef _XtStringDefs_h_
+#define XtNbitmap "bitmap"
+#define XtNforeground "foreground"
+#define XtNlabel "label"
+#define XtNfont "font"
+#define XtNinternalWidth "internalWidth"
+#define XtNinternalHeight "internalHeight"
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#define XtCBitmap "Bitmap"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass labelWidgetClass;
+
+typedef struct _LabelClassRec *LabelWidgetClass;
+typedef struct _LabelRec *LabelWidget;
+
+#endif /* _XawLabel_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/LabelP.h b/vendor/x11iraf/obm/ObmW/Xraw/LabelP.h
new file mode 100644
index 00000000..44deb671
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/LabelP.h
@@ -0,0 +1,111 @@
+/*
+* $XConsortium: LabelP.h,v 1.27 91/06/22 19:34:58 rws Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * LabelP.h - Private definitions for Label widget
+ *
+ */
+
+#ifndef _XawLabelP_h
+#define _XawLabelP_h
+
+/***********************************************************************
+ *
+ * Label Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/Label.h>
+
+/* New fields for the Label widget class record */
+
+typedef struct {
+ XtWidgetProc label_position;
+} LabelClassPart;
+
+/* Full class record declaration */
+typedef struct _LabelClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+} LabelClassRec;
+
+extern LabelClassRec labelClassRec;
+
+/* New fields for the Label widget record */
+typedef struct {
+ /* resources */
+ XFontStruct *font;
+ char *label;
+ XtJustify justify;
+ Dimension internal_width;
+ Dimension internal_height;
+ Pixmap pixmap;
+ Boolean resize;
+ unsigned char encoding;
+ Pixmap left_bitmap;
+
+ /* private state */
+ GC normal_GC;
+ GC gray_GC;
+ Pixmap stipple;
+ Position label_x;
+ Position label_y;
+ Dimension label_width;
+ Dimension label_height;
+ Dimension label_len;
+ int lbm_y; /* where in label */
+ unsigned int lbm_width, lbm_height; /* size of pixmap */
+ Boolean need_calculate_width;
+} LabelPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _LabelRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+} LabelRec;
+
+
+#define XtInheritLabelPosition ((void (*)())_XtInherit)
+#define XtLabelClass(w) ((LabelWidgetClass)XtClass(w))
+#define LEFT_OFFSET(lw) ((lw)->label.left_bitmap \
+ ? (lw)->label.lbm_width + (lw)->label.internal_width : 0)
+
+
+
+#endif /* _XawLabelP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/List.h b/vendor/x11iraf/obm/ObmW/Xraw/List.h
new file mode 100644
index 00000000..3081ef89
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/List.h
@@ -0,0 +1,225 @@
+/* $XConsortium: List.h,v 1.20 91/07/26 20:07:51 converse Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* This is the List widget, it is useful to display a list, without the
+ * overhead of having a widget for each item in the list. It allows
+ * the user to select an item in a list and notifies the application through
+ * a callback function.
+ *
+ * Created: 8/13/88
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ */
+
+#ifndef _XawList_h
+#define _XawList_h
+
+/***********************************************************************
+ *
+ * List Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/Simple.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback XtCallbackList NULL **6
+ columnSpacing Spacing Dimension 6
+ cursor Cursor Cursor left_ptr
+ cursorName Cursor String NULL
+ defaultColumns Columns int 2 **5
+ destroyCallback Callback Pointer NULL
+ font Font XFontStruct* XtDefaultFont
+ forceColumns Columns Boolean False **5
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension 0 **1
+ insensitiveBorder Insensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ list List String * NULL **2
+ longest Longest int 0 **3 **4
+ mappedWhenManaged MappedWhenManaged Boolean True
+ numberStrings NumberStrings int 0 **4
+ pasteBuffer Boolean Boolean False
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ rowSpacing Spacing Dimension 4
+ sensitive Sensitive Boolean True
+ verticalList Boolean Boolean False
+ width Width Dimension 0 **1
+ x Position Position 0
+ y Position Position 0
+
+ **1 - If the Width or Height of the list widget is zero (0) then the value
+ is set to the minimum size necessay to fit the entire list.
+
+ If both Width and Height are zero then they are adjusted to fit the
+ entire list that is created width the number of default columns
+ specified in the defaultColumns resource.
+
+ **2 - This is an array of strings the specify elements of the list.
+ This resource must be specified.
+ (What good is a list widget without a list?? :-)
+
+ **3 - Longest is the length of the widest string in pixels.
+
+ **4 - If either of these values are zero (0) then the list widget calculates
+ the correct value.
+
+ (This allows you to make startup faster if you already have
+ this information calculated)
+
+ NOTE: If the numberStrings value is zero the list must
+ be NULL terminated.
+
+ **5 - By setting the List.Columns resource you can force the application to
+ have a given number of columns.
+
+ **6 - This returns the name and index of the item selected in an
+ XawListReturnStruct that is pointed to by the client_data
+ in the CallbackProc.
+
+*/
+
+
+/*
+ * Value returned when there are no highlighted objects.
+ */
+
+#define XAW_LIST_NONE -1
+
+#define XtCList "List"
+#define XtCSpacing "Spacing"
+#define XtCColumns "Columns"
+#define XtCLongest "Longest"
+#define XtCNumberStrings "NumberStrings"
+
+#define XtNcursor "cursor"
+#define XtNcolumnSpacing "columnSpacing"
+#define XtNdefaultColumns "defaultColumns"
+#define XtNforceColumns "forceColumns"
+#define XtNlist "list"
+#define XtNlongest "longest"
+#define XtNnumberStrings "numberStrings"
+#define XtNpasteBuffer "pasteBuffer"
+#define XtNrowSpacing "rowSpacing"
+#define XtNverticalList "verticalList"
+
+#ifndef XtNdoubleClickCallback
+#define XtNdoubleClickCallback "doubleClickCallback"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass listWidgetClass;
+
+typedef struct _ListClassRec *ListWidgetClass;
+typedef struct _ListRec *ListWidget;
+
+/* The list return structure. */
+
+typedef struct _XawListReturnStruct {
+ String string;
+ int list_index;
+} XawListReturnStruct;
+
+/******************************************************************
+ *
+ * Exported Functions
+ *
+ *****************************************************************/
+
+/* Function Name: XawListChange.
+ * Description: Changes the list being used and shown.
+ * Arguments: w - the list widget.
+ * list - the new list.
+ * nitems - the number of items in the list.
+ * longest - the length (in Pixels) of the longest element
+ * in the list.
+ * resize - if TRUE the the list widget will
+ * try to resize itself.
+ * Returns: none.
+ * NOTE: If nitems of longest are <= 0 then they will be caluculated.
+ * If nitems is <= 0 then the list needs to be NULL terminated.
+ */
+
+extern void XawListChange(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ String* /* list */,
+ int /* nitems */,
+ int /* longest */,
+#if NeedWidePrototypes
+ /* Boolean */ int /* resize */
+#else
+ Boolean /* resize */
+#endif
+#endif
+);
+
+/* Function Name: XawListUnhighlight
+ * Description: unlights the current highlighted element.
+ * Arguments: w - the widget.
+ * Returns: none.
+ */
+
+extern void XawListUnhighlight(
+#if NeedFunctionPrototypes
+ Widget /* w */
+#endif
+);
+
+/* Function Name: XawListHighlight
+ * Description: Highlights the given item.
+ * Arguments: w - the list widget.
+ * item - the item to highlight.
+ * Returns: none.
+ */
+
+extern void XawListHighlight(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ int /* item */
+#endif
+);
+
+
+/* Function Name: XawListShowCurrent
+ * Description: returns the currently highlighted object.
+ * Arguments: w - the list widget.
+ * Returns: the info about the currently highlighted object.
+ */
+
+extern XawListReturnStruct * XawListShowCurrent(
+#if NeedFunctionPrototypes
+ Widget /* w */
+#endif
+);
+
+#endif /* _XawList_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ListP.h b/vendor/x11iraf/obm/ObmW/Xraw/ListP.h
new file mode 100644
index 00000000..4c2c86e1
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ListP.h
@@ -0,0 +1,115 @@
+/*
+ * $XConsortium: ListP.h,v 1.12 89/12/11 15:09:04 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris D. Peterson, MIT X Consortium
+ */
+
+
+/*
+ * ListP.h - Private definitions for List widget
+ *
+ * This is the List widget, it is useful to display a list, without the
+ * overhead of having a widget for each item in the list. It allows
+ * the user to select an item in a list and notifies the application through
+ * a callback function.
+ *
+ * Created: 8/13/88
+ * By: Chris D. Peterson
+ * MIT - Project Athena
+ */
+
+#ifndef _XawListP_h
+#define _XawListP_h
+
+/***********************************************************************
+ *
+ * List Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/List.h>
+
+#define NO_HIGHLIGHT XAW_LIST_NONE
+#define OUT_OF_RANGE -1
+#define OKAY 0
+
+/* New fields for the List widget class record */
+
+typedef struct {int foo;} ListClassPart;
+
+/* Full class record declaration */
+typedef struct _ListClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ ListClassPart list_class;
+} ListClassRec;
+
+extern ListClassRec listClassRec;
+
+/* New fields for the List widget record */
+typedef struct {
+ /* resources */
+ Pixel foreground;
+ Dimension internal_width,
+ internal_height,
+ column_space,
+ row_space;
+ int default_cols;
+ Boolean force_cols,
+ paste,
+ vertical_cols;
+ int longest;
+ int nitems; /* number of items in the list. */
+ XFontStruct *font;
+ String * list;
+ XtCallbackList callback;
+ XtCallbackList double_callback;
+
+ /* private state */
+
+ int is_highlighted, /* set to the item currently highlighted. */
+ highlight, /*set to the item that should be highlighted.*/
+ col_width, /* width of each column. */
+ row_height, /* height of each row. */
+ nrows, /* number of rows in the list. */
+ ncols; /* number of columns in the list. */
+ GC normgc, /* a couple o' GC's. */
+ revgc,
+ graygc; /* used when inactive. */
+
+} ListPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _ListRec {
+ CorePart core;
+ SimplePart simple;
+ ListPart list;
+} ListRec;
+
+#endif /* _XawListP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Logo.h b/vendor/x11iraf/obm/ObmW/Xraw/Logo.h
new file mode 100644
index 00000000..d1fed3bf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Logo.h
@@ -0,0 +1,50 @@
+/*
+* $XConsortium: Logo.h,v 1.11 90/10/22 14:45:11 converse Exp $
+*/
+
+/*
+Copyright 1988 by the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of M.I.T. not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+M.I.T. makes no representations about the suitability of
+this software for any purpose. It is provided "as is"
+without express or implied warranty.
+*/
+
+#ifndef _XawLogo_h
+#define _XawLogo_h
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension 100
+ mappedWhenManaged MappedWhenManaged Boolean True
+ shapeWindow ShapeWindow Boolean False
+ width Width Dimension 100
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XtNshapeWindow "shapeWindow"
+#define XtCShapeWindow "ShapeWindow"
+
+typedef struct _LogoRec *LogoWidget;
+typedef struct _LogoClassRec *LogoWidgetClass;
+
+extern WidgetClass logoWidgetClass;
+
+#endif /* _XawLogo_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/LogoP.h b/vendor/x11iraf/obm/ObmW/Xraw/LogoP.h
new file mode 100644
index 00000000..22d930a0
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/LogoP.h
@@ -0,0 +1,51 @@
+/*
+* $XConsortium: LogoP.h,v 1.9 90/10/22 14:45:51 converse Exp $
+*/
+
+/*
+Copyright 1988 by the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of M.I.T. not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+M.I.T. makes no representations about the suitability of
+this software for any purpose. It is provided "as is"
+without express or implied warranty.
+*/
+
+#ifndef _XawLogoP_h
+#define _XawLogoP_h
+
+#include <X11/Xraw/Logo.h>
+#include <X11/Xraw/SimpleP.h>
+
+typedef struct {
+ Pixel fgpixel;
+ GC foreGC;
+ GC backGC;
+ Boolean shape_window;
+ Boolean need_shaping;
+ } LogoPart;
+
+typedef struct _LogoRec {
+ CorePart core;
+ SimplePart simple;
+ LogoPart logo;
+ } LogoRec;
+
+typedef struct {int dummy;} LogoClassPart;
+
+typedef struct _LogoClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LogoClassPart logo_class;
+ } LogoClassRec;
+
+extern LogoClassRec logoClassRec;
+
+#endif /* _XawLogoP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h b/vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h
new file mode 100644
index 00000000..71ddd9b6
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h
@@ -0,0 +1,61 @@
+/*
+ * $XConsortium: Mailbox.h,v 1.20 91/05/04 18:58:42 rws Exp $
+ *
+ * Copyright 1988 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawMailbox_h
+#define _XawMailbox_h
+
+/*
+ * Mailbox widget; looks a lot like the clock widget, don't it...
+ */
+
+/* resource names used by mailbox widget that aren't defined in StringDefs.h */
+
+#ifndef _XtStringDefs_h_
+#define XtNupdate "update"
+#endif
+
+/* command to exec */
+#define XtNcheckCommand "checkCommand"
+#define XtNonceOnly "onceOnly"
+
+/* Int: volume for bell */
+#define XtNvolume "volume"
+#define XtNfullPixmap "fullPixmap"
+#define XtNfullPixmapMask "fullPixmapMask"
+#define XtNemptyPixmap "emptyPixmap"
+#define XtNemptyPixmapMask "emptyPixmapMask"
+#define XtNflip "flip"
+#define XtNshapeWindow "shapeWindow"
+
+#define XtCCheckCommand "CheckCommand"
+#define XtCVolume "Volume"
+#define XtCPixmapMask "PixmapMask"
+#define XtCFlip "Flip"
+#define XtCShapeWindow "ShapeWindow"
+
+
+/* structures */
+
+typedef struct _MailboxRec *MailboxWidget; /* see MailboxP.h */
+typedef struct _MailboxClassRec *MailboxWidgetClass; /* see MailboxP.h */
+
+
+extern WidgetClass mailboxWidgetClass;
+
+#endif /* _XawMailbox_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h b/vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h
new file mode 100644
index 00000000..1dd8d32e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h
@@ -0,0 +1,80 @@
+/*
+ * $XConsortium: MailboxP.h,v 1.20 91/07/19 21:52:57 rws Exp $
+ *
+ * Copyright 1988 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawMailboxP_h
+#define _XawMailboxP_h
+
+#include <X11/Xraw/Mailbox.h>
+#include <X11/Xraw/SimpleP.h>
+
+#ifdef SYSV
+#define MAILBOX_DIRECTORY "/usr/mail"
+#else
+#ifdef SVR4
+#define MAILBOX_DIRECTORY "/var/mail"
+#else
+#define MAILBOX_DIRECTORY "/usr/spool/mail"
+#endif
+#endif
+
+typedef struct { /* new fields for mailbox widget */
+ /* resources */
+ int update; /* seconds between updates */
+ Pixel foreground_pixel; /* color index of normal state fg */
+ String filename; /* filename to watch */
+ String check_command; /* command to exec for mail check */
+ Boolean flipit; /* do flip of full pixmap */
+ int volume; /* bell volume */
+ Boolean once_only; /* ring bell only once on new mail */
+ /* local state */
+ GC gc; /* normal GC to use */
+ long last_size; /* size in bytes of mailboxname */
+ XtIntervalId interval_id; /* time between checks */
+ Boolean flag_up; /* is the flag up? */
+ struct _mbimage {
+ Pixmap bitmap, mask; /* depth 1, describing shape */
+ Pixmap pixmap; /* full depth pixmap */
+ int width, height; /* geometry of pixmaps */
+ } full, empty;
+ Boolean shapeit; /* do shape extension */
+ struct {
+ Pixmap mask;
+ int x, y;
+ } shape_cache; /* last set of info */
+} MailboxPart;
+
+typedef struct _MailboxRec { /* full instance record */
+ CorePart core;
+ SimplePart simple;
+ MailboxPart mailbox;
+} MailboxRec;
+
+
+typedef struct { /* new fields for mailbox class */
+ int dummy; /* stupid C compiler */
+} MailboxClassPart;
+
+typedef struct _MailboxClassRec { /* full class record declaration */
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ MailboxClassPart mailbox_class;
+} MailboxClassRec;
+
+extern MailboxClassRec mailboxClassRec; /* class pointer */
+
+#endif /* _XawMailboxP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h b/vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h
new file mode 100644
index 00000000..92c95eda
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h
@@ -0,0 +1,96 @@
+/*
+ * $XConsortium: MenuButtoP.h,v 1.6 89/12/11 14:57:23 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/***********************************************************************
+ *
+ * MenuButton Widget
+ *
+ ***********************************************************************/
+
+/*
+ * MenuButtonP.h - Private Header file for MenuButton widget.
+ *
+ * This is the private header file for the Athena MenuButton widget.
+ * It is intended to provide an easy method of activating pulldown menus.
+ *
+ * Date: May 2, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _XawMenuButtonP_h
+#define _XawtMenuButtonP_h
+
+#include <X11/Xraw/MenuButton.h>
+#include <X11/Xraw/CommandP.h>
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+
+ /* New fields for the MenuButton widget class record */
+typedef struct _MenuButtonClass
+{
+ int makes_compiler_happy; /* not used */
+} MenuButtonClassPart;
+
+ /* Full class record declaration */
+typedef struct _MenuButtonClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ MenuButtonClassPart menuButton_class;
+} MenuButtonClassRec;
+
+extern MenuButtonClassRec menuButtonClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+ /* New fields for the MenuButton widget record */
+typedef struct {
+ /* resources */
+ String menu_name;
+} MenuButtonPart;
+
+ /* Full widget declaration */
+typedef struct _MenuButtonRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+ CommandPart command;
+ MenuButtonPart menu_button;
+} MenuButtonRec;
+
+#endif /* _XawMenuButtonP_h */
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h b/vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h
new file mode 100644
index 00000000..9c127c52
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h
@@ -0,0 +1,86 @@
+/*
+ * $XConsortium: MenuButton.h,v 1.7 89/12/11 14:57:44 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/***********************************************************************
+ *
+ * MenuButton Widget
+ *
+ ***********************************************************************/
+
+/*
+ * MenuButton.h - Public Header file for MenuButton widget.
+ *
+ * This is the public header file for the Athena MenuButton widget.
+ * It is intended to provide an easy method of activating pulldown menus.
+ *
+ * Date: May 2, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _XawMenuButton_h
+#define _XawMenuButton_h
+
+#include <X11/Xraw/Command.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback Pointer NULL
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ font Font XFontStruct* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ highlightThickness Thickness Dimension 2
+ insensitiveBorder Insensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ mappedWhenManaged MappedWhenManaged Boolean True
+ menuName MenuName String "menu"
+ resize Resize Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XtNmenuName "menuName"
+#define XtCMenuName "MenuName"
+
+extern WidgetClass menuButtonWidgetClass;
+
+typedef struct _MenuButtonClassRec *MenuButtonWidgetClass;
+typedef struct _MenuButtonRec *MenuButtonWidget;
+
+#endif /* _XawMenuButton_h -- DON'T ADD STUFF AFTER THIS */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Object.h b/vendor/x11iraf/obm/ObmW/Xraw/Object.h
new file mode 100644
index 00000000..bc0a002d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Object.h
@@ -0,0 +1,37 @@
+/* $XConsortium: Object.h,v 1.8 89/09/11 17:39:25 swick Exp $ */
+/* $oHeader: Object.h,v 1.2 88/08/18 15:55:32 asente Exp $ */
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XtObject_h
+#define _XtObject_h
+
+typedef struct _ObjectRec *Object;
+typedef struct _ObjectClassRec *ObjectClass;
+
+#ifndef OBJECT
+externalref WidgetClass objectClass;
+#endif
+#endif /* _XtObject_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Paned.h b/vendor/x11iraf/obm/ObmW/Xraw/Paned.h
new file mode 100644
index 00000000..c32de6a5
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Paned.h
@@ -0,0 +1,229 @@
+/*
+* $XConsortium: Paned.h,v 1.13 91/02/17 13:16:15 rws Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * Paned.h - Paned Composite Widget's public header file.
+ *
+ * Updated and significantly modifided from the Athena VPaned Widget.
+ *
+ * Date: March 1, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _XawPaned_h
+#define _XawPaned_h
+
+#include <X11/Constraint.h>
+#include <X11/Xmu/Converters.h>
+
+/****************************************************************
+ *
+ * Vertical Paned Widget (SubClass of CompositeClass)
+ *
+ ****************************************************************/
+
+/* RESOURCES:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ betweenCursor Cursor Cursor **
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ gripIndent GripIndent Position 10
+ gripCursor Cursor Cursor **
+ horizontalGripCursol Cursor Cursor sb_h_double_arrow
+ horizontalBetweencursor Cursor Cursor sb_up_arrow
+ internalBorderColor BorderColor Pixel XtDefaultForeground
+ internalBorderWidth BorderWidth Position 6
+ leftCursor Cursor Cursor sb_left_arrow
+ lowerCursor Cursor Cursor sb_down_arrow
+ mappedWhenManaged MappedWhenManaged Boolean True
+ orientation Orientation XtOrientation XtorientVertical
+ refigureMode Boolean Boolean On
+ rightCursor Cursor Cursor sb_right_arrow
+ sensitive Sensitive Boolean True
+ upperCursor Cursor Cursor sb_up_arrow
+ verticalBetweenCursor Cursor Cursor sb_left_arrow
+ verticalGripCursor Cursor Cursor sb_v_double_arrow
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+** These resources now are set to the vertical or horizontal cursor
+ depending upon orientation, by default. If a value is specified here
+ then that cursor will be used reguardless of orientation.
+
+
+CONSTRAINT RESOURCES:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ allowResize Boolean Boolean False
+ max Max Dimension unlimited
+ min Min Dimension Grip Size
+ preferredPaneSize PerferredPaneSize Dimension PANED_ASK_CHILD
+ resizeToPreferred Boolean Boolean False
+ showGrip ShowGrip Boolean True
+ skipAdjust Boolean Boolean False
+
+*/
+
+#define PANED_ASK_CHILD 0
+#define PANED_GRIP_SIZE 0
+
+/* New Fields */
+#define XtNallowResize "allowResize"
+#define XtNbetweenCursor "betweenCursor"
+#define XtNverticalBetweenCursor "verticalBetweenCursor"
+#define XtNhorizontalBetweenCursor "horizontalBetweenCursor"
+#define XtNgripCursor "gripCursor"
+#define XtNgripIndent "gripIndent"
+#define XtNhorizontalGripCursor "horizontalGripCursor"
+#define XtNinternalBorderColor "internalBorderColor"
+#define XtNinternalBorderWidth "internalBorderWidth"
+#define XtNleftCursor "leftCursor"
+#define XtNlowerCursor "lowerCursor"
+#define XtNrefigureMode "refigureMode"
+#define XtNposition "position"
+#define XtNmin "min"
+#define XtNmax "max"
+#define XtNpreferredPaneSize "preferredPaneSize"
+#define XtNresizeToPreferred "resizeToPreferred"
+#define XtNrightCursor "rightCursor"
+#define XtNshowGrip "showGrip"
+#define XtNskipAdjust "skipAdjust"
+#define XtNupperCursor "upperCursor"
+#define XtNverticalGripCursor "verticalGripCursor"
+
+#define XtCGripIndent "GripIndent"
+#define XtCMin "Min"
+#define XtCMax "Max"
+#define XtCPreferredPaneSize "PreferredPaneSize"
+#define XtCShowGrip "ShowGrip"
+
+/* Class record constant */
+extern WidgetClass panedWidgetClass;
+
+typedef struct _PanedClassRec *PanedWidgetClass;
+typedef struct _PanedRec *PanedWidget;
+
+/************************************************************
+ *
+ * Public Procedures
+ *
+ ************************************************************/
+
+/* Function Name: XawPanedSetMinMax
+ * Description: Sets the min and max size for a pane.
+ * Arguments: widget - the widget that is a child of the Paned widget.
+ * min, max - the new min and max size for the pane.
+ * Returns: none.
+ */
+
+extern void XawPanedSetMinMax(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ int /* min */,
+ int /* max */
+#endif
+);
+
+/* Function Name: XawPanedGetMinMax
+ * Description: Gets the min and max size for a pane.
+ * Arguments: widget - the widget that is a child of the Paned widget.
+ ** RETURNED ** min, max - the current min and max size for the pane.
+ * Returns: none.
+ */
+
+extern void XawPanedGetMinMax(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ int * /* min_return */,
+ int * /* max_return */
+#endif
+);
+
+/* Function Name: XawPanedSetRefigureMode
+ * Description: Allows a flag to be set the will inhibit
+ * the paned widgets relayout routine.
+ * Arguments: w - the paned widget.
+ * mode - if FALSE then inhibit refigure.
+ * Returns: none.
+ */
+
+extern void XawPanedSetRefigureMode(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+#if NeedWidePrototypes
+ /* Boolean */ int /* mode */
+#else
+ Boolean /* mode */
+#endif
+#endif
+);
+
+/* Function Name: XawPanedGetNumSub
+ * Description: Returns the number of panes in the paned widget.
+ * Arguments: w - the paned widget.
+ * Returns: the number of panes in the paned widget.
+ */
+
+extern int XawPanedGetNumSub(
+#if NeedFunctionPrototypes
+ Widget /* w */
+#endif
+);
+
+/* Function Name: XawPanedAllowResize
+ * Description: Allows a flag to be set that determines if the paned
+ * widget will allow geometry requests from this child
+ * Arguments: widget - a child of the paned widget.
+ * Returns: none.
+ */
+
+extern void XawPanedAllowResize(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+#if NeedWidePrototypes
+ /* Boolean */ int /* allow_resize */
+#else
+ Boolean /* allow_resize */
+#endif
+#endif
+);
+
+#endif /* _XawPaned_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/PanedP.h b/vendor/x11iraf/obm/ObmW/Xraw/PanedP.h
new file mode 100644
index 00000000..7954bda1
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/PanedP.h
@@ -0,0 +1,172 @@
+/***********************************************************
+
+ $XConsortium: PanedP.h,v 1.5 91/05/09 20:58:23 gildea Exp $
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * PanedP.h - Paned Composite Widget's private header file.
+ *
+ * Updated and significantly modified from the Athena VPaned Widget.
+ *
+ * Date: March 1, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _XawPanedP_h
+#define _XawPanedP_h
+
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Paned.h>
+
+/*********************************************************************
+ *
+ * Paned Widget Private Data
+ *
+ *********************************************************************/
+
+/* New fields for the Paned widget class record */
+
+typedef struct _PanedClassPart {
+ int foo; /* keep compiler happy. */
+} PanedClassPart;
+
+/* Full Class record declaration */
+typedef struct _PanedClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ PanedClassPart paned_class;
+} PanedClassRec;
+
+extern PanedClassRec panedClassRec;
+
+/* Paned constraint record */
+typedef struct _PanedConstraintsPart {
+ /* Resources. */
+ Dimension min; /* Minimum height */
+ Dimension max; /* Maximum height */
+ Boolean allow_resize; /* TRUE iff child resize requests are ok */
+ Boolean show_grip; /* TRUE iff child will have grip below it,
+ when it is not the bottom pane. */
+ Boolean skip_adjust; /* TRUE iff child's height should not be */
+ /* changed without explicit user action. */
+ int position; /* position location in Paned (relative to
+ other children) ** NIY ** */
+ Dimension preferred_size; /* The Preferred size of the pane.
+ Iff this is zero then ask child for size.*/
+ Boolean resize_to_pref; /* resize this pane to its preferred size
+ on a resize or change managed after
+ realize. */
+ /* Private state. */
+ Position delta; /* Desired Location */
+ Position olddelta; /* The last value of dy. */
+ Boolean paned_adjusted_me; /* Has the vpaned adjusted this widget w/o
+ user interaction to make things fit? */
+ Dimension wp_size; /* widget's preferred size */
+ int size; /* the size the widget will actually get. */
+ Widget grip; /* The grip for this child */
+
+} PanedConstraintsPart, *Pane;
+
+typedef struct _PanedConstraintsRec {
+ PanedConstraintsPart paned;
+} PanedConstraintsRec, *PanedConstraints;
+
+/*
+ * The Pane Stack Structure.
+ */
+
+typedef struct _PaneStack {
+ struct _PaneStack * next; /* The next element on the stack. */
+ Pane pane; /* The pane in this element on the stack. */
+ int start_size; /* The size of this element when it was pushed
+ onto the stack. */
+} PaneStack;
+
+/* New Fields for the Paned widget record */
+typedef struct {
+ /* resources */
+ Position grip_indent; /* Location of grips (offset
+ from right margin) */
+ Boolean refiguremode; /* Whether to refigure changes
+ right now */
+ XtTranslations grip_translations; /* grip translation table */
+ Dimension internal_bw; /* internal border width. */
+ XtOrientation orientation; /* Orientation of paned widget. */
+
+ Cursor cursor; /* Cursor for paned window */
+ Cursor grip_cursor; /* inactive grip cursor */
+ Cursor v_grip_cursor; /* inactive vert grip cursor */
+ Cursor h_grip_cursor; /* inactive horiz grip cursor */
+ Cursor adjust_this_cursor; /* active grip cursor: T */
+ Cursor v_adjust_this_cursor; /* active vert grip cursor: T */
+ Cursor h_adjust_this_cursor; /* active horiz grip cursor: T */
+
+ /* vertical. */
+ Cursor adjust_upper_cursor; /* active grip cursor: U */
+ Cursor adjust_lower_cursor; /* active grip cursor: D */
+
+ /* horizontal. */
+ Cursor adjust_left_cursor; /* active grip cursor: U */
+ Cursor adjust_right_cursor; /* active grip cursor: D */
+
+ Dimension v_space;
+ Dimension h_space;
+
+ /* private */
+ Boolean recursively_called; /* for ChangeManaged */
+ Boolean resize_children_to_pref; /* override constrain resources
+ and resize all children to
+ preferred size. */
+ int start_loc; /* mouse origin when adjusting */
+ Widget whichadd; /* Which pane to add changes to */
+ Widget whichsub; /* Which pane to sub changes from */
+ GC flipgc; /* GC to use when animating
+ borders */
+ int num_panes; /* count of managed panes */
+ PaneStack * stack; /* The pane stack for this widget.*/
+
+} PanedPart;
+
+/**************************************************************************
+ *
+ * Full instance record declaration
+ *
+ **************************************************************************/
+
+typedef struct _PanedRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ PanedPart paned;
+} PanedRec;
+
+#endif /* _XawPanedP_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Panner.h b/vendor/x11iraf/obm/ObmW/Xraw/Panner.h
new file mode 100644
index 00000000..9d0be8fa
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Panner.h
@@ -0,0 +1,104 @@
+/*
+ * $XConsortium: Panner.h,v 1.21 91/05/04 18:59:17 rws Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPanner_h
+#define _XawPanner_h
+
+#include <X11/Xraw/Reports.h>
+
+/*****************************************************************************
+ *
+ * Panner Widget (subclass of Simple)
+ *
+ * This widget is used to represent navigation in a 2d coordinate system.
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * allowOff AllowOff Boolean FALSE
+ * background Background Pixel XtDefaultBackground
+ * backgroundStipple BackgroundStipple String NULL
+ * canvasWidth CanvasWidth Dimension 0
+ * canvasHeight CanvasHeight Dimension 0
+ * defaultScale DefaultScale Dimension 8 percent
+ * foreground Foreground Pixel XtDefaultBackground
+ * internalSpace InternalSpace Dimension 4
+ * lineWidth LineWidth Dimension 0
+ * reportCallback ReportCallback XtCallbackList NULL
+ * resize Resize Boolean TRUE
+ * rubberBand RubberBand Boolean FALSE
+ * shadowColor ShadowColor Pixel XtDefaultForeground
+ * shadowThickness ShadowThickness Dimension 2
+ * sliderX SliderX Position 0
+ * sliderY SliderY Position 0
+ * sliderWidth SliderWidth Dimension 0
+ * sliderHeight SliderHeight Dimension 0
+ *
+ *****************************************************************************/
+
+ /* new instance and class names */
+#ifndef _XtStringDefs_h_
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#endif
+
+#define XtNallowOff "allowOff"
+#define XtCAllowOff "AllowOff"
+#define XtNbackgroundStipple "backgroundStipple"
+#define XtCBackgroundStipple "BackgroundStipple"
+#define XtNdefaultScale "defaultScale"
+#define XtCDefaultScale "DefaultScale"
+#define XtNcanvasWidth "canvasWidth"
+#define XtCCanvasWidth "CanvasWidth"
+#define XtNcanvasHeight "canvasHeight"
+#define XtCCanvasHeight "CanvasHeight"
+#define XtNinternalSpace "internalSpace"
+#define XtCInternalSpace "InternalSpace"
+#define XtNlineWidth "lineWidth"
+#define XtCLineWidth "LineWidth"
+#define XtNrubberBand "rubberBand"
+#define XtCRubberBand "RubberBand"
+#define XtNshadowThickness "shadowThickness"
+#define XtCShadowThickness "ShadowThickness"
+#define XtNshadowColor "shadowColor"
+#define XtCShadowColor "ShadowColor"
+#define XtNsliderX "sliderX"
+#define XtCSliderX "SliderX"
+#define XtNsliderY "sliderY"
+#define XtCSliderY "SliderY"
+#define XtNsliderWidth "sliderWidth"
+#define XtCSliderWidth "SliderWidth"
+#define XtNsliderHeight "sliderHeight"
+#define XtCSliderHeight "SliderHeight"
+
+ /* external declarations */
+extern WidgetClass pannerWidgetClass;
+
+typedef struct _PannerClassRec *PannerWidgetClass;
+typedef struct _PannerRec *PannerWidget;
+
+#endif /* _XawPanner_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/PannerP.h b/vendor/x11iraf/obm/ObmW/Xraw/PannerP.h
new file mode 100644
index 00000000..58aa6ce2
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/PannerP.h
@@ -0,0 +1,100 @@
+/*
+ * $XConsortium: PannerP.h,v 1.18 90/04/11 17:05:11 jim Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPannerP_h
+#define _XawPannerP_h
+
+#include <X11/Xraw/Panner.h>
+#include <X11/Xraw/SimpleP.h> /* parent */
+
+typedef struct { /* new fields in widget class */
+ int dummy;
+} PannerClassPart;
+
+typedef struct _PannerClassRec { /* Panner widget class */
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ PannerClassPart panner_class;
+} PannerClassRec;
+
+typedef struct { /* new fields in widget */
+ /* resources... */
+ XtCallbackList report_callbacks; /* callback/Callback */
+ Boolean allow_off; /* allowOff/AllowOff */
+ Boolean resize_to_pref; /* resizeToPreferred/Boolean */
+ Pixel foreground; /* foreground/Foreground */
+ Pixel shadow_color; /* shadowColor/ShadowColor */
+ Dimension shadow_thickness; /* shadowThickness/ShadowThickness */
+ Dimension default_scale; /* defaultScale/DefaultScale */
+ Dimension line_width; /* lineWidth/LineWidth */
+ Dimension canvas_width; /* canvasWidth/CanvasWidth */
+ Dimension canvas_height; /* canvasHeight/CanvasHeight */
+ Position slider_x; /* sliderX/SliderX */
+ Position slider_y; /* sliderY/SliderY */
+ Dimension slider_width; /* sliderWidth/SliderWidth */
+ Dimension slider_height; /* sliderHeight/SliderHeight */
+ Dimension internal_border; /* internalBorderWidth/BorderWidth */
+ String stipple_name; /* backgroundStipple/BackgroundStipple */
+ /* private data... */
+ GC slider_gc; /* background of slider */
+ GC shadow_gc; /* edge of slider and shadow */
+ GC xor_gc; /* for doing XOR tmp graphics */
+ double haspect, vaspect; /* aspect ratio of core to canvas */
+ Boolean rubber_band; /* true = rubber band, false = move */
+ struct {
+ Boolean doing; /* tmp graphics in progress */
+ Boolean showing; /* true if tmp graphics displayed */
+ Position startx, starty; /* initial position of slider */
+ Position dx, dy; /* offset loc for tmp graphics */
+ Position x, y; /* location for tmp graphics */
+ } tmp;
+ Position knob_x, knob_y; /* real upper left of knob in canvas */
+ Dimension knob_width, knob_height; /* real size of knob in canvas */
+ Boolean shadow_valid; /* true if rects are valid */
+ XRectangle shadow_rects[2]; /* location of shadows */
+ Position last_x, last_y; /* previous location of knob */
+} PannerPart;
+
+typedef struct _PannerRec {
+ CorePart core;
+ SimplePart simple;
+ PannerPart panner;
+} PannerRec;
+
+#define PANNER_HSCALE(pw,val) ((pw)->panner.haspect * ((double) (val)))
+#define PANNER_VSCALE(pw,val) ((pw)->panner.vaspect * ((double) (val)))
+
+#define PANNER_DSCALE(pw,val) (Dimension) \
+ ((((unsigned long) (val)) * (unsigned long) pw->panner.default_scale) / 100L)
+#define PANNER_DEFAULT_SCALE 8 /* percent */
+
+#define PANNER_OUTOFRANGE -30000
+
+/*
+ * external declarations
+ */
+extern PannerClassRec pannerClassRec;
+
+#endif /* _XawPannerP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Porthole.h b/vendor/x11iraf/obm/ObmW/Xraw/Porthole.h
new file mode 100644
index 00000000..68005c83
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Porthole.h
@@ -0,0 +1,60 @@
+/*
+ * $XConsortium: Porthole.h,v 1.1 90/02/28 18:07:31 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPorthole_h
+#define _XawPorthole_h
+
+#include <X11/Xraw/Reports.h>
+
+/*****************************************************************************
+ *
+ * Porthole Widget (subclass of Composite)
+ *
+ * This widget is similar to a viewport without scrollbars. Child movement
+ * is done by external panners or scrollbars.
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * background Background Pixel XtDefaultBackground
+ * border BorderColor Pixel XtDefaultForeground
+ * borderWidth BorderWidth Dimension 1
+ * height Height Dimension 0
+ * reportCallback ReportCallback Pointer NULL
+ * width Width Dimension 0
+ * x Position Position 0
+ * y Position Position 0
+ *
+ *****************************************************************************/
+
+ /* external declarations */
+
+extern WidgetClass portholeWidgetClass;
+typedef struct _PortholeClassRec *PortholeWidgetClass;
+typedef struct _PortholeRec *PortholeWidget;
+
+#endif /* _XawPorthole_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h b/vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h
new file mode 100644
index 00000000..fca997ba
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h
@@ -0,0 +1,63 @@
+/*
+ * $XConsortium: PortholeP.h,v 1.1 90/02/28 18:07:32 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPortholeP_h
+#define _XawPortholeP_h
+
+#include <X11/CompositeP.h>
+#include <X11/Xraw/Porthole.h>
+
+
+typedef struct { /* new fields in widget class */
+ int dummy;
+} PortholeClassPart;
+
+typedef struct _PortholeClassRec { /* Porthole widget class */
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ PortholeClassPart porthole_class;
+} PortholeClassRec;
+
+
+typedef struct { /* new fields in widget */
+ /* resources... */
+ XtCallbackList report_callbacks; /* callback/Callback */
+ /* private data... */
+} PortholePart;
+
+typedef struct _PortholeRec {
+ CorePart core;
+ CompositePart composite;
+ PortholePart porthole;
+} PortholeRec;
+
+
+/*
+ * external declarations
+ */
+extern PortholeClassRec portholeClassRec;
+
+
+#endif /* _XawPortholeP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Repeater.h b/vendor/x11iraf/obm/ObmW/Xraw/Repeater.h
new file mode 100644
index 00000000..e0c6b20b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Repeater.h
@@ -0,0 +1,73 @@
+/*
+ * $XConsortium: Repeater.h,v 1.3 90/03/02 15:46:57 jim Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawRepeater_h
+#define _XawRepeater_h
+
+#include <X11/Xraw/Command.h>
+
+/*****************************************************************************
+ *
+ * Repeater Widget (subclass of Command)
+ *
+ * This widget is a push button that repeatedly fires when held down.
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * decay Decay int 5 milliseconds
+ * flash Boolean Boolean FALSE
+ * initialDelay Delay int 200 milliseconds
+ * minimumDelay MinimumDelay int 10 milliseconds
+ * repeatDelay Delay int 50 milliseconds
+ * startCallback StartCallback XtCallbackList NULL
+ * stopCallback StopCallback XtCallbackList NULL
+ *
+ *****************************************************************************/
+
+ /* new instance and class names */
+#define XtNdecay "decay"
+#define XtCDecay "Decay"
+#define XtNinitialDelay "initialDelay"
+#define XtCDelay "Delay"
+#define XtNminimumDelay "minimumDelay"
+#define XtCMinimumDelay "MinimumDelay"
+#define XtNrepeatDelay "repeatDelay"
+#define XtNflash "flash"
+#define XtNstartCallback "startCallback"
+#define XtCStartCallback "StartCallback"
+#define XtNstopCallback "stopCallback"
+#define XtCStopCallback "StopCallback"
+
+
+ /* external declarations */
+extern WidgetClass repeaterWidgetClass;
+
+typedef struct _RepeaterClassRec *RepeaterWidgetClass;
+typedef struct _RepeaterRec *RepeaterWidget;
+
+#endif /* _XawRepeater_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h b/vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h
new file mode 100644
index 00000000..716e295b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h
@@ -0,0 +1,76 @@
+/*
+ * $XConsortium: RepeaterP.h,v 1.3 90/03/02 15:47:00 jim Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawRepeaterP_h
+#define _XawRepeaterP_h
+
+#include <X11/Xraw/CommandP.h>
+#include <X11/Xraw/Repeater.h>
+
+typedef struct { /* new fields in widget class */
+ int dummy;
+} RepeaterClassPart;
+
+typedef struct _RepeaterClassRec { /* Repeater widget class */
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ RepeaterClassPart repeater_class;
+} RepeaterClassRec;
+
+typedef struct { /* new fields in widget */
+ /* resources... */
+ int initial_delay; /* initialDelay/Delay */
+ int repeat_delay; /* repeatDelay/Delay */
+ int minimum_delay; /* minimumDelay/MinimumDelay */
+ int decay; /* decay to minimum delay */
+ Boolean flash; /* flash/Boolean */
+ XtCallbackList start_callbacks; /* startCallback/StartCallback */
+ XtCallbackList stop_callbacks; /* stopCallback/StopCallback */
+ /* private data... */
+ int next_delay; /* next amount for timer */
+ XtIntervalId timer; /* timer that will fire */
+} RepeaterPart;
+
+typedef struct _RepeaterRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+ CommandPart command;
+ RepeaterPart repeater;
+} RepeaterRec;
+
+#define REP_DEF_DECAY 5 /* milliseconds */
+#define REP_DEF_INITIAL_DELAY 200 /* milliseconds */
+#define REP_DEF_MINIMUM_DELAY 10 /* milliseconds */
+#define REP_DEF_REPEAT_DELAY 50 /* milliseconds */
+
+/*
+ * external declarations
+ */
+extern RepeaterClassRec repeaterClassRec;
+
+#endif /* _XawRepeaterP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Reports.h b/vendor/x11iraf/obm/ObmW/Xraw/Reports.h
new file mode 100644
index 00000000..caa136f2
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Reports.h
@@ -0,0 +1,51 @@
+/*
+ * $XConsortium: Reports.h,v 1.3 90/02/28 18:46:46 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _Xaw_Reports_h
+#define _Xaw_Reports_h
+
+/*
+ * XawPannerReport - this structure is used by the reportCallback of the
+ * Panner, Porthole, Viewport, and Scrollbar widgets to report its position.
+ * All fields must be filled in, although the changed field may be used as
+ * a hint as to which fields have been altered since the last report.
+ */
+typedef struct {
+ unsigned int changed; /* mask, see below */
+ Position slider_x, slider_y; /* location of slider within outer */
+ Dimension slider_width, slider_height; /* size of slider */
+ Dimension canvas_width, canvas_height; /* size of canvas */
+} XawPannerReport;
+
+#define XawPRSliderX (1 << 0)
+#define XawPRSliderY (1 << 1)
+#define XawPRSliderWidth (1 << 2)
+#define XawPRSliderHeight (1 << 3)
+#define XawPRCanvasWidth (1 << 4)
+#define XawPRCanvasHeight (1 << 5)
+#define XawPRAll (63) /* union of above */
+
+#define XtNreportCallback "reportCallback"
+#define XtCReportCallback "reportCallback"
+
+#endif /* _Xaw_Reports_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h b/vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h
new file mode 100644
index 00000000..b62c7b13
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h
@@ -0,0 +1,221 @@
+/* $XConsortium: Scrollbar.h,v 1.7 91/07/26 21:59:31 converse Exp $ */
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _Scrollbar_h
+#define _Scrollbar_h
+
+/****************************************************************
+ *
+ * Scrollbar Widget
+ *
+ ****************************************************************/
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Simple.h>
+
+/* Scrollbar resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ accelerators Accelerators AcceleratorTable NULL
+ ancestorSensitive AncestorSensitive Boolean True
+ background Background Pixel XtDefaultBackground
+ backgroundPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ borderColor BorderColor Pixel XtDefaultForeground
+ borderPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ borderWidth BorderWidth Dimension 1
+ colormap Colormap Colormap parent's colormap
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ depth Depth int parent's depth
+ destroyCallback Callback XtCallbackList NULL
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension length or thickness
+ insensitiveBorder Insensitive Pixmap GreyPixmap
+ length Length Dimension 1
+ mappedWhenManaged MappedWhenManaged Boolean True
+ minimumThumb MinimumThumb Dimension 7
+ orientation Orientation XtOrientation XtorientVertical
+ screen Screen Screen parent's screen
+ sensitive Sensitive Boolean True
+ shown Shown Float 0.0
+ thickness Thickness Dimension 14
+ thumb Thumb Bitmap GreyPixmap
+ topOfThumb TopOfThumb Float 0.0
+ translations Translations TranslationTable see source or doc
+ width Width Dimension thickness or length
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * Most things we need are in StringDefs.h
+ */
+
+#ifndef XtNincrement
+#define XtNincrement "increment"
+#endif
+
+#ifndef XtNpageIncrement
+#define XtNpageIncrement "pageIncrement"
+#endif
+
+#ifndef XtNrepeatDelay
+#define XtNrepeatDelay "repeatDelay"
+#endif
+
+#ifndef XtNshowArrows
+#define XtNshowArrows "showArrows"
+#endif
+
+#ifndef XtNminimumThumb
+#define XtNminimumThumb "minimumThumb"
+#endif
+
+#ifndef XtNtopOfThumb
+#define XtNtopOfThumb "topOfThumb"
+#endif
+
+#ifndef XtNshown
+#define XtNshown "shown"
+#endif
+
+#ifndef XtNincrementProc
+#define XtNincrementProc "incrementProc"
+#endif
+
+#ifndef XtNdecrementProc
+#define XtNdecrementProc "decrementProc"
+#endif
+
+#ifndef XtNvalueChangedProc
+#define XtNvalueChangedProc "valueChangedProc"
+#endif
+
+#ifndef XtNpageIncrementProc
+#define XtNpageIncrementProc "pageIncrementProc"
+#endif
+
+#ifndef XtNpageDecrementProc
+#define XtNpageDecrementProc "pageDecrementProc"
+#endif
+
+#ifndef XtNdragProc
+#define XtNdragProc "dragProc"
+#endif
+
+#ifndef XtNtoTopProc
+#define XtNtoTopProc "toTopProc"
+#endif
+
+#ifndef XtNtoBottomProc
+#define XtNtoBottomProc "toBottomProc"
+#endif
+
+#ifndef XtCShowArrows
+#define XtCShowArrows "ShowArrows"
+#endif
+
+#ifndef XtCIncrement
+#define XtCIncrement "Increment"
+#endif
+
+#ifndef XtCMinimumThumb
+#define XtCMinimumThumb "MinimumThumb"
+#endif
+
+#ifndef XtCRepeatDelay
+#define XtCRepeatDelay "RepeatDelay"
+#endif
+
+#ifndef XtCShown
+#define XtCShown "Shown"
+#endif
+
+#ifndef XtCTopOfThumb
+#define XtCTopOfThumb "TopOfThumb"
+#endif
+
+#ifndef XtNthumbColor
+#define XtNthumbColor "thumbColor"
+#endif
+
+#ifndef XtCThumbColor
+#define XtCThumbColor "ThumbColor"
+#endif
+
+#ifndef XtNstripeColor
+#define XtNstripeColor "stripeColor"
+#endif
+
+#ifndef XtCStripeColor
+#define XtCStripeColor "StripeColor"
+#endif
+
+
+enum XawScrollBarReasons{
+ XawSB_INCREMENT = Xraw_SCROLLBAR,
+ XawSB_DECREMENT,
+ XawSB_PAGE_INCREMENT,
+ XawSB_PAGE_DECREMENT,
+ XawSB_VALUE_CHANGED,
+ XawSB_TOP,
+ XawSB_BOTTOM,
+ XawSB_DRAG
+};
+
+typedef struct {
+ int reason;
+ XEvent *event;
+ float top;
+ float shown;
+ Dimension topLoc;
+ Dimension shownLength;
+ Dimension length;
+}XawScrollBarCallbackStruct;
+
+typedef struct _ScrollbarRec *ScrollbarWidget;
+typedef struct _ScrollbarClassRec *ScrollbarWidgetClass;
+
+extern WidgetClass scrollbarWidgetClass;
+
+extern void XawScrollbarSetThumb(
+#if NeedFunctionPrototypes
+ Widget /* scrollbar */,
+#if NeedWidePrototypes
+ /* float */ double /* top */,
+ /* float */ double /* shown */
+#else
+ float /* top */,
+ float /* shown */
+#endif
+#endif
+);
+
+#endif /* _Scrollbar_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h b/vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h
new file mode 100644
index 00000000..29a5da8f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h
@@ -0,0 +1,99 @@
+/*
+ * $XConsortium: ScrollbarP.h,v 1.2 90/04/11 17:33:53 jim Exp $
+ */
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _ScrollbarP_h
+#define _ScrollbarP_h
+
+#include <X11/Xraw/Scrollbar.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/Arrow.h>
+
+#define BAR(w) ((ScrollbarWidget)w)->scrollbar
+
+typedef struct {
+ /* public */
+ Pixel foreground; /* thumb foreground color */
+ XtOrientation orientation; /* horizontal or vertical */
+ float top; /* What percent is above the win's top */
+ float shown; /* What percent is shown in the win */
+ Dimension along; /* either height or width */
+ Dimension cross;
+ Dimension min_thumb; /* minium size for the thumb. */
+ Boolean showArrows;
+ Dimension increment;
+ Dimension page_increment;
+ int delay;
+ XtCallbackList incrementProc;
+ XtCallbackList decrementProc;
+ XtCallbackList pageIncrementProc;
+ XtCallbackList pageDecrementProc;
+ XtCallbackList valueChangedProc;
+ XtCallbackList dragProc;
+ XtCallbackList toTopProc;
+ XtCallbackList toBottomProc;
+
+
+ XtCallbackList scrollProc; /* proportional scroll */
+ XtCallbackList thumbProc; /* jump (to position) scroll */
+ XtCallbackList jumpProc; /* same as thumbProc but pass data by ref */
+
+ /* private */
+
+ int scrolling; /* a scrollbar status: FREE|BESY|MOVE */
+ GC gc; /* a (shared) gc */
+ int topLoc; /* Pixel that corresponds to top */
+ Dimension shownLength;/* Num pixels corresponding to shown */
+
+ Dimension direction;
+
+ int margin;
+ int newLoc;
+ int shift;
+ XtIntervalId timer;
+ XawDrawArrowStruct top_arrow;
+ XawDrawArrowStruct bot_arrow;
+} ScrollbarPart;
+
+typedef struct _ScrollbarRec {
+ CorePart core;
+ SimplePart simple;
+ ScrollbarPart scrollbar;
+} ScrollbarRec;
+
+typedef struct {int empty;} ScrollbarClassPart;
+
+typedef struct _ScrollbarClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ ScrollbarClassPart scrollbar_class;
+} ScrollbarClassRec;
+
+extern ScrollbarClassRec scrollbarClassRec;
+
+#endif /* _ScrollbarP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h b/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h
new file mode 100644
index 00000000..65acf55d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h
@@ -0,0 +1,104 @@
+/***********************************************************************
+
+ ScrolledTable widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _XawScrolledTable_H_
+#define _XawScrolledTable_H_
+
+#include <X11/Xraw/Container.h>
+#include <X11/Xraw/Viewport.h>
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resources #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNdistance
+#define XtNdistance "distance"
+#endif
+
+#ifndef XtNsignWidget
+#define XtNsignWidget "signWidget"
+#endif
+
+#ifndef XtNscrollbarWidth
+#define XtNscrollbarWidth "scrollbarWidth"
+#endif
+
+#ifndef XtNframeWidth
+#define XtNframeWidth "frameWidth"
+#endif
+
+#ifndef XtNrowWidget
+#define XtNrowWidget "rowWidget"
+#endif
+
+#ifndef XtNstuffWidget
+#define XtNstuffWidget "stuffWidget"
+#endif
+
+#ifndef XtNcolumnWidget
+#define XtNcolumnWidget "columnWidget"
+#endif
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Classes #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtCColumnWidget
+#define XtCColumnWidget "ColumnWidget"
+#endif
+
+#ifndef XtCScrollbarWidth
+#define XtCScrollbarWidth "ScrollbarWidth"
+#endif
+
+#ifndef XtCSignWidget
+#define XtCSignWidget "SignWidget"
+#endif
+
+#ifndef XtCStuffWidget
+#define XtCStuffWidget "StuffWidget"
+#endif
+
+#ifndef XtCDistance
+#define XtCDistance "Distance"
+#endif
+
+#ifndef XtCFrameWidth
+#define XtCFrameWidth "FrameWidth"
+#endif
+
+#ifndef XtCRowWidget
+#define XtCRowWidget "RowWidget"
+#endif
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass scrolledTableWidgetClass;
+
+typedef struct _ScrolledTableClassRec *XrawScrolledTableWidgetClass;
+typedef struct _ScrolledTableRec *XrawScrolledTableWidget;
+
+#endif /* _XawScrolledTable_H_ */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h b/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h
new file mode 100644
index 00000000..9de6947b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h
@@ -0,0 +1,64 @@
+#ifndef _XawScrolledTableP_H_
+#define _XawScrolledTableP_H_
+
+#include <X11/Xraw/ScrolledTable.h>
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/FrameP.h>
+
+typedef struct {
+ int unused; /* class variables */
+} ScrolledTableClassPart;
+
+typedef struct _ScrolledTableClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ ScrolledTableClassPart scrolled_table_class;
+} ScrolledTableClassRec;
+
+typedef struct _ScrolledTablePart{
+
+ /* resources */
+
+ Dimension distance;
+ Dimension scrollbar_width;
+ Dimension frame_width;
+ XawFrameType frame_type;
+ Boolean allow_vertical_scrollbar;
+ Boolean allow_horizontal_scrollbar;
+ Boolean force_scrollbar;
+
+ Widget sign_widget;
+ Widget row_widget;
+ Widget column_widget;
+ Widget stuff_widget;
+
+ /* private state */
+
+ Widget row_clip;
+ Widget column_clip;
+ Widget stuff_clip;
+
+ Position stuff_x;
+ Position stuff_y;
+ Dimension stuff_width;
+ Dimension stuff_height;
+
+ Widget v_scroll;
+ Widget h_scroll;
+
+} ScrolledTablePart;
+
+typedef struct _ScrolledTableRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ ScrolledTablePart scrolled_table;
+} ScrolledTableRec;
+
+extern ScrolledTableClassRec scrolledTableClassRec;
+
+#endif /* _XawScrolledTableP_H_ */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Separator.h b/vendor/x11iraf/obm/ObmW/Xraw/Separator.h
new file mode 100644
index 00000000..6d5ad87f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Separator.h
@@ -0,0 +1,99 @@
+#ifndef _XawSeparator_h
+#define _XawSeparator_h
+
+/***********************************************************************
+ *
+ * Separator Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Simple.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback XtCallbackList NULL
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+
+
+typedef enum {
+ XawSINGLE_LINE = Xraw_SEPARATOR,
+ XawDOUBLE_LINE,
+ XawSHADOW_ETCHED_IN,
+ XawSHADOW_ETCHED_OUT
+} XawSeparatorType;
+
+
+#define XawSingle_Line "singleline"
+#define XawDouble_Line "doubleline"
+#define XawShadow_Etched_In "shadowetchedin"
+#define XawShadow_Etched_Out "shadowetchedout"
+
+
+
+#ifndef XtNmargin
+#define XtNmargin "margin"
+#endif
+
+#ifndef XtCMargin
+#define XtCMargin "Margin"
+#endif
+
+#ifndef XtNseparatorType
+#define XtNseparatorType "separatorType"
+#endif
+
+#ifndef XtCSeparatorType
+#define XtCSeparatorType "SeparatorType"
+#endif
+
+#ifndef XtRSeparatorType
+#define XtRSeparatorType "SeparatorType"
+#endif
+
+#define XawTextEncoding8bit 0
+#define XawTextEncodingChar2b 1
+
+#define XtNleftBitmap "leftBitmap"
+#define XtCLeftBitmap "LeftBitmap"
+#define XtNencoding "encoding"
+#define XtCEncoding "Encoding"
+
+#ifndef _XtStringDefs_h_
+#define XtNbitmap "bitmap"
+#define XtNforeground "foreground"
+#define XtNseparator "separator"
+#define XtNfont "font"
+#define XtNinternalWidth "internalWidth"
+#define XtNinternalHeight "internalHeight"
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#define XtCBitmap "Bitmap"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass separatorWidgetClass;
+
+typedef struct _SeparatorClassRec *SeparatorWidgetClass;
+typedef struct _SeparatorRec *SeparatorWidget;
+
+#endif /* _XawSeparator_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h b/vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h
new file mode 100644
index 00000000..75250d38
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h
@@ -0,0 +1,60 @@
+/*
+ * SeparatorP.h - Private definitions for Separator widget
+ *
+ */
+
+#ifndef _XawSeparatorP_h
+#define _XawSeparatorP_h
+
+/***********************************************************************
+ *
+ * Separator Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/Separator.h>
+
+
+/* New fields for the Separator widget class record */
+
+typedef struct {int foo;} SeparatorClassPart;
+
+/* Full class record declaration */
+typedef struct _SeparatorClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ SeparatorClassPart separator_class;
+} SeparatorClassRec;
+
+extern SeparatorClassRec separatorClassRec;
+
+/* New fields for the Separator widget record */
+
+typedef struct {
+
+ /* Public Resources */
+ XtOrientation orientation;
+ Dimension margin;
+ XawSeparatorType separatorType;
+
+ /* Private part */
+ GC gc;
+
+} SeparatorPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SeparatorRec {
+ CorePart core;
+ SimplePart simple;
+ SeparatorPart separator;
+} SeparatorRec;
+
+#endif /* _XawSeparatorP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Simple.h b/vendor/x11iraf/obm/ObmW/Xraw/Simple.h
new file mode 100644
index 00000000..bbe11cda
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Simple.h
@@ -0,0 +1,96 @@
+/*
+ * $XConsortium: Simple.h,v 1.9 89/07/21 01:44:53 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _Simple_h
+#define _Simple_h
+
+/****************************************************************
+ *
+ * Simple widgets
+ *
+ ****************************************************************/
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ insensitiveBorder Insensitive Pixmap Gray
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+ shadowWidth ShadowWidth Dimension 2
+ topShadowPixel TopShadowPixel Pixel dynamic
+ bottomShadowPixel BottomShadowPixel Pixel dynamic
+ topShadowContrast TopShadowContrast Int 20
+ bottomShadowContrast BottomShadowContrast Int 40
+ userData UserData XtPointer NULL
+ beNiceToColormap BeNiceToColormap Boolean False
+
+*/
+
+#define XtNcursor "cursor"
+#define XtNinsensitiveBorder "insensitiveBorder"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+
+#define XtCInsensitive "Insensitive"
+
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNhighlightPixmap "highlightPixmap"
+#define XtCHighlightPixmap "HighlightPixmap"
+#define XtNhighlightThickness "highlightThickness"
+#define XtCHighlightThickness "HighlightThickness"
+
+
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNhighlightPixel "highlightPixel"
+#define XtCHighlightPixel "HighlightPixel"
+
+typedef struct _SimpleClassRec *SimpleWidgetClass;
+typedef struct _SimpleRec *SimpleWidget;
+
+extern WidgetClass simpleWidgetClass;
+
+#endif /* _Simple_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h b/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h
new file mode 100644
index 00000000..32f5ccf9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h
@@ -0,0 +1,113 @@
+/*
+ * $XConsortium: SimpleMenP.h,v 1.12 89/12/11 15:01:39 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * SimpleMenuP.h - Private Header file for SimpleMenu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SimpleMenuP_h
+#define _SimpleMenuP_h
+
+#include <X11/ShellP.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleMenu.h>
+#include <X11/Xraw/SmeP.h>
+
+#define SMW(w) ((SimpleMenuWidget)w)->simple_menu
+
+typedef struct {
+ XtPointer extension; /* For future needs. */
+} SimpleMenuClassPart;
+
+typedef struct _SimpleMenuClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ SimpleMenuClassPart simpleMenu_class;
+} SimpleMenuClassRec;
+
+extern SimpleMenuClassRec simpleMenuClassRec;
+
+typedef struct _SimpleMenuPart {
+ /* resources */
+ Dimension shadow_thickness;
+ Dimension bsb_shadow_thickness;
+
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+
+ GC top_shadow_GC;
+ GC bottom_shadow_GC;
+
+ XawFrameType frame_type;
+
+ XtPointer user_data;
+
+ /* resources */
+
+ String label_string; /* The string for the label or NULL. */
+ SmeObject label; /* If label_string is non-NULL then this is
+ the label widget. */
+ WidgetClass label_class; /* Widget Class of the menu label object. */
+
+ Dimension top_margin; /* Top and bottom margins. */
+ Dimension bottom_margin;
+ Dimension row_height; /* height of each row (menu entry) */
+
+ Cursor cursor; /* The menu's cursor. */
+ SmeObject popup_entry; /* The entry to position the cursor on for
+ when using XawPositionSimpleMenu. */
+ Boolean menu_on_screen; /* Force the menus to be fully on the screen.*/
+ int backing_store; /* What type of backing store to use. */
+
+ /* private state */
+
+ Boolean recursive_set_values; /* contain a possible infinite loop. */
+
+ Boolean menu_width; /* If true then force width to remain
+ core.width */
+ Boolean menu_height; /* Just like menu_width, but for height. */
+
+ SmeObject entry_set; /* The entry that is currently set or
+ highlighted. */
+} SimpleMenuPart;
+
+typedef struct _SimpleMenuRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ SimpleMenuPart simple_menu;
+} SimpleMenuRec, *SimpleMenu;
+
+#endif /* _SimpleMenuP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h b/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h
new file mode 100644
index 00000000..752be892
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h
@@ -0,0 +1,169 @@
+/*
+ * $XConsortium: SimpleMenu.h,v 1.17 89/12/11 15:01:55 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris D. Peterson, MIT X Consortium
+ */
+
+/*
+ * SimpleMenu.h - Public Header file for SimpleMenu widget.
+ *
+ * This is the public header file for the Athena SimpleMenu widget.
+ * It is intended to provide one pane pulldown and popup menus within
+ * the framework of the X Toolkit. As the name implies it is a first and
+ * by no means complete implementation of menu code. It does not attempt to
+ * fill the needs of all applications, but does allow a resource oriented
+ * interface to menus.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SimpleMenu_h
+#define _SimpleMenu_h
+
+#include <X11/Shell.h>
+#include <X11/Xmu/Converters.h>
+
+/****************************************************************
+ *
+ * SimpleMenu widget
+ *
+ ****************************************************************/
+
+/* SimpleMenu Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ backgroundPixmap BackgroundPixmap Pixmap None
+ borderColor BorderColor Pixel XtDefaultForeground
+ borderPixmap BorderPixmap Pixmap None
+ borderWidth BorderWidth Dimension 1
+ bottomMargin VerticalMargins Dimension VerticalSpace
+ columnWidth ColumnWidth Dimension Width of widest text
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ label Label String NULL (No label)
+ labelClass LabelClass Pointer smeBSBObjectClass
+ mappedWhenManaged MappedWhenManaged Boolean True
+ rowHeight RowHeight Dimension Height of Font
+ sensitive Sensitive Boolean True
+ topMargin VerticalMargins Dimension VerticalSpace
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+typedef struct _SimpleMenuClassRec* SimpleMenuWidgetClass;
+typedef struct _SimpleMenuRec* SimpleMenuWidget;
+
+extern WidgetClass simpleMenuWidgetClass;
+
+#define XtNcursor "cursor"
+#define XtNbottomMargin "bottomMargin"
+#define XtNcolumnWidth "columnWidth"
+#define XtNlabelClass "labelClass"
+#define XtNmenuOnScreen "menuOnScreen"
+#define XtNpopupOnEntry "popupOnEntry"
+#define XtNrowHeight "rowHeight"
+#define XtNtopMargin "topMargin"
+
+#define XtCColumnWidth "ColumnWidth"
+#define XtCLabelClass "LabelClass"
+#define XtCMenuOnScreen "MenuOnScreen"
+#define XtCPopupOnEntry "PopupOnEntry"
+#define XtCRowHeight "RowHeight"
+#define XtCVerticalMargins "VerticalMargins"
+
+/* New fields */
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNbsbShadowWidth "bsbShadowWidth"
+#define XtCBsbShadowWidth "BsbShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+#define XtNframeType "frameType"
+#define XtCFrameType "FrameType"
+#define XtRFrameType "FrameType"
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawSimpleMenuAddGlobalActions
+ * Description: adds the global actions to the simple menu widget.
+ * Arguments: app_con - the appcontext.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuAddGlobalActions(/* app_con */);
+/*
+XtAppContext app_con;
+*/
+
+/* Function Name: XawSimpleMenuGetActiveEntry
+ * Description: Gets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: the currently set entry or NULL if none is set.
+ */
+
+Widget
+XawSimpleMenuGetActiveEntry( /* w */);
+/*
+Widget w;
+*/
+
+/* Function Name: XawSimpleMenuClearActiveEntry
+ * Description: Unsets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuClearActiveEntry(/* w */);
+/*
+Widget w;
+*/
+
+#endif /* _SimpleMenu_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h b/vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h
new file mode 100644
index 00000000..f4044709
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h
@@ -0,0 +1,62 @@
+#ifndef _SimpleP_h
+#define _SimpleP_h
+
+#include <X11/IntrinsicP.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Simple.h>
+
+#define SIMPLE(w) ((SimpleWidget) w)->simple
+
+typedef Boolean (*XawDisplayRectProc) Xraw_PROTO((Widget, XRectangle * ));
+typedef Boolean (*XawChangeSensitive) Xraw_PROTO((Widget));
+
+typedef struct {
+ XawChangeSensitive change_sensitive;
+ XawDisplayRectProc display_rect;
+ caddr_t extension;
+} SimpleClassPart;
+
+typedef struct _SimpleClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+} SimpleClassRec;
+
+extern SimpleClassRec simpleClassRec;
+
+typedef struct {
+ /* resources */
+ Cursor cursor;
+ Pixmap insensitive_border;
+ Pixel foreground;
+
+ Dimension shadow_thickness;
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+ Pixel highlight_color;
+ Pixmap highlight_pixmap;
+ Dimension highlight_thickness;
+
+ caddr_t user_data;
+
+ /* private state */
+ GC top_shadow_GC;
+ GC bottom_shadow_GC;
+ GC highlight_GC;
+} SimplePart;
+
+typedef struct _SimpleRec {
+ CorePart core;
+ SimplePart simple;
+} SimpleRec;
+
+#define SIMPLE_MARGIN(w) (((SimpleWidget)w)->simple.highlight_thickness + \
+ ((SimpleWidget)w)->simple.shadow_thickness)
+
+#define XtSimpleClass(w) ((SimpleWidgetClass)XtClass(w))
+#define XtInheritDisplayRectProc ((Boolean (*)())_XtInherit)
+#define XtInheritChangeSensitive ((Boolean (*)())_XtInherit)
+
+#endif /* _SimpleP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Sme.h b/vendor/x11iraf/obm/ObmW/Xraw/Sme.h
new file mode 100644
index 00000000..23d567cd
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Sme.h
@@ -0,0 +1,66 @@
+/*
+ * $XConsortium: Sme.h,v 1.4 89/12/11 15:20:09 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Sme.h - Public Header file for Sme object.
+ *
+ * This is the public header file for the Athena Sme object.
+ * It is intended to be used with the simple menu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _Sme_h
+#define _Sme_h
+
+#include <X11/RectObj.h>
+
+/****************************************************************
+ *
+ * Sme Object
+ *
+ ****************************************************************/
+
+/*
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ callback Callback Pointer NULL
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+typedef struct _SmeClassRec* SmeObjectClass;
+typedef struct _SmeRec* SmeObject;
+
+extern WidgetClass smeObjectClass;
+
+#endif /* _Sme_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h b/vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h
new file mode 100644
index 00000000..6e72b38f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h
@@ -0,0 +1,109 @@
+/*
+ * $XConsortium: SmeBSB.h,v 1.5 89/12/11 15:20:14 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * SmeBSB.h - Public Header file for SmeBSB object.
+ *
+ * This is the public header file for the Athena BSB Sme object.
+ * It is intended to be used with the simple menu widget. This object
+ * provides bitmap - string - bitmap style entries.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SmeBSB_h
+#define _SmeBSB_h
+
+#include <X11/Xmu/Converters.h>
+
+#include <X11/Xraw/Sme.h>
+
+/****************************************************************
+ *
+ * SmeBSB object
+ *
+ ****************************************************************/
+
+/* BSB Menu Entry Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ callback Callback Callback NULL
+ destroyCallback Callback Pointer NULL
+ font Font XFontStruct * XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension 0
+ label Label String Name of entry
+ leftBitmap LeftBitmap Pixmap None
+ leftMargin HorizontalMargins Dimension 4
+ rightBitmap RightBitmap Pixmap None
+ rightMargin HorizontalMargins Dimension 4
+ sensitive Sensitive Boolean True
+ vertSpace VertSpace int 25
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+typedef struct _SmeBSBClassRec *SmeBSBObjectClass;
+typedef struct _SmeBSBRec *SmeBSBObject;
+
+extern WidgetClass smeBSBObjectClass;
+
+#ifndef XtNmfore
+#define XtNmfore "mfore"
+#endif
+
+#ifndef XtNstate
+#define XtNstate "state"
+#endif
+
+#ifndef XtCState
+#define XtCState "State"
+#endif
+
+#ifndef XtNswitched
+#define XtNswitched "switched"
+#endif
+
+#ifndef XtCSwitched
+#define XtCSwitched "Switched"
+#endif
+
+#define XtNleftBitmap "leftBitmap"
+#define XtNleftMargin "leftMargin"
+#define XtNrightBitmap "rightBitmap"
+#define XtNrightMargin "rightMargin"
+#define XtNvertSpace "vertSpace"
+
+#define XtCLeftBitmap "LeftBitmap"
+#define XtCHorizontalMargins "HorizontalMargins"
+#define XtCRightBitmap "RightBitmap"
+#define XtCVertSpace "VertSpace"
+
+#endif /* _SmeBSB_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h b/vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h
new file mode 100644
index 00000000..63427ff3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h
@@ -0,0 +1,121 @@
+/*
+ * $XConsortium: SmeBSBP.h,v 1.6 89/12/11 15:20:15 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris D. Peterson, MIT X Consortium
+ */
+
+/*
+ * SmeP.h - Private definitions for Sme object
+ *
+ */
+
+#ifndef _XawSmeBSBP_h
+#define _XawSmeBSBP_h
+
+/***********************************************************************
+ *
+ * Sme Object Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/SmeP.h>
+#include <X11/Xraw/SmeBSB.h>
+
+/************************************************************
+ *
+ * New fields for the Sme Object class record.
+ *
+ ************************************************************/
+
+typedef struct _SmeBSBClassPart {
+ XtPointer extension;
+} SmeBSBClassPart;
+
+/* Full class record declaration */
+typedef struct _SmeBSBClassRec {
+ RectObjClassPart rect_class;
+ SmeClassPart sme_class;
+ SmeBSBClassPart sme_bsb_class;
+} SmeBSBClassRec;
+
+extern SmeBSBClassRec smeBSBClassRec;
+
+/* New fields for the Sme Object record */
+typedef struct {
+ /* resources */
+ String label; /* The entry label. */
+ int vert_space; /* Extra vert space to leave, */
+ /* as a percentage of the font height */
+ /* of the label. */
+ Pixmap left_bitmap;
+ Pixmap right_bitmap; /* Bitmaps to show. */
+
+ Dimension left_margin;
+ Dimension right_margin; /* Left and right margins. */
+
+ Pixel foreground; /* Foreground color. */
+ Pixel mfore;
+
+ XFontStruct * font; /* The font to show label in. */
+ XtJustify justify; /* Justification for the label. */
+
+ Boolean state;
+ Boolean switched;
+
+ XtPointer user_data;
+
+/* private resources. */
+
+ Boolean set_values_area_cleared; /* Remember if we need to unhighlight. */
+ GC norm_gc; /* noral color gc. */
+ GC rev_gc; /* reverse color gc. */
+ GC norm_gray_gc; /* Normal color (grayed out) gc. */
+ GC invert_gc; /* gc for flipping colors. */
+ GC mfore_gc;
+
+ Dimension left_bitmap_width; /* size of each bitmap. */
+ Dimension left_bitmap_height;
+ Dimension right_bitmap_width;
+ Dimension right_bitmap_height;
+
+} SmeBSBPart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SmeBSBRec {
+ ObjectPart object;
+ RectObjPart rectangle;
+ SmePart sme;
+ SmeBSBPart sme_bsb;
+} SmeBSBRec;
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+#endif /* _XawSmeBSBP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h b/vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h
new file mode 100644
index 00000000..c8bb834f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h
@@ -0,0 +1,75 @@
+/*
+ * $XConsortium: SmeLine.h,v 1.3 89/12/11 15:20:19 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * SmeLine.h - Public Header file for SmeLine object.
+ *
+ * This is the public header file for the Athena SmeLine object.
+ * It is intended to be used with the simple menu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SmeLine_h
+#define _SmeLine_h
+
+#include <X11/Xraw/Sme.h>
+#include <X11/Xmu/Converters.h>
+
+/****************************************************************
+ *
+ * SmeLine Object
+ *
+ ****************************************************************/
+
+/* Menu Entry Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ callback Callback Pointer NULL
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define XtCLineWidth "LineWidth"
+#define XtCStipple "Stipple"
+
+#define XtNlineWidth "lineWidth"
+#define XtNstipple "stipple"
+
+typedef struct _SmeLineClassRec* SmeLineObjectClass;
+typedef struct _SmeLineRec* SmeLineObject;
+
+extern WidgetClass smeLineObjectClass;
+
+#endif /* _SmeLine_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h b/vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h
new file mode 100644
index 00000000..8cb9412a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h
@@ -0,0 +1,93 @@
+/*
+ * $XConsortium: SmeLineP.h,v 1.3 89/12/11 15:20:20 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris D. Peterson, MIT X Consortium
+ */
+
+/*
+ * SmeLineP.h - Private definitions for SmeLine widget
+ *
+ */
+
+#ifndef _XawSmeLineP_h
+#define _XawSmeLineP_h
+
+/***********************************************************************
+ *
+ * SmeLine Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/SmeP.h>
+#include <X11/Xraw/SmeLine.h>
+
+/************************************************************
+ *
+ * New fields for the SmeLine widget class record.
+ *
+ ************************************************************/
+
+typedef struct _SmeLineClassPart {
+ XtPointer extension;
+} SmeLineClassPart;
+
+/* Full class record declaration */
+typedef struct _SmeLineClassRec {
+ RectObjClassPart rect_class;
+ SmeClassPart sme_class;
+ SmeLineClassPart sme_line_class;
+} SmeLineClassRec;
+
+extern SmeLineClassRec smeLineClassRec;
+
+/* New fields for the SmeLine widget record */
+typedef struct {
+ /* resources */
+ Pixel foreground; /* Foreground color. */
+ Pixmap stipple; /* Line Stipple. */
+ Dimension line_width; /* Width of the line. */
+
+ /* private data. */
+
+ GC gc; /* Graphics context for drawing line. */
+} SmeLinePart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SmeLineRec {
+ ObjectPart object;
+ RectObjPart rectangle;
+ SmePart sme;
+ SmeLinePart sme_line;
+} SmeLineRec;
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+#endif /* _XawSmeLineP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/SmeP.h b/vendor/x11iraf/obm/ObmW/Xraw/SmeP.h
new file mode 100644
index 00000000..92726393
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/SmeP.h
@@ -0,0 +1,102 @@
+/*
+ * $XConsortium: SmeP.h,v 1.4 89/12/11 15:20:22 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * SmeP.h - Private Header file for Sme object.
+ *
+ * This is the private header file for the Athena Sme object.
+ * This object is intended to be used with the simple menu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _XawSmeP_h
+#define _XawSmeP_h
+
+/***********************************************************************
+ *
+ * Sme Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/RectObjP.h>
+#include <X11/Xraw/Sme.h>
+
+/************************************************************
+ *
+ * New fields for the Sme widget class record.
+ *
+ ************************************************************/
+
+typedef struct _SmeClassPart {
+ XtWidgetProc highlight;
+ XtWidgetProc unhighlight;
+ XtWidgetProc notify;
+ XtPointer extension;
+} SmeClassPart;
+
+/* Full class record declaration */
+typedef struct _SmeClassRec {
+ RectObjClassPart rect_class;
+ SmeClassPart sme_class;
+} SmeClassRec;
+
+extern SmeClassRec smeClassRec;
+
+/* New fields for the Sme widget record */
+typedef struct {
+ /* resources */
+ XtCallbackList callbacks; /* The callback list */
+ XtPointer user_data;
+
+} SmePart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SmeRec {
+ ObjectPart object;
+ RectObjPart rectangle;
+ SmePart sme;
+} SmeRec;
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+typedef void (*_XawEntryVoidFunc)();
+
+#define XtInheritHighlight ((_XawEntryVoidFunc) _XtInherit)
+#define XtInheritUnhighlight XtInheritHighlight
+#define XtInheritNotify XtInheritHighlight
+
+#endif /* _XawSmeP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h b/vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h
new file mode 100644
index 00000000..02670325
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h
@@ -0,0 +1,83 @@
+/*
+* $XConsortium: StripCharP.h,v 1.4 90/10/22 14:38:15 converse Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawStripChartP_h
+#define _XawStripChartP_h
+
+#include <X11/Xraw/StripChart.h>
+#include <X11/Xraw/SimpleP.h>
+
+#define NO_GCS 0
+#define FOREGROUND 1 << 0
+#define HIGHLIGHT 1 << 1
+#define ALL_GCS (FOREGROUND | HIGHLIGHT)
+
+/* New fields for the stripChart widget instance record */
+
+typedef struct {
+ Pixel fgpixel; /* color index for graph */
+ Pixel hipixel; /* color index for lines */
+ GC fgGC; /* graphics context for fgpixel */
+ GC hiGC; /* graphics context for hipixel */
+
+ /* start of graph stuff */
+
+ int update; /* update frequence */
+ int scale; /* scale factor */
+ int min_scale; /* smallest scale factor */
+ int interval; /* data point interval */
+ XPoint * points ; /* Poly point for repairing graph lines. */
+ double max_value; /* Max Value in window */
+ double valuedata[2048];/* record of data points */
+ XtIntervalId interval_id;
+ XtCallbackList get_value; /* proc to call to fetch load pt */
+ int jump_val; /* Amount to jump on each scroll. */
+} StripChartPart;
+
+/* Full instance record declaration */
+typedef struct _StripChartRec {
+ CorePart core;
+ SimplePart simple;
+ StripChartPart strip_chart;
+} StripChartRec;
+
+/* New fields for the StripChart widget class record */
+typedef struct {int dummy;} StripChartClassPart;
+
+/* Full class record declaration. */
+typedef struct _StripChartClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ StripChartClassPart strip_chart_class;
+} StripChartClassRec;
+
+/* Class pointer. */
+extern StripChartClassRec stripChartClassRec;
+
+#endif /* _XawStripChartP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/StripChart.h b/vendor/x11iraf/obm/ObmW/Xraw/StripChart.h
new file mode 100644
index 00000000..bb607269
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/StripChart.h
@@ -0,0 +1,94 @@
+/* $XConsortium: StripChart.h,v 1.5 91/07/26 22:50:35 converse Exp $ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawStripChart_h
+#define _XawStripChart_h
+
+/***********************************************************************
+ *
+ * StripChart Widget
+ *
+ ***********************************************************************/
+
+/* StripChart resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ accelerators Accelerators AcceleratorTable NULL
+ ancestorSensitive AncestorSensitive Boolean True
+ background Background Pixel XtDefaultBackground
+ backgroundPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ borderColor BorderColor Pixel XtDefaultForeground
+ borderPixmap Pixmap Pixmap XtUnspecifiedPixmap
+ borderWidth BorderWidth Dimension 1
+ colormap Colormap Colormap parent's colormap
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ depth Depth int parent's depth
+ destroyCallback Callback XtCallbackList NULL
+ foreground Foreground Pixel XtDefaultForeground
+ getValue Callback XtCallbackList NULL
+ height Height Dimension 120
+ highlight Foreground Pixel XtDefaultForeground
+ insensitiveBorder Insensitive Pixmap GreyPixmap
+ jumpScroll JumpScroll int 1/2 width
+ mappedWhenManaged MappedWhenManaged Boolean True
+ minScale Scale int 1
+ pointerColor Foreground Pixel XtDefaultForeground
+ pointerColorBackground Background Pixel XtDefaultBackground
+ screen Screen Screen parent's screen
+ sensitive Sensitive Boolean True
+ translations Translations TranslationTable NULL
+ update Interval int 10 (seconds)
+ width Width Dimension 120
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+#define DEFAULT_JUMP -1
+
+#ifndef _XtStringDefs_h_
+#define XtNhighlight "highlight"
+#define XtNupdate "update"
+#endif
+
+#define XtCJumpScroll "JumpScroll"
+#define XtCScale "Scale"
+
+#define XtNgetValue "getValue"
+#define XtNjumpScroll "jumpScroll"
+#define XtNminScale "minScale"
+#define XtNscale "scale"
+#define XtNvmunix "vmunix"
+
+typedef struct _StripChartRec *StripChartWidget;
+typedef struct _StripChartClassRec *StripChartWidgetClass;
+
+extern WidgetClass stripChartWidgetClass;
+
+#endif /* _XawStripChart_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Table.h b/vendor/x11iraf/obm/ObmW/Xraw/Table.h
new file mode 100644
index 00000000..4c7ab5cf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Table.h
@@ -0,0 +1,539 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _XawTable_h
+#define _XawTable_h
+
+#include <X11/Xmu/Converters.h>
+
+#include <X11/Xraw/Simple.h>
+#include <X11/Xraw/XawInit.h>
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resources #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XawTextEncoding8bit
+#define XawTextEncoding8bit 0
+#endif
+#ifndef XawTextEncodingChar2b
+#define XawTextEncodingChar2b 1
+#endif
+
+#ifndef XtNliteral
+#define XtNliteral "literal"
+#endif
+
+#ifndef XtNrows
+#define XtNrows "rows"
+#endif
+
+#ifndef XtNcolumns
+#define XtNcolumns "columns"
+#endif
+
+
+#ifndef XtNmaskNumber
+#define XtNmaskNumber "maskNumber"
+#endif
+
+#ifndef XtNrowOriented
+#define XtNrowOriented "rowOriented"
+#endif
+
+#ifndef XtNeditForeground
+#define XtNeditForeground "editForeground"
+#endif
+
+#ifndef XtNeditBackground
+#define XtNeditBackground "editBackground"
+#endif
+
+#ifndef XtNcolumnForeground
+#define XtNcolumnForeground "columnForeground"
+#endif
+
+#ifndef XtNrowForeground
+#define XtNrowForeground "rowForeground"
+#endif
+
+#ifndef XtNvetricalScroll
+#define XtNvetricalScroll "vetricalScroll"
+#endif
+
+#ifndef XtNhorizontalScroll
+#define XtNhorizontalScroll "horizontalScroll"
+#endif
+
+#ifndef XtNcolumnsWidth
+#define XtNcolumnsWidth "columnsWidth"
+#endif
+
+#ifndef XtNrowHeight
+#define XtNrowHeight "rowHeight"
+#endif
+
+#ifndef XtNdefaultWidth
+#define XtNdefaultWidth "defaultWidth"
+#endif
+
+#ifndef XtNeditable
+#define XtNeditable "editable"
+#endif
+
+#ifndef XtNliteralWidth
+#define XtNliteralWidth "literalWidth"
+#endif
+
+#ifndef XtNtableMargin
+#define XtNtableMargin "tableMargin"
+#endif
+
+#ifndef XtNrowMargin
+#define XtNrowMargin "rowMargin"
+#endif
+
+#ifndef XtNcolumnMargin
+#define XtNcolumnMargin "columnMargin"
+#endif
+
+#ifndef XtNlabelShadowWidth
+#define XtNlabelShadowWidth "labelShadowWidth"
+#endif
+
+#ifndef XtNencoding
+#define XtNencoding "encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Classes #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtCLiteral
+#define XtCLiteral "Literal"
+#endif
+
+#ifndef XtCColumns
+#define XtCColumns "Columns"
+#endif
+
+#ifndef XtCMaskNumber
+#define XtCMaskNumber "MaskNumber"
+#endif
+
+#ifndef XtCScroll
+#define XtCScroll "Scroll"
+#endif
+
+#ifndef XtCColumnsWidth
+#define XtCColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowHeight
+#define XtCRowHeight "RowHeight"
+#endif
+
+#ifndef XtCDefaultWidth
+#define XtCDefaultWidth "DefaultWidth"
+#endif
+
+#ifndef XtCEditable
+#define XtCEditable "Editable"
+#endif
+
+#ifndef XtCLiteralWidth
+#define XtCLiteralWidth "LiteralWidth"
+#endif
+
+#ifndef XtCRows
+#define XtCRows "Rows"
+#endif
+
+#ifndef XtCTableMargin
+#define XtCTableMargin "TableMargin"
+#endif
+
+#ifndef XtCRowMargin
+#define XtCRowMargin "RowMargin"
+#endif
+
+#ifndef XtCColumnMargin
+#define XtCColumnMargin "ColumnMargin"
+#endif
+
+#ifndef XtCLabelShadowWidth
+#define XtCLabelShadowWidth "LabelShadowWidth"
+#endif
+
+#ifndef XtCEncoding
+#define XtCEncoding "Encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Types #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtRColumnsWidth
+#define XtRColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowOriented
+#define XtCRowOriented "RowOriented"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Allowance Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNallowAddColumn
+#define XtNallowAddColumn "allowAddColumn"
+#endif
+
+#ifndef XtNallowAddRow
+#define XtNallowAddRow "allowAddRow"
+#endif
+
+#ifndef XtNallowDeleteColumn
+#define XtNallowDeleteColumn "allowDeleteColumn"
+#endif
+
+#ifndef XtNallowDeleteRow
+#define XtNallowDeleteRow "allowDeleteRow"
+#endif
+
+#ifndef XtNallowDeleteTable
+#define XtNallowDeleteTable "allowDeleteTable"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Information Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNaddColumn
+#define XtNaddColumn "addColumn"
+#endif
+
+#ifndef XtNaddRow
+#define XtNaddRow "addRow"
+#endif
+
+#ifndef XtNchangedCell
+#define XtNchangedCell "changedCell"
+#endif
+
+#ifndef XtNchangedColumnWidth
+#define XtNchangedColumnWidth "changedColumnWidth"
+#endif
+
+#ifndef XtNchangedRowHeight
+#define XtNchangedRowHeight "changedRowHeight"
+#endif
+
+#ifndef XtNcreateTable
+#define XtNcreateTable "createTable"
+#endif
+
+#ifndef XtNdeleteColumn
+#define XtNdeleteColumn "deleteColumn"
+#endif
+
+#ifndef XtNdeleteRow
+#define XtNdeleteRow "deleteRow"
+#endif
+
+#ifndef XtNdeleteTable
+#define XtNdeleteTable "deleteTable"
+#endif
+
+#ifndef XtNwhatCell
+#define XtNwhatCell "whatCell"
+#endif
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# XawTableCell & XawTableColumn #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct _XawTableCellRec *XawTableCell; /* opaque to outside */
+
+typedef struct _XawTableColumnRec *XawTableColumn; /* opaque to outside */
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routine and Direction Types #*/
+/*# #*/
+/*#########################################################################*/
+typedef Boolean (*XawTableProc) Xraw_PROTO((Widget,
+ int,
+ int,
+ XawTableCell,
+ XtPointer));
+enum XawTableBypassDirection{
+ XawTABLE_RIGHT_DOWN,
+ XawTABLE_DOWN_RIGHT
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Reasons #*/
+/*# #*/
+/*#########################################################################*/
+enum XawTableReasons{
+ XawTABLE_ALLOW_ADD_COLUMN = Xraw_TABLE,
+ XawTABLE_ALLOW_ADD_ROW,
+ XawTABLE_ALLOW_CREATE_TABLE,
+ XawTABLE_ALLOW_DELETE_COLUMN,
+ XawTABLE_ALLOW_DELETE_ROW,
+ XawTABLE_ALLOW_DELETE_TABLE,
+
+ XawTABLE_ADD_COLUMN,
+ XawTABLE_ADD_ROW,
+ XawTABLE_CHANGED_CELL,
+ XawTABLE_CHANGED_COLUMN_WIDTH,
+ XawTABLE_CHANGED_ROW_HEIGHT,
+ XawTABLE_CREATE_TABLE,
+ XawTABLE_DELETE_COLUMN,
+ XawTABLE_DELETE_ROW,
+ XawTABLE_DELETE_TABLE,
+ XawTABLE_WHAT_CELL
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Structure #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct {
+ int reason;
+ XEvent *event;
+ XawTableCell old_cell;
+ XawTableCell new_cell;
+ int row;
+ int column;
+ Boolean do_it;
+}XawTableCallbackStruct;
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Layout Control Routine #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableDoLayout Xraw_PROTO((Widget w,
+ Boolean do_layout));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Stuff Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetNewSize Xraw_PROTO((Widget w,
+ int rows,
+ int columns));
+
+extern void XawTableGetSize Xraw_PROTO((Widget w,
+ int *rows,
+ int *columns));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Row Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependRow Xraw_PROTO((Widget w));
+
+extern int XawTableAppendRow Xraw_PROTO((Widget w));
+
+extern int XawTableInsertRow Xraw_PROTO((Widget w, int row));
+
+extern int XawTableDeleteRow Xraw_PROTO((Widget w, int row));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableAppendColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableInsertColumn Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableDeleteColumn Xraw_PROTO((Widget w, int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Label Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern char *XawTableGetLabelByCell Xraw_PROTO((XawTableCell cell));
+
+extern char *XawTableGetLabelByPosition Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetLabel Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ char *label));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableWalk Xraw_PROTO((Widget w,
+ XawTableProc proc,
+ int b_row,
+ int e_row,
+ int b_column,
+ int e_column,
+ int direction,
+ int *row, int *column,
+ XtPointer client_data));
+
+extern Boolean XawTableSearchLabel Xraw_PROTO((Widget w,
+ char *name,
+ int *row,
+ int *column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Edit Cell Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableIsEditManaged Xraw_PROTO((Widget w));
+
+extern void XawTableGetEditPosition Xraw_PROTO((Widget w,
+ int *row,
+ int *column));
+
+extern void XawTableUnsetEdit Xraw_PROTO((Widget w));
+
+extern void XawTableSetEdit Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Colour Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetCellBackground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel background));
+
+extern int XawTableSetCellForeground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground));
+
+extern int XawTableSetCellDefaultColours Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground,
+ Pixel background));
+
+
+extern void XawTableGetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel *foreground,
+ Pixel *background));
+
+extern void XawTableGetCellColoursByCell Xraw_PROTO((Widget w,
+ XawTableCell cell,
+ Pixel *foreground,
+ Pixel *background));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Deta #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableSetColumnJustify Xraw_PROTO((Widget w,
+ int column,
+ XtJustify justify));
+
+extern XtJustify XawTableGetColumnJustify Xraw_PROTO((Widget w,
+ int column));
+
+extern void XawTableSetColumnWidth Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableGetColumnWidth Xraw_PROTO((Widget w,
+ int column));
+
+extern int XawTableGetColumnPixelWidth Xraw_PROTO((Widget w,
+ int column));
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass tableWidgetClass;
+
+typedef struct _TableClassRec *XawTableWidgetClass;
+typedef struct _TableRec *XawTableWidget;
+
+
+#endif /* _XawTable_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Table3d.h b/vendor/x11iraf/obm/ObmW/Xraw/Table3d.h
new file mode 100644
index 00000000..8d09dddf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Table3d.h
@@ -0,0 +1,145 @@
+#ifndef _3d_h_
+#define _3d_h_
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xraw/XawInit.h>
+
+typedef enum {
+ XawRAISED = Xraw_3d,
+ XawSUNKEN,
+ XawCHISELED,
+ XawLEDGED,
+ XawTACK
+} XawFrameType;
+
+#define TOP (1)
+#define BOTTOM (2)
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean ArmedColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+
+
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+
+extern Pixmap CreateShadowPixmap Xraw_PROTO((Widget ,
+ Pixel ,
+ int ));
+
+
+extern Boolean AllocShadowPixel Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Pixel * ));
+
+
+extern GC MakeGC Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Boolean ,
+ int ));
+
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern void XawDrawFrame Xraw_PROTO((Widget ,
+ Position ,
+ Position ,
+ Dimension ,
+ Dimension ,
+ XawFrameType ,
+ Dimension ,
+ GC ,
+ GC ));
+
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean ArmedColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern void DrawRhombus Xraw_PROTO((Widget ,
+ short ,
+ short ,
+ short ,
+ short ,
+ GC ,
+ GC ,
+ GC ,
+ Boolean ));
+
+extern Boolean FetchPixel Xraw_PROTO((Widget ,
+ String name ,
+ Pixel* ));
+
+#endif /* _3d_h_ */
+
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TableP.h b/vendor/x11iraf/obm/ObmW/Xraw/TableP.h
new file mode 100644
index 00000000..352fb278
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TableP.h
@@ -0,0 +1,166 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is desined for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advises, new components and patches of the existing programs.
+Commercial usage is also possible with participation of it's author.
+
+*************************************************************************/
+
+#ifndef _XawTableP_h
+#define _XawTableP_h
+
+/***********************************************************************
+ *
+ * Table Widget Private Data
+ *
+ ***********************************************************************/
+
+
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Table.h>
+#include <X11/Xraw/xraw_table.h>
+
+/* New fields for the Table widget class record */
+
+typedef struct {int foo;} TableClassPart;
+
+/* Full class record declaration */
+typedef struct _TableClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ TableClassPart table_class;
+} TableClassRec;
+
+#define MAX_ROWS 50
+
+typedef struct _NormalReverseGC {
+ int used;
+ Pixel fore;
+ Pixel back;
+ GC normal;
+ GC reverse;
+}NormalReverseGC;
+
+typedef struct _ShadowGC {
+ int used;
+ Pixel back;
+ GC top;
+ GC bottom;
+}ShadowGC;
+
+
+
+/* New fields for the Table widget record */
+typedef struct {
+ /* ------------------------ resources -----------------------*/
+ Pixel row_fore;
+ Pixel column_fore;
+ Pixel edit_fore;
+ Pixel edit_back;
+ Boolean row_oriented;
+ Boolean editable;
+ Boolean literal;
+
+ int mask_number;
+ int columns;
+ int rows;
+ Dimension tab_margin;
+ Dimension row_margin;
+ Dimension col_margin;
+ Dimension internal_width;
+ Dimension internal_height;
+ Dimension label_shadow_thickness;
+ unsigned char encoding;
+
+ /* Default Values */
+ Pixel foreground;
+ XtJustify justify;
+ XFontStruct *font;
+ int width;
+
+ /* Allowance CallbackList */
+ XtCallbackList allow_add_row;
+ XtCallbackList allow_add_column;
+ XtCallbackList allow_delete_column;
+ XtCallbackList allow_delete_row;
+ XtCallbackList allow_delete_table;
+
+ /* Information CallbackList */
+ XtCallbackList add_row;
+ XtCallbackList add_column;
+ XtCallbackList changed_cell;
+ XtCallbackList create_table;
+ XtCallbackList delete_column;
+ XtCallbackList delete_row;
+ XtCallbackList delete_table;
+ XtCallbackList what_cell;
+ XtCallbackList changed_column_width;
+ XtCallbackList changed_row_height;
+
+ Widget v_scroll;
+ Widget h_scroll;
+
+ int row_height;
+ int column_default_width;
+ int literal_width;
+
+ /* ------------------------ private state -----------------------*/
+
+ int no_refigure; /* no re-layout while > 0 */
+ int no_redraw; /* no re-draw while > 0 */
+ Boolean was_resized;
+
+
+ XawTableColumn column_data;
+
+ Dimension prefer_width;
+ Dimension prefer_height;
+ Widget edit;
+ int edit_row;
+ int edit_column;
+ XawTableCell cell_own;
+ XawTableCell table_stuff;
+
+ GC row_gc; /* Intrinsics sharedable GC */
+ GC column_gc; /* Intrinsics sharedable GC */
+
+ GC normal; /* Table sharedable GC */
+ GC reverse; /* Table sharedable GC */
+ GC top;
+ GC bottom;
+
+ GC edit_top;
+ GC edit_bottom;
+
+ NormalReverseGC *normal_hash_table;
+ ShadowGC *shadow_hash_table;
+ int mask_hash_table;
+
+ Atom selections[30];
+ int num_selections;
+} TablePart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TableRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ TablePart table;
+} TableRec;
+
+extern TableClassRec tableClassRec;
+
+#endif /* _XawTableP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h b/vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h
new file mode 100644
index 00000000..a8262f75
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h
@@ -0,0 +1,94 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _table_h_
+#define _table_h_
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xraw/Table.h>
+
+#if __STDC__ || defined(__cplusplus)
+#define F_PROTO(s) s
+#else
+#define F_PROTO(s) ()
+#endif
+
+typedef struct _XawTableNodeRec { /* Node of table grid */
+ struct _XawTableNodeRec *l;
+ struct _XawTableNodeRec *r;
+ struct _XawTableNodeRec *t;
+ struct _XawTableNodeRec *b;
+}XawTableNodeRec, *XawTableNode;
+
+
+extern XtPointer create_table F_PROTO((int rows,
+ int columns,
+ int node_size));
+
+extern Boolean row_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean row_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern Boolean column_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean column_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern XtPointer get_table F_PROTO((XtPointer f));
+
+extern XtPointer get_cell F_PROTO((XtPointer p,
+ int i,
+ int j));
+
+extern void get_table_size F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void get_cell_positions F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void row_delete F_PROTO((XtPointer p));
+
+extern void column_delete F_PROTO((XtPointer p));
+
+extern void delete_table F_PROTO((XtPointer p));
+
+extern Boolean go_table F_PROTO((XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *row,
+ register int *column,
+ XtPointer client_data));
+
+#ifdef EBUG_XRAW_MALLOC
+extern void _check_table F_PROTO((XtPointer table,
+ int rows,
+ int columns));
+#endif
+
+#undef F_PROTO
+
+#endif /* _table_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Template.h b/vendor/x11iraf/obm/ObmW/Xraw/Template.h
new file mode 100644
index 00000000..c53f9aa8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Template.h
@@ -0,0 +1,65 @@
+/* $XConsortium: Template.h,v 1.5 90/12/19 18:46:00 converse Exp $ */
+
+/* Copyright Massachusetts Institute of Technology 1987, 1988
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef _Template_h
+#define _Template_h
+
+/****************************************************************
+ *
+ * Template widget
+ *
+ ****************************************************************/
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/* define any special resource names here that are not in <X11/StringDefs.h> */
+
+#define XtNtemplateResource "templateResource"
+
+#define XtCTemplateResource "TemplateResource"
+
+/* declare specific TemplateWidget class and instance datatypes */
+
+typedef struct _TemplateClassRec* TemplateWidgetClass;
+typedef struct _TemplateRec* TemplateWidget;
+
+/* declare the class constant */
+
+extern WidgetClass templateWidgetClass;
+
+#endif /* _Template_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h b/vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h
new file mode 100644
index 00000000..de13b3fa
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h
@@ -0,0 +1,57 @@
+/* $XConsortium: TemplateP.h,v 1.6 91/03/13 20:12:07 rws Exp $ */
+
+/* Copyright Massachusetts Institute of Technology 1987, 1988
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef _TemplateP_h
+#define _TemplateP_h
+
+#include <X11/Xraw/Template.h>
+/* include superclass private header file */
+#include <X11/CoreP.h>
+
+/* define unique representation types not found in <X11/StringDefs.h> */
+
+#define XtRTemplateResource "TemplateResource"
+
+typedef struct {
+ int empty;
+} TemplateClassPart;
+
+typedef struct _TemplateClassRec {
+ CoreClassPart core_class;
+ TemplateClassPart template_class;
+} TemplateClassRec;
+
+extern TemplateClassRec templateClassRec;
+
+typedef struct {
+ /* resources */
+ char* resource;
+ /* private state */
+} TemplatePart;
+
+typedef struct _TemplateRec {
+ CorePart core;
+ TemplatePart template;
+} TemplateRec;
+
+#endif /* _TemplateP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Text.h b/vendor/x11iraf/obm/ObmW/Xraw/Text.h
new file mode 100644
index 00000000..9493e9db
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Text.h
@@ -0,0 +1,314 @@
+/*
+* $XConsortium: Text.h,v 1.32 89/10/19 15:01:11 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawText_h
+#define _XawText_h
+
+#include <X11/Xraw/TextSink.h>
+#include <X11/Xraw/TextSrc.h>
+
+/****************************************************************
+ *
+ * Text widget
+ *
+ ****************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ dialogHOffset Margin int 10
+ dialogVOffset Margin int 10
+ displayCaret Output Boolean True
+ displayPosition TextPosition int 0
+ editType EditType XtTextEditType XttextRead
+ height Height Dimension font height
+ insertPosition TextPosition int 0
+ leftMargin Margin Dimension 2
+ mappedWhenManaged MappedWhenManaged Boolean True
+ selectTypes SelectTypes Pointer (internal)
+ selection Selection Pointer empty selection
+ sensitive Sensitive Boolean True
+ textSink TextSink Pointer (none)
+ textSource TextSource Pointer (none)
+ width Width Dimension 100
+ x Position int 0
+ y Position int 0
+
+*/
+
+#define XtEtextScrollNever "never"
+#define XtEtextScrollWhenNeeded "whenneeded"
+#define XtEtextScrollAlways "always"
+
+#define XtEtextWrapNever "never"
+#define XtEtextWrapLine "line"
+#define XtEtextWrapWord "word"
+
+#define XtEtextResizeNever "never"
+#define XtEtextResizeWidth "width"
+#define XtEtextResizeHeight "height"
+#define XtEtextResizeBoth "both"
+
+#define XtNautoFill "autoFill"
+#define XtNbottomMargin "bottomMargin"
+#define XtNdialogHOffset "dialogHOffset"
+#define XtNdialogVOffset "dialogVOffset"
+#define XtNdisplayCaret "displayCaret"
+#define XtNdisplayPosition "displayPosition"
+#define XtNleftMargin "leftMargin"
+#define XtNrightMargin "rightMargin"
+#define XtNscrollVertical "scrollVertical"
+#define XtNscrollHorizontal "scrollHorizontal"
+#define XtNselectTypes "selectTypes"
+#define XtNtopMargin "topMargin"
+#define XtNwrap "wrap"
+
+#define XtCAutoFill "AutoFill"
+#define XtCSelectTypes "SelectTypes"
+#define XtCWrap "Wrap"
+
+#ifndef XtCScroll
+#define XtCScroll "Scroll"
+#endif
+
+#ifndef XtNresize
+#define XtNresize "resize"
+#endif
+
+#ifndef XtNinsertPosition
+#define XtNinsertPosition "insertPosition"
+#endif
+
+#ifndef XtNselection
+#define XtNselection "selection"
+#endif
+
+#ifndef XtCResize
+#define XtCResize "Resize"
+#endif
+
+
+
+
+/* Return Error code for XawTextSearch */
+
+#define XawTextSearchError (-12345L)
+
+/* Return codes from XawTextReplace */
+
+#define XawEditDone 0
+#define XawEditError 1
+#define XawPositionError 2
+
+extern Atom FMT8BIT;
+
+/* Class record constants */
+
+extern WidgetClass textWidgetClass;
+
+typedef struct _TextClassRec *TextWidgetClass;
+typedef struct _TextRec *TextWidget;
+
+/* other stuff */
+
+typedef enum { XawtextScrollNever,
+ XawtextScrollWhenNeeded, XawtextScrollAlways} XawTextScrollMode;
+
+typedef enum { XawtextWrapNever,
+ XawtextWrapLine, XawtextWrapWord} XawTextWrapMode;
+
+typedef enum { XawtextResizeNever, XawtextResizeWidth,
+ XawtextResizeHeight, XawtextResizeBoth} XawTextResizeMode;
+
+typedef enum {XawsdLeft, XawsdRight} XawTextScanDirection;
+typedef enum {XawtextRead, XawtextAppend, XawtextEdit} XawTextEditType;
+typedef enum {XawselectNull, XawselectPosition, XawselectChar, XawselectWord,
+ XawselectLine, XawselectParagraph, XawselectAll} XawTextSelectType;
+
+typedef struct {
+ int firstPos;
+ int length;
+ char *ptr;
+ Atom format;
+ } XawTextBlock, *XawTextBlockPtr;
+#ifdef XAW_BC
+/************************************************************
+ *
+ * This Stuff is only for compatibility, and will go away in
+ * future releases. */
+
+/* preserved for Back Compatability only. */
+
+#define XawTextSource Widget
+#define XtTextSource Widget
+
+#define wordBreak 0x01
+#define scrollVertical 0x02
+#define scrollHorizontal 0x04
+#define scrollOnOverflow 0x08
+#define resizeWidth 0x10
+#define resizeHeight 0x20
+#define editable 0x40
+
+typedef long XtTextPosition;
+
+#define XtTextBlock XawTextBlock
+#define XtTextBlockPtr XawTextBlockPtr
+
+#define EditDone XawEditDone
+#define EditError XawEditError
+#define PositionError XawPositionError
+
+#define XtEditDone XawEditDone
+#define XtEditError XawEditError
+#define XtPositionError XawPositionError
+
+#define XttextRead XawtextRead
+#define XttextAppend XawtextAppend
+#define XttextEdit XawtextEdit
+#define XtTextEditType XawTextEditType
+#define XtselectNull XawselectNull
+
+#define XtselectPosition XawselectPosition
+#define XtselectChar XawselectChar
+#define XtselectWord XawselectWord
+#define XtselectLine XawselectLine
+#define XtselectParagraph XawselectParagraph
+#define XtselectAll XawselectAll
+#define XtTextSelectType XawTextSelectType
+
+#define XtTextDisableRedisplay XawTextDisableRedisplay
+#define XtTextEnableRedisplay XawTextEnableRedisplay
+#define XtTextGetSource XawTextGetSource
+
+#define XtTextDisplay XawTextDisplay
+#define XtTextDisplayCaret XawTextDisplayCaret
+#define XtTextSetSelectionArray XawTextSetSelectionArray
+#define XtTextSetLastPos XawTextSetLastPos
+#define XtTextGetSelectionPos XawTextGetSelectionPos
+#define XtTextSetSource XawTextSetSource
+#define XtTextReplace XawTextReplace
+#define XtTextTopPosition XawTextTopPosition
+#define XtTextSetInsertionPoint XawTextSetInsertionPoint
+#define XtTextGetInsertionPoint XawTextGetInsertionPoint
+#define XtTextUnsetSelection XawTextUnsetSelection
+#define XtTextChangeOptions XawTextChangeOptions
+#define XtTextGetOptions XawTextGetOptions
+#define XtTextSetSelection XawTextSetSelection
+#define XtTextInvalidate XawTextInvalidate
+
+#define XtDiskSourceCreate XawDiskSourceCreate
+#define XtDiskSourceDestroy XawDiskSourceDestroy
+#define XtStringSourceCreate XawStringSourceCreate
+#define XtStringSourceDestroy XawStringSourceDestroy
+
+extern void XawTextChangeOptions(); /* w, options */
+ /* Widget w; */
+ /* int options; */
+
+extern int XawTextGetOptions(); /* w */
+ /* Widget w; */
+
+extern void XawTextSetLastPos(); /* w, lastPos */
+ /* Widget w; */
+ /* XawTextPosition lastPos; */
+
+/*************************************************************/
+#endif /* XAW_BC */
+
+extern void XawTextDisplay(); /* w */
+ /* Widget w; */
+
+extern void XawTextEnableRedisplay(); /* w */
+ /* Widget w; */
+
+extern void XawTextDisableRedisplay(); /* w */
+ /* Widget w; */
+
+extern void XawTextSetSelectionArray(); /* w, sarray */
+ /* Widget w; */
+ /* SelectionType *sarray; */
+
+extern void XawTextGetSelectionPos(); /* dpy, w, left, right */
+ /* Widget w; */
+ /* XawTextPosition *left, *right; */
+
+extern void XawTextSetSource(); /* dpy, w, source, startPos */
+ /* Widget w; */
+ /* XawTextSource source; */
+ /* XawTextPosition startPos; */
+
+extern int XawTextReplace(); /* w, startPos, endPos, text */
+ /* Widget w; */
+ /* XawTextPosition startPos, endPos; */
+ /* XawTextBlock *text; */
+
+extern XawTextPosition XawTextTopPosition(); /* w */
+ /* Widget w; */
+
+extern void XawTextSetInsertionPoint(); /* w, position */
+ /* Widget w; */
+ /* XawTextPosition position; */
+
+extern XawTextPosition XawTextGetInsertionPoint(); /* w */
+ /* Widget w; */
+
+extern void XawTextUnsetSelection(); /* w */
+ /* Widget w; */
+
+extern void XawTextSetSelection(); /* w, left, right */
+ /* Widget w; */
+ /* XawTextPosition left, right; */
+
+extern void XawTextInvalidate(); /* w, from, to */
+ /* Widget w; */
+ /* XawTextPosition from, to; */
+
+extern Widget XawTextGetSource() ; /* w */
+ /* Widget w; */
+
+extern XawTextPosition XawTextSearch() ; /* w, dir, text */
+ /* Widget w; */
+ /* XawTextScanDirection dir; */
+ /* XawTextBlock *text; */
+
+/*
+ * For R3 compatability only.
+ */
+
+#include <X11/Xraw/AsciiSrc.h>
+#include <X11/Xraw/AsciiSink.h>
+
+#endif /* _XawText_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TextP.h b/vendor/x11iraf/obm/ObmW/Xraw/TextP.h
new file mode 100644
index 00000000..c20e7ee8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TextP.h
@@ -0,0 +1,224 @@
+/*
+* $XConsortium: TextP.h,v 1.42 89/11/21 15:48:03 swick Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawTextP_h
+#define _XawTextP_h
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Text.h>
+#include <X11/Xraw/SimpleP.h>
+
+/****************************************************************
+ *
+ * Text widget private
+ *
+ ****************************************************************/
+#define MAXCUT 30000 /* Maximum number of characters that can be cut. */
+
+#define abs(x) (((x) < 0) ? (-(x)) : (x))
+
+#define GET_LAST_POS XawTextSourceScan(ctx->text.source, 0, \
+ XawstAll, XawsdRight, 1, TRUE)
+
+#define zeroPosition ((XawTextPosition) 0)
+
+extern XtActionsRec textActionsTable[];
+extern Cardinal textActionsTableCount;
+
+#define LF 0x0a
+#define CR 0x0d
+#define TAB 0x09
+#define BS 0x08
+#define SP 0x20
+#define DEL 0x7f
+#define BSLASH '\\'
+
+/* constants that subclasses may want to know */
+#define DEFAULT_TEXT_HEIGHT ((Dimension)~0)
+
+/* displayable text management data structures */
+
+typedef struct {
+ XawTextPosition position;
+ Position y;
+ Dimension textWidth;
+} XawTextLineTableEntry, *XawTextLineTableEntryPtr;
+
+typedef struct {
+ XawTextPosition left, right;
+ XawTextSelectType type;
+ Atom* selections;
+ int atom_count;
+ int array_size;
+} XawTextSelection;
+
+/* Line Tables are n+1 long - last position displayed is in last lt entry */
+typedef struct {
+ XawTextPosition top; /* Top of the displayed text. */
+ int lines; /* How many lines in this table. */
+ XawTextLineTableEntry *info; /* A dynamic array, one entry per line */
+} XawTextLineTable, *XawTextLineTablePtr;
+
+
+typedef struct _XawTextMargin {
+ Position left, right, top, bottom;
+} XawTextMargin;
+
+#define VMargins(ctx) ( (ctx)->text.margin.top + (ctx)->text.margin.bottom )
+#define HMargins(ctx) ( (ctx)->text.margin.left + (ctx)->text.margin.right )
+
+#define IsPositionVisible(ctx, pos) \
+ (pos >= ctx->text.lt.info[0].position && \
+ pos < ctx->text.lt.info[ctx->text.lt.lines].position)
+
+/*
+ * Search & Replace data structure.
+ */
+
+struct SearchAndReplace {
+ Boolean selection_changed; /* flag so that the selection cannot be
+ changed out from underneath query-replace.*/
+ Widget search_popup; /* The poppup widget that allows searches.*/
+ Widget label1; /* The label widgets for the search window. */
+ Widget label2;
+ Widget left_toggle; /* The left search toggle radioGroup. */
+ Widget right_toggle; /* The right search toggle radioGroup. */
+ Widget rep_label; /* The Replace label string. */
+ Widget rep_text; /* The Replace text field. */
+ Widget search_text; /* The Search text field. */
+ Widget rep_one; /* The Replace one button. */
+ Widget rep_all; /* The Replace all button. */
+};
+
+/* Private Text Definitions */
+
+typedef int (*ActionProc)();
+
+/* New fields for the Text widget class record */
+
+typedef struct {int empty;} TextClassPart;
+
+/* Full class record declaration */
+typedef struct _TextClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ TextClassPart text_class;
+} TextClassRec;
+
+extern TextClassRec textClassRec;
+
+/* New fields for the Text widget record */
+typedef struct _TextPart {
+ /* resources */
+
+ Widget source, sink;
+ XawTextPosition insertPos;
+ XawTextSelection s;
+ XawTextSelectType *sarray; /* Array to cycle for selections. */
+ int options; /* wordbreak, scroll, etc. */
+ int dialog_horiz_offset; /* position for popup dialog */
+ int dialog_vert_offset; /* position for popup dialog */
+ Boolean display_caret; /* insertion pt visible iff T */
+ Boolean auto_fill; /* Auto fill mode? */
+ XawTextScrollMode scroll_vert, scroll_horiz; /*what type of scrollbars.*/
+ XawTextWrapMode wrap; /* The type of wrapping. */
+ XawTextResizeMode resize; /* what to resize */
+ XawTextMargin r_margin; /* The real margins. */
+
+ /* private state */
+
+ XawTextMargin margin; /* The current margins. */
+ XawTextLineTable lt;
+ XawTextScanDirection extendDir;
+ XawTextSelection origSel; /* the selection being modified */
+ Time lasttime; /* timestamp of last processed action */
+ Time time; /* time of last key or button action */
+ Position ev_x, ev_y; /* x, y coords for key or button action */
+ Widget vbar, hbar; /* The scroll bars (none = NULL). */
+ struct SearchAndReplace * search;/* Search and replace structure. */
+ Widget file_insert; /* The file insert popup widget. */
+ XawTextPosition *updateFrom; /* Array of start positions for update. */
+ XawTextPosition *updateTo; /* Array of end positions for update. */
+ int numranges; /* How many update ranges there are. */
+ int maxranges; /* How many ranges we have space for */
+ XawTextPosition lastPos; /* Last position of source. */
+ GC gc;
+ Boolean showposition; /* True if we need to show the position. */
+ Boolean hasfocus; /* TRUE if we currently have input focus.*/
+ Boolean update_disabled; /* TRUE if display updating turned off */
+ Boolean single_char; /* Single character replaced. */
+ XawTextPosition old_insert; /* Last insertPos for batched updates */
+ short mult; /* Multiplier. */
+
+ /* private state, shared w/Source and Sink */
+ Boolean redisplay_needed; /* in SetValues */
+
+} TextPart;
+
+/*************************************************************
+ *
+ * Resource types private to Text widget.
+ *
+ *************************************************************/
+
+#define XtRScrollMode "ScrollMode"
+#define XtRWrapMode "WrapMode"
+#define XtRResizeMode "ResizeMode"
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TextRec {
+ CorePart core;
+ SimplePart simple;
+ TextPart text;
+} TextRec;
+
+#ifdef XAW_BC
+/*************************************************************
+ * For Compatibility only. */
+
+#define XtTextLineTable XawTextLineTable
+#define XtTextLineTablePtr XawTextLineTablePtr
+#define XtTextLineTableEntry XawTextLineTableEntry
+#define XtTextLineTableEntryPtr XawTextLineTableEntryPtr
+
+/*************************************************************/
+#endif /* XAW_BC */
+
+extern void _XawTextPrepareToUpdate Xraw_PROTO((TextWidget));
+
+extern int _XawTextReplace Xraw_PROTO((TextWidget,
+ XawTextPosition,
+ XawTextPosition,
+ XawTextBlock*));
+#endif /* _XawTextP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TextSink.h b/vendor/x11iraf/obm/ObmW/Xraw/TextSink.h
new file mode 100644
index 00000000..c2ad36b6
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TextSink.h
@@ -0,0 +1,239 @@
+/*
+ * $XConsortium: TextSink.h,v 1.5 89/11/01 17:28:26 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawTextSink_h
+#define _XawTextSink_h
+
+/***********************************************************************
+ *
+ * TextSink Object
+ *
+ ***********************************************************************/
+
+#include <X11/Object.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ font Font XFontStruct * XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ background Background Pixel XtDefaultBackground
+
+*/
+
+/* Class record constants */
+
+extern WidgetClass textSinkObjectClass;
+
+typedef struct _TextSinkClassRec *TextSinkObjectClass;
+typedef struct _TextSinkRec *TextSinkObject;
+
+typedef enum {XawisOn, XawisOff} XawTextInsertState;
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawTextSinkDisplayText
+ * Description: Stub function that in subclasses will display text.
+ * Arguments: w - the TextSink Object.
+ * x, y - location to start drawing text.
+ * pos1, pos2 - location of starting and ending points
+ * in the text buffer.
+ * highlight - hightlight this text?
+ * Returns: none.
+ *
+ * This function doesn't actually display anything, it is only a place
+ * holder.
+ */
+
+void XawTextSinkDisplayText(/* w, x, y, pos1, pos2, highlight */);
+/*
+Widget w;
+Position x, y;
+Boolean highlight;
+XawTextPosition pos1, pos2;
+*/
+
+/* Function Name: XawTextSinkInsertCursor
+ * Description: Places the InsertCursor.
+ * Arguments: w - the TextSink Object.
+ * x, y - location for the cursor.
+ * staye - whether to turn the cursor on, or off.
+ * Returns: none.
+ *
+ * This function doesn't actually display anything, it is only a place
+ * holder.
+ */
+
+void XawTextSinkInsertCursor( /* w, x, y, state */ );
+/*
+Widget w;
+Position x, y;
+XawTextInsertState state;
+*/
+
+/* Function Name: XawTextSinkClearToBackground
+ * Description: Clears a region of the sink to the background color.
+ * Arguments: w - the TextSink Object.
+ * x, y - location of area to clear.
+ * width, height - size of area to clear
+ * Returns: void.
+ *
+ * This function doesn't actually display anything, it is only a place
+ * holder.
+ */
+
+void XawTextSinkClearToBackground (/* w, x, y, width, height */);
+/*
+Widget w;
+Position x, y;
+Dimension width, height;
+*/
+
+/* Function Name: XawTextSinkFindPosition
+ * Description: Finds a position in the text.
+ * Arguments: w - the TextSink Object.
+ * fromPos - reference position.
+ * fromX - reference location.
+ * width, - width of section to paint text.
+ * stopAtWordBreak - returned position is a word break?
+ * resPos - Position to return. *** RETURNED ***
+ * resWidth - Width actually used. *** RETURNED ***
+ * resHeight - Height actually used. *** RETURNED ***
+ * Returns: none (see above).
+ */
+
+void XawTextSinkFindPosition(/* w, fromPos, fromx, width, stopAtWordBreak,
+ resPos, resWidth, resHeight */ );
+/*
+Widget w;
+XawTextPosition fromPos;
+int fromx, width;
+Boolean stopAtWordBreak;
+XawTextPosition *resPos;
+int *resWidth, *resHeight;
+*/
+
+/* Function Name: XawTextSinkFindDistance
+ * Description: Find the Pixel Distance between two text Positions.
+ * Arguments: w - the TextSink Object.
+ * fromPos - starting Position.
+ * fromX - x location of starting Position.
+ * toPos - end Position.
+ * resWidth - Distance between fromPos and toPos.
+ * resPos - Acutal toPos used.
+ * resHeight - Height required by this text.
+ * Returns: none.
+ */
+
+void XawTextSinkFindDistance (/* w, fromPos, fromx,
+ toPos, resWidth, resPos, resHeight */);
+/*
+Widget w;
+XawTextPosition fromPos, toPos, *resPos;
+int fromx, *resWidth, *resHeight;
+*/
+
+/* Function Name: XawTextSinkResolve
+ * Description: Resloves a location to a position.
+ * Arguments: w - the TextSink Object.
+ * pos - a reference Position.
+ * fromx - a reference Location.
+ * width - width to move.
+ * resPos - the resulting position.
+ * Returns: none
+ */
+
+void XawTextSinkResolve(/* w, pos, fromx, width, resPos */);
+/*
+Widget w;
+XawTextPosition pos;
+int fromx, width;
+XawTextPosition *resPos;
+*/
+
+/* Function Name: XawTextSinkMaxLines
+ * Description: Finds the Maximum number of lines that will fit in
+ * a given height.
+ * Arguments: w - the TextSink Object.
+ * height - height to fit lines into.
+ * Returns: the number of lines that will fit.
+ */
+
+int XawTextSinkMaxLines(/* w, height */);
+/*
+Widget w;
+Dimension height;
+*/
+
+/* Function Name: XawTextSinkMaxHeight
+ * Description: Finds the Minium height that will contain a given number
+ * lines.
+ * Arguments: w - the TextSink Object.
+ * lines - the number of lines.
+ * Returns: the height.
+ */
+
+int XawTextSinkMaxHeight(/* w, lines */);
+/*
+Widget w;
+int lines;
+*/
+
+/* Function Name: XawTextSinkSetTabs
+ * Description: Sets the Tab stops.
+ * Arguments: w - the TextSink Object.
+ * tab_count - the number of tabs in the list.
+ * tabs - the text positions of the tabs.
+ * Returns: none
+ */
+
+void XawTextSinkSetTabs(/* w, tab_count, tabs */);
+/*
+Widget w;
+int tab_count, *tabs;
+*/
+
+/* Function Name: XawTextSinkGetCursorBounds
+ * Description: Finds the bounding box for the insert curor (caret).
+ * Arguments: w - the TextSinkObject.
+ * rect - an X rectance containing the cursor bounds.
+ * Returns: none (fills in rect).
+ */
+
+void XawTextSinkGetCursorBounds(/* w, rect */);
+/*
+Widget w;
+XRectangle * rect;
+*/
+
+#endif /* _XawTextSrc_h -- DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h b/vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h
new file mode 100644
index 00000000..4bc4aea1
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h
@@ -0,0 +1,121 @@
+/*
+* $XConsortium: TextSinkP.h,v 1.3 89/10/04 13:56:59 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * TextSinkP.h - Private definitions for TextSink object
+ *
+ */
+
+#ifndef _XawTextSinkP_h
+#define _XawTextSinkP_h
+
+/***********************************************************************
+ *
+ * TextSink Object Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/ObjectP.h>
+#include <X11/Xraw/TextSink.h>
+#include <X11/Xraw/TextP.h> /* This source works with the Text widget. */
+#include <X11/Xraw/TextSrcP.h> /* This source works with the Text Source. */
+
+/************************************************************
+ *
+ * New fields for the TextSink object class record.
+ *
+ ************************************************************/
+
+typedef struct _TextSinkClassPart {
+ void (*DisplayText)();
+ void (*InsertCursor)();
+ void (*ClearToBackground)();
+ void (*FindPosition)();
+ void (*FindDistance)();
+ void (*Resolve)();
+ int (*MaxLines)();
+ int (*MaxHeight)();
+ void (*SetTabs)();
+ void (*GetCursorBounds)();
+} TextSinkClassPart;
+
+/* Full class record declaration */
+typedef struct _TextSinkClassRec {
+ ObjectClassPart object_class;
+ TextSinkClassPart text_sink_class;
+} TextSinkClassRec;
+
+extern TextSinkClassRec textSinkClassRec;
+
+/* New fields for the TextSink object record */
+typedef struct {
+ /* resources */
+ XFontStruct *font; /* Font to draw in. */
+ Pixel foreground; /* Foreground color. */
+ Pixel background; /* Background color. */
+
+ /* private state. */
+ Position *tabs; /* The tab stops as pixel values. */
+ short *char_tabs; /* The tabs stops as character values. */
+ int tab_count; /* number of items in tabs */
+
+} TextSinkPart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TextSinkRec {
+ ObjectPart object;
+ TextSinkPart text_sink;
+} TextSinkRec;
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+typedef int (*_XawSinkIntFunc)();
+typedef void (*_XawSinkVoidFunc)();
+
+#define XtInheritDisplayText ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritInsertCursor ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritClearToBackground ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritFindPosition ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritFindDistance ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritResolve ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritMaxLines ((_XawSinkIntFunc) _XtInherit)
+#define XtInheritMaxHeight ((_XawSinkIntFunc) _XtInherit)
+#define XtInheritSetTabs ((_XawSinkVoidFunc) _XtInherit)
+#define XtInheritGetCursorBounds ((_XawSinkVoidFunc) _XtInherit)
+
+#endif /* _XawTextSinkP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h b/vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h
new file mode 100644
index 00000000..262a8a00
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h
@@ -0,0 +1,224 @@
+/*
+ * $XConsortium: TextSrc.h,v 1.4 89/10/31 17:12:42 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _XawTextSrc_h
+#define _XawTextSrc_h
+
+/***********************************************************************
+ *
+ * TextSrc Object
+ *
+ ***********************************************************************/
+
+#include <X11/Object.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ editType EditType XawTextEditType XawtextRead
+
+*/
+
+/* Class record constants */
+
+extern WidgetClass textSrcObjectClass;
+
+typedef struct _TextSrcClassRec *TextSrcObjectClass;
+typedef struct _TextSrcRec *TextSrcObject;
+
+typedef enum {XawstPositions, XawstWhiteSpace, XawstEOL, XawstParagraph,
+ XawstAll} XawTextScanType;
+typedef enum {Normal, Selected }highlightType;
+typedef enum {XawsmTextSelect, XawsmTextExtend} XawTextSelectionMode;
+typedef enum {XawactionStart, XawactionAdjust, XawactionEnd}
+ XawTextSelectionAction;
+
+typedef long XawTextPosition;
+
+/*
+ * Error Conditions:
+ */
+
+#define XawTextReadError -1
+#define XawTextScanError -1
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawTextSourceRead
+ * Description: This function reads the source.
+ * Arguments: w - the TextSrc Object.
+ * pos - position of the text to retreive.
+ * RETURNED text - text block that will contain returned text.
+ * length - maximum number of characters to read.
+ * Returns: The number of characters read into the buffer.
+ */
+
+XawTextPosition XawTextSourceRead(/* w, pos, text, length */);
+/*
+Widget w;
+XawTextPosition pos;
+XawTextBlock *text;
+int length;
+*/
+
+/* Function Name: XawTextSourceReplace.
+ * Description: Replaces a block of text with new text.
+ * Arguments: src - the Text Source Object.
+ * startPos, endPos - ends of text that will be removed.
+ * text - new text to be inserted into buffer at startPos.
+ * Returns: XawEditError or XawEditDone.
+ */
+
+int XawTextSourceReplace (/* w, startPos, endPos, text */);
+/*
+Widget w;
+XawTextPosition startPos, endPos;
+XawTextBlock *text;
+*/
+
+/* Function Name: XawTextSourceScan
+ * Description: Scans the text source for the number and type
+ * of item specified.
+ * Arguments: w - the TextSrc Object.
+ * position - the position to start scanning.
+ * type - type of thing to scan for.
+ * dir - direction to scan.
+ * count - which occurance if this thing to search for.
+ * include - whether or not to include the character found in
+ * the position that is returned.
+ * Returns: The position of the text.
+ *
+ */
+
+XawTextPosition XawTextSourceScan(/* w, position, type, dir, count, include*/);
+/*
+Widget w;
+XawTextPosition position;
+XawTextScanType type;
+XawTextScanDirection dir;
+int count;
+Boolean include;
+*/
+
+/* Function Name: XawTextSourceSearch
+ * Description: Searchs the text source for the text block passed
+ * Arguments: w - the TextSource Object.
+ * position - the position to start scanning.
+ * dir - direction to scan.
+ * text - the text block to search for.
+ * Returns: The position of the text we are searching for or
+ * XawTextSearchError.
+ */
+
+XawTextPosition XawTextSourceSearch(/* w, position, dir, text */);
+/*
+Widget w;
+XawTextPosition position;
+XawTextScanDirection dir;
+XawTextBlock * text;
+*/
+
+/* Function Name: XawTextSourceConvertSelection
+ * Description: Dummy selection converter.
+ * Arguments: w - the TextSrc object.
+ * selection - the current selection atom.
+ * target - the current target atom.
+ * type - the type to conver the selection to.
+ * RETURNED value, length - the return value that has been converted.
+ * RETURNED format - the format of the returned value.
+ * Returns: TRUE if the selection has been converted.
+ *
+ */
+
+Boolean XawTextSourceConvertSelection(/* w, selection, target,
+ type, value, length, format */);
+/*
+Widget w;
+Atom * selection, * target, * type;
+caddr_t * value;
+unsigned long * length;
+int * format;
+*/
+
+/* Function Name: XawTextSourceSetSelection
+ * Description: allows special setting of the selection.
+ * Arguments: w - the TextSrc object.
+ * left, right - bounds of the selection.
+ * selection - the selection atom.
+ * Returns: none
+ */
+
+void XawTextSourceSetSelection(/* w, left, right, selection */);
+/*
+Widget w;
+XawTextPosition left, right;
+Atom selection;
+*/
+
+#ifdef XAW_BC
+/*************************************************************
+ * For Compatibility only. */
+
+#define _XtTextSink _XawTextSink
+#define _XtTextSource _XawTextSource
+
+#define XtisOn XawisOn
+#define XtisOff XawisOff
+
+#define XtsmTextSelect XawsmTextSelect
+#define XtsmTextExtend XawsmTextExtend
+
+#define XtactionStart XawactionStart
+#define XtactionAdjust XawactionAdjust
+#define XtactionEnd XawactionEnd
+
+#define XtsdLeft XawsdLeft
+#define XtsdRight XawsdRight
+
+#define XtstPositions XawstPositions
+#define XtstWhiteSpace XawstWhiteSpace
+#define XtstEOL XawstEOL
+#define XtstParagraph XawstParagraph
+#define XtstAll XawstAll
+
+#define XtTextSelectionAction XawTextSelectionAction
+#define XtTextSelection XawTextSelection
+#define XtTextScanDirection XawTextScanDirection
+#define XtTextScanType XawTextScanType
+
+
+/*************************************************************/
+#endif /* XAW_BC */
+
+#endif /* _XawTextSrc_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h b/vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h
new file mode 100644
index 00000000..a58fff09
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h
@@ -0,0 +1,106 @@
+/*
+* $XConsortium: TextSrcP.h,v 1.17 89/10/04 13:56:16 kit Exp $
+*/
+
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * TextSrcP.h - Private definitions for TextSrc object
+ *
+ */
+
+#ifndef _XawTextSrcP_h
+#define _XawTextSrcP_h
+
+/***********************************************************************
+ *
+ * TextSrc Object Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/ObjectP.h>
+#include <X11/Xraw/TextSrc.h>
+#include <X11/Xraw/TextP.h> /* This source works with the Text widget. */
+
+/************************************************************
+ *
+ * New fields for the TextSrc object class record.
+ *
+ ************************************************************/
+
+typedef struct _TextSrcClassPart {
+ XawTextPosition (*Read)();
+ int (*Replace)();
+ XawTextPosition (*Scan)();
+ XawTextPosition (*Search)();
+ void (*SetSelection)();
+ Boolean (*ConvertSelection)();
+} TextSrcClassPart;
+
+/* Full class record declaration */
+typedef struct _TextSrcClassRec {
+ ObjectClassPart object_class;
+ TextSrcClassPart textSrc_class;
+} TextSrcClassRec;
+
+extern TextSrcClassRec textSrcClassRec;
+
+/* New fields for the TextSrc object record */
+typedef struct {
+ /* resources */
+ XawTextEditType edit_mode;
+} TextSrcPart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TextSrcRec {
+ ObjectPart object;
+ TextSrcPart textSrc;
+} TextSrcRec;
+
+/************************************************************
+ *
+ * Private declarations.
+ *
+ ************************************************************/
+
+typedef Boolean (*_XawBooleanFunc)();
+typedef int (*_XawIntFunc)();
+typedef XawTextPosition (*_XawTextPositionFunc)();
+typedef void (*_XawTextVoidFunc)();
+
+#define XtInheritRead ((_XawTextPositionFunc) _XtInherit)
+#define XtInheritReplace ((_XawIntFunc) _XtInherit)
+#define XtInheritScan ((_XawTextPositionFunc) _XtInherit)
+#define XtInheritSearch ((_XawTextPositionFunc) _XtInherit)
+#define XtInheritSetSelection ((_XawTextVoidFunc) _XtInherit)
+#define XtInheritConvertSelection ((_XawBooleanFunc) _XtInherit)
+
+#endif /* _XawTextSrcP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Toggle.h b/vendor/x11iraf/obm/ObmW/Xraw/Toggle.h
new file mode 100644
index 00000000..fbd74490
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Toggle.h
@@ -0,0 +1,170 @@
+/*
+ * $XConsortium: Toggle.h,v 1.13 91/05/04 18:59:01 rws Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * ToggleP.h - Private definitions for Toggle widget
+ *
+ * Author: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ *
+ * Date: January 12, 1989
+ */
+
+#ifndef _XawToggle_h
+#define _XawToggle_h
+
+/***********************************************************************
+ *
+ * Toggle Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/Command.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ radioGroup RadioGroup Widget NULL +
+ radioData RadioData Pointer (caddr_t) Widget ++
+ state State Boolean Off
+
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback Pointer NULL
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ font Font XFontStructx* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ highlightThickness Thickness Dimension 2
+ insensitiveBorder Insensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ mappedWhenManaged MappedWhenManaged Boolean True
+ resize Resize Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
++ To use the toggle as a radio toggle button, set this resource to point to
+ any other widget in the radio group.
+
+++ This is the data returned from a call to XtToggleGetCurrent, by default
+ this is set to the name of toggle widget.
+
+*/
+
+/*
+ * These should be in StringDefs.h but aren't so we will define
+ * them here if they are needed.
+ */
+
+
+#define XtCWidget "Widget"
+#define XtCState "State"
+#define XtCRadioGroup "RadioGroup"
+#define XtCRadioData "RadioData"
+
+#ifndef _XtStringDefs_h_
+#define XtRWidget "Widget"
+#endif
+
+#define XtNstate "state"
+#define XtNradioGroup "radioGroup"
+#define XtNradioData "radioData"
+
+extern WidgetClass toggleWidgetClass;
+
+typedef struct _ToggleClassRec *ToggleWidgetClass;
+typedef struct _ToggleRec *ToggleWidget;
+
+
+/************************************************************
+ *
+ * Public Functions
+ *
+ ************************************************************/
+
+/* Function Name: XawToggleChangeRadioGroup
+ * Description: Allows a toggle widget to change radio lists.
+ * Arguments: w - The toggle widget to change lists.
+ * radio_group - any widget in the new list.
+ * Returns: none.
+ */
+
+extern void XawToggleChangeRadioGroup(
+#if NeedFunctionPrototypes
+ Widget /* w */,
+ Widget /* radio_group */
+#endif
+);
+
+/* Function Name: XawToggleGetCurrent
+ * Description: Returns the RadioData associated with the toggle
+ * widget that is currently active in a toggle list.
+ * Arguments: radio_group - any toggle widget in the toggle list.
+ * Returns: The XtNradioData associated with the toggle widget.
+ */
+
+extern XtPointer XawToggleGetCurrent(
+#if NeedFunctionPrototypes
+ Widget /* radio_group */
+#endif
+);
+
+/* Function Name: XawToggleSetCurrent
+ * Description: Sets the Toggle widget associated with the
+ * radio_data specified.
+ * Arguments: radio_group - any toggle widget in the toggle list.
+ * radio_data - radio data of the toggle widget to set.
+ * Returns: none.
+ */
+
+extern void XawToggleSetCurrent(
+#if NeedFunctionPrototypes
+ Widget /* radio_group */,
+ XtPointer /* radio_data */
+#endif
+);
+
+/* Function Name: XawToggleUnsetCurrent
+ * Description: Unsets all Toggles in the radio_group specified.
+ * Arguments: radio_group - any toggle widget in the toggle list.
+ * Returns: none.
+ */
+
+extern void XawToggleUnsetCurrent(
+#if NeedFunctionPrototypes
+ Widget /* radio_group */
+#endif
+);
+
+#endif /* _XawToggle_h */
+/* DON'T ADD STUFF AFTER THIS */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h b/vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h
new file mode 100644
index 00000000..2fd31e53
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h
@@ -0,0 +1,108 @@
+/*
+ * $XConsortium: ToggleP.h,v 1.8 91/06/20 16:15:51 converse Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * ToggleP.h - Private definitions for Toggle widget
+ *
+ * Author: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ *
+ * Date: January 12, 1989
+ *
+ */
+
+#ifndef _XawToggleP_h
+#define _XawToggleP_h
+
+#include <X11/Xraw/Toggle.h>
+#include <X11/Xraw/CommandP.h>
+
+/***********************************************************************
+ *
+ * Toggle Widget Private Data
+ *
+ ***********************************************************************/
+#ifdef streq
+#undef streq
+#endif
+
+#define streq(a, b) ( strcmp((a), (b)) == 0 )
+
+typedef struct _RadioGroup {
+ struct _RadioGroup *prev, *next; /* Pointers to other elements in group. */
+ Widget widget; /* Widget corrosponding to this element. */
+} RadioGroup;
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+ /* New fields for the Toggle widget class record */
+typedef struct _ToggleClass {
+ XtActionProc Set;
+ XtActionProc Unset;
+ XtPointer extension;
+} ToggleClassPart;
+
+ /* Full class record declaration */
+typedef struct _ToggleClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ ToggleClassPart toggle_class;
+} ToggleClassRec;
+
+extern ToggleClassRec toggleClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+ /* New fields for the Toggle widget record */
+typedef struct {
+ /* resources */
+ Widget widget;
+ XtPointer radio_data;
+
+ /* private data */
+ RadioGroup * radio_group;
+} TogglePart;
+
+ /* Full widget declaration */
+typedef struct _ToggleRec {
+ CorePart core;
+ SimplePart simple;
+ LabelPart label;
+ CommandPart command;
+ TogglePart toggle;
+} ToggleRec;
+
+#endif /* _XawToggleP_h */
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Tree.h b/vendor/x11iraf/obm/ObmW/Xraw/Tree.h
new file mode 100644
index 00000000..7ed38fee
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Tree.h
@@ -0,0 +1,120 @@
+/*
+ * $XConsortium: Tree.h,v 1.11 91/05/04 18:59:13 rws Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ * Copyright 1989 Prentice Hall
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation.
+ *
+ * M.I.T., Prentice Hall and the authors disclaim all warranties with regard
+ * to this software, including all implied warranties of merchantability and
+ * fitness. In no event shall M.I.T., Prentice Hall or the authors be liable
+ * for any special, indirect or cosequential damages or any damages whatsoever
+ * resulting from loss of use, data or profits, whether in an action of
+ * contract, negligence or other tortious action, arising out of or in
+ * connection with the use or performance of this software.
+ *
+ * Authors: Jim Fulton, MIT X Consortium,
+ * based on a version by Douglas Young, Prentice Hall
+ *
+ * This widget is based on the Tree widget described on pages 397-419 of
+ * Douglas Young's book "The X Window System, Programming and Applications
+ * with Xt OSF/Motif Edition." The layout code has been rewritten to use
+ * additional blank space to make the structure of the graph easier to see
+ * as well as to support vertical trees.
+ */
+
+
+#ifndef _XawTree_h
+#define _XawTree_h
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/XawInit.h>
+
+
+/******************************************************************************
+ *
+ * Tree Widget (subclass of ConstraintClass)
+ *
+ ******************************************************************************
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * autoReconfigure AutoReconfigure Boolean FALSE
+ * background Background Pixel XtDefaultBackground
+ * foreground Foreground Pixel XtDefaultForeground
+ * gravity Gravity XtGravity West
+ * hSpace HSpace Dimension 20
+ * lineWidth LineWidth Dimension 0
+ * vSpace VSpace Dimension 6
+ *
+ *
+ * Constraint Resources attached to children:
+ *
+ * treeGC TreeGC GC NULL
+ * treeParent TreeParent Widget NULL
+ *
+ *
+ *****************************************************************************/
+
+ /* new instance field names */
+#ifndef _XtStringDefs_h_
+#define XtNhSpace "hSpace"
+#define XtNvSpace "vSpace"
+#define XtCHSpace "HSpace"
+#define XtCVSpace "VSpace"
+#endif
+
+#define XtNautoReconfigure "autoReconfigure"
+#define XtNlineWidth "lineWidth"
+#define XtNtreeGC "treeGC"
+#define XtNtreeParent "treeParent"
+#define XtNgravity "gravity"
+
+ /* new class field names */
+#define XtCAutoReconfigure "AutoReconfigure"
+#define XtCLineWidth "LineWidth"
+#define XtCTreeGC "TreeGC"
+#define XtCTreeParent "TreeParent"
+#define XtCGravity "Gravity"
+
+#define XtRGC "GC"
+ /* external declarations */
+extern WidgetClass treeWidgetClass;
+
+typedef struct _TreeClassRec *TreeWidgetClass;
+typedef struct _TreeRec *TreeWidget;
+
+
+extern void XawTreeForceLayout Xraw_PROTO(( Widget /* tree */));
+
+
+#if defined(XtSpecificationRelease) && XtSpecificationRelease < 5
+
+typedef int XtGravity;
+
+#define XtRGravity "Gravity"
+#define XtEForget "forget"
+#define XtENorthWest "northwest"
+#define XtENorth "north"
+#define XtENorthEast "northeast"
+#define XtEWest "west"
+#define XtECenter "center"
+#define XtEEast "east"
+#define XtESouthWest "southwest"
+#define XtESouth "south"
+#define XtESouthEast "sotheast"
+#define XtEStatic "static"
+#define XtEUnmap "unmap"
+#define XtEtop "top"
+#define XtEbottom "bottom"
+
+#endif
+
+#endif /* _XawTree_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/TreeP.h b/vendor/x11iraf/obm/ObmW/Xraw/TreeP.h
new file mode 100644
index 00000000..16164afc
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/TreeP.h
@@ -0,0 +1,112 @@
+/*
+ * $XConsortium: TreeP.h,v 1.13 90/04/13 16:39:54 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ * Copyright 1989 Prentice Hall
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation.
+ *
+ * M.I.T., Prentice Hall and the authors disclaim all warranties with regard
+ * to this software, including all implied warranties of merchantability and
+ * fitness. In no event shall M.I.T., Prentice Hall or the authors be liable
+ * for any special, indirect or cosequential damages or any damages whatsoever
+ * resulting from loss of use, data or profits, whether in an action of
+ * contract, negligence or other tortious action, arising out of or in
+ * connection with the use or performance of this software.
+ *
+ * Authors: Jim Fulton, MIT X Consortium,
+ * based on a version by Douglas Young, Prentice Hall
+ *
+ * This widget is based on the Tree widget described on pages 397-419 of
+ * Douglas Young's book "The X Window System, Programming and Applications
+ * with Xt OSF/Motif Edition." The layout code has been rewritten to use
+ * additional blank space to make the structure of the graph easier to see
+ * as well as to support vertical trees.
+ */
+
+
+#ifndef _XawTreeP_h
+#define _XawTreeP_h
+
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Tree.h>
+
+typedef struct _TreeClassPart {
+ int ignore;
+} TreeClassPart;
+
+typedef struct _TreeClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ TreeClassPart tree_class;
+} TreeClassRec;
+
+extern TreeClassRec treeClassRec;
+
+typedef struct {
+ /* fields available through resources */
+ Dimension hpad; /* hSpace/HSpace */
+ Dimension vpad; /* vSpace/VSpace */
+ Dimension line_width; /* lineWidth/LineWidth */
+ Pixel foreground; /* foreground/Foreground */
+ XtGravity gravity; /* gravity/Gravity */
+ Boolean auto_reconfigure; /* autoReconfigure/AutoReconfigure */
+ /* private fields */
+ GC gc; /* used to draw lines */
+ Widget tree_root; /* hidden root off all children */
+ Dimension *largest; /* list of largest per depth */
+ int n_largest; /* number of elements in largest */
+ Dimension maxwidth, maxheight; /* for shrink wrapping */
+} TreePart;
+
+
+typedef struct _TreeRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ TreePart tree;
+} TreeRec;
+
+
+/*
+ * structure attached to all children
+ */
+typedef struct _TreeConstraintsPart {
+ /* resources */
+ Widget parent; /* treeParent/TreeParent */
+ GC gc; /* treeGC/TreeGC */
+ /* private data */
+ Widget *children;
+ int n_children;
+ int max_children;
+ Dimension bbsubwidth, bbsubheight; /* bounding box of sub tree */
+ Dimension bbwidth, bbheight; /* bounding box including node */
+ Position x, y;
+} TreeConstraintsPart;
+
+typedef struct _TreeConstraintsRec {
+ TreeConstraintsPart tree;
+} TreeConstraintsRec, *TreeConstraints;
+
+
+/*
+ * useful macros
+ */
+
+#define TREE_CONSTRAINT(w) \
+ ((TreeConstraints)((w)->core.constraints))
+
+#define TREE_INITIAL_DEPTH 10 /* for allocating largest array */
+#define TREE_HORIZONTAL_DEFAULT_SPACING 20
+#define TREE_VERTICAL_DEFAULT_SPACING 6
+
+#endif /* _XawTreeP_h */
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Viewport.h b/vendor/x11iraf/obm/ObmW/Xraw/Viewport.h
new file mode 100644
index 00000000..f1bcc0f9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Viewport.h
@@ -0,0 +1,153 @@
+/* $XConsortium: Viewport.h,v 1.21 91/07/22 19:05:23 converse Exp $ */
+
+/************************************************************
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+
+#ifndef _XawViewport_h
+#define _XawViewport_h
+
+#include <X11/Xraw/Form.h>
+#include <X11/Xraw/Reports.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ allowHoriz Boolean Boolean False
+ allowVert Boolean Boolean False
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ destroyCallback Callback Pointer NULL
+ foreceBars Boolean Boolean False
+ height Height Dimension 0
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reportCallback ReportCallback Pointer NULL
+ sensitive Sensitive Boolean True
+ useBottom Boolean Boolean False
+ useRight Boolean Boolean False
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resources #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNforceBars
+#define XtNforceBars "forceBars"
+#endif
+
+#ifndef XtNallowHoriz
+#define XtNallowHoriz "allowHoriz"
+#endif
+
+#ifndef XtNallowVert
+#define XtNallowVert "allowVert"
+#endif
+
+#ifndef XtNuseBottom
+#define XtNuseBottom "useBottom"
+#endif
+
+#ifndef XtNuseRight
+#define XtNuseRight "useRight"
+#endif
+
+#ifndef XtNframeWidth
+#define XtNframeWidth "frameWidth"
+#endif
+
+#ifndef XtNscrollbarWidth
+#define XtNscrollbarWidth "scrollbarWidth"
+#endif
+
+#ifndef XtNdistance
+#define XtNdistance "distance"
+#endif
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Classes #*/
+/*# #*/
+/*#########################################################################*/
+
+#ifndef XtCDistance
+#define XtCDistance "Distance"
+#endif
+
+#ifndef XtCScrollbarWidth
+#define XtCScrollbarWidth "ScrollbarWidth"
+#endif
+
+#ifndef XtCFrameWidth
+#define XtCFrameWidth "FrameWidth"
+#endif
+
+
+
+extern void XawViewportSetLocation (
+#if NeedFunctionPrototypes
+ Widget /* gw */,
+#if NeedWidePrototypes
+ /* float */ double /* xoff */,
+ /* float */ double /* yoff */
+#else
+ float /* xoff */,
+ float /* yoff */
+#endif
+#endif
+);
+
+extern void XawViewportSetCoordinates (
+#if NeedFunctionPrototypes
+ Widget /* gw */,
+#if NeedWidePrototypes
+ /* Position */ int /* x */,
+ /* Position */ int /* y */
+#else
+ Position /* x */,
+ Position /* y */
+#endif
+#endif
+);
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass viewportWidgetClass;
+
+typedef struct _ViewportClassRec *ViewportWidgetClass;
+typedef struct _ViewportRec *ViewportWidget;
+
+
+#endif /* _XawViewport_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h b/vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h
new file mode 100644
index 00000000..0aee6123
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h
@@ -0,0 +1,92 @@
+/*
+ * $XConsortium: ViewportP.h,v 1.13 90/02/13 14:04:14 jim Exp $
+ * Private declarations for ViewportWidgetClass
+ */
+
+/************************************************************
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+
+#ifndef _ViewportP_h
+#define _ViewportP_h
+
+#include <X11/Xraw/Viewport.h>
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/FrameP.h>
+
+typedef struct {int empty;} ViewportClassPart;
+
+typedef struct _ViewportClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ ViewportClassPart viewport_class;
+} ViewportClassRec;
+
+extern ViewportClassRec viewportClassRec;
+
+typedef struct _ViewportPart {
+ /* resources */
+ Boolean forcebars; /* Whether we should always display */
+ /* the selected scrollbars. */
+ Boolean allowhoriz; /* Whether we allow horizontal scrollbars. */
+ Boolean allowvert; /* Whether we allow vertical scrollbars. */
+ Boolean usebottom; /* True if horiz bars appear at bottom. */
+ Boolean useright; /* True if vert bars appear at right. */
+
+ Dimension distance;
+ Dimension scrollbar_width;
+ Dimension frame_width;
+ XawFrameType frame_type;
+
+ XtCallbackList report_callbacks; /* when size/position changes */
+
+ /* private state */
+
+ Widget clip, child; /* The clipping and (scrolled) child widgets */
+ Widget horiz_bar, vert_bar;/* What scrollbars we currently have. */
+ Boolean not_manage;
+
+} ViewportPart;
+
+typedef struct _ViewportRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ ViewportPart viewport;
+} ViewportRec;
+
+typedef struct {
+ /* resources */
+
+ /* private state */
+ Boolean reparented; /* True if child has been re-parented */
+} ViewportConstraintsPart;
+
+typedef struct _ViewportConstraintsRec {
+ ViewportConstraintsPart viewport;
+} ViewportConstraintsRec, *ViewportConstraints;
+
+#endif /* _ViewportP_h */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/XawAll.h b/vendor/x11iraf/obm/ObmW/Xraw/XawAll.h
new file mode 100644
index 00000000..4cf0d285
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/XawAll.h
@@ -0,0 +1,48 @@
+#ifndef _XawAll_h_
+#define _XawAll_h_
+
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/Arrow.h>
+#include <X11/Xraw/AsciiSink.h>
+#include <X11/Xraw/AsciiSrc.h>
+#include <X11/Xraw/AsciiText.h>
+#include <X11/Xraw/Box.h>
+#include <X11/Xraw/Cardinals.h>
+#include <X11/Xraw/Clock.h>
+#include <X11/Xraw/Command.h>
+#include <X11/Xraw/color.h>
+#include <X11/Xraw/Container.h>
+#include <X11/Xraw/Dialog.h>
+#include <X11/Xraw/Form.h>
+#include <X11/Xraw/Frame.h>
+#include <X11/Xraw/Grip.h>
+#include <X11/Xraw/Label.h>
+#include <X11/Xraw/List.h>
+#include <X11/Xraw/Logo.h>
+#include <X11/Xraw/MenuButton.h>
+#include <X11/Xraw/Mailbox.h>
+#include <X11/Xraw/Paned.h>
+#include <X11/Xraw/Panner.h>
+#include <X11/Xraw/Porthole.h>
+#include <X11/Xraw/Repeater.h>
+#include <X11/Xraw/Reports.h>
+#include <X11/Xraw/Scrollbar.h>
+#include <X11/Xraw/ScrolledTable.h>
+#include <X11/Xraw/Separator.h>
+#include <X11/Xraw/Simple.h>
+#include <X11/Xraw/SimpleMenu.h>
+#include <X11/Xraw/Sme.h>
+#include <X11/Xraw/SmeBSB.h>
+#include <X11/Xraw/SmeLine.h>
+#include <X11/Xraw/StripChart.h>
+#include <X11/Xraw/table.h>
+#include <X11/Xraw/Table.h>
+#include <X11/Xraw/Text.h>
+#include <X11/Xraw/TextSink.h>
+#include <X11/Xraw/TextSrc.h>
+#include <X11/Xraw/Tree.h>
+#include <X11/Xraw/Toggle.h>
+#include <X11/Xraw/Viewport.h>
+#include <X11/Xraw/XawInit.h>
+
+#endif /* _XawAll_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/XawInit.h b/vendor/x11iraf/obm/ObmW/Xraw/XawInit.h
new file mode 100644
index 00000000..cf6bcbc8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/XawInit.h
@@ -0,0 +1,60 @@
+/* $XConsortium: XawInit.h,v 1.4 91/07/22 19:05:25 converse Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _XawInit_
+#define _XawInit_
+
+#if !(defined(__STDC__) && __STDC__) && !defined(__cplusplus) && !defined(c_plusplus) && !defined(FUNCPROTO) && !defined(XTFUNCPROTO) && !defined(XAWFUNCPROTO) && !(defined(NeedFunctionPrototypes) && NeedFunctionPrototypes)
+#define Xraw_NO_PROTO
+#else
+#define Xraw_NEED_PROTO
+#endif /* __STDC__ */
+
+
+#ifdef Xraw_NEED_PROTO
+#define Xraw_PROTO(args) args
+#else
+#define Xraw_PROTO(args) ()
+#endif
+
+#define Xraw_VERSION 1
+#define Xraw_REVISION 2
+
+#define Xraw_3d 1
+#define Xraw_SCROLLBAR 20
+#define Xraw_TABLE 40
+#define Xraw_SEPARATOR 60
+#define Xraw_FRAME 80
+
+#define streq(a,b) (XrmStringToQuark(a) == XrmStringToQuark(b))
+
+#define FULL_WIDTH(w) ((w)->core.width + ((w)->core.border_width << 1))
+#define FULL_HEIGHT(w) ((w)->core.height + ((w)->core.border_width << 1))
+#define WNULL (Widget)NULL
+
+/* called from ClassInit procs */
+extern void XawInitializeWidgetSet Xraw_PROTO((void));
+
+#if defined(XtSpecificationRelease) && XtSpecificationRelease < 5
+#define XPointer XtPointer
+#endif
+
+#endif /* _XawInit_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h b/vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h
new file mode 100644
index 00000000..86ab5ed7
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h
@@ -0,0 +1,95 @@
+/*
+ * O/S-dependent (mis)feature macro definitions
+ *
+ * $XConsortium: Xosdefs.h,v 1.7 91/07/19 23:22:19 rws Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _XOSDEFS_H_
+#define _XOSDEFS_H_
+
+/*
+ * X_NOT_STDC_ENV means does not have ANSI C header files. Lack of this
+ * symbol does NOT mean that the system has stdarg.h.
+ *
+ * X_NOT_POSIX means does not have POSIX header files. Lack of this
+ * symbol does NOT mean that the POSIX environment is the default.
+ * You may still have to define _POSIX_SOURCE to get it.
+ */
+
+#ifdef NOSTDHDRS
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+
+#ifdef sony
+#ifndef SYSTYPE_SYSV
+#define X_NOT_POSIX
+#endif
+#endif
+
+#ifdef UTEK
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+
+#ifdef CRAY
+#define X_NOT_POSIX
+#endif
+
+#ifdef vax
+#ifndef ultrix /* assume vanilla BSD */
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+#endif
+
+#ifdef luna
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+
+#ifdef Mips
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+
+#ifdef USL
+#ifdef SYSV /* (release 3.2) */
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+#endif
+
+#ifdef SYSV386
+#ifdef SYSV
+#define X_NOT_POSIX
+#define X_NOT_STDC_ENV
+#endif
+#endif
+
+#ifdef MOTOROLA
+#ifdef SYSV
+#define X_NOT_STDC_ENV
+#endif
+#endif
+
+#endif /* _XOSDEFS_H_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h b/vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h
new file mode 100644
index 00000000..cf6bcbc8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h
@@ -0,0 +1,60 @@
+/* $XConsortium: XawInit.h,v 1.4 91/07/22 19:05:25 converse Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _XawInit_
+#define _XawInit_
+
+#if !(defined(__STDC__) && __STDC__) && !defined(__cplusplus) && !defined(c_plusplus) && !defined(FUNCPROTO) && !defined(XTFUNCPROTO) && !defined(XAWFUNCPROTO) && !(defined(NeedFunctionPrototypes) && NeedFunctionPrototypes)
+#define Xraw_NO_PROTO
+#else
+#define Xraw_NEED_PROTO
+#endif /* __STDC__ */
+
+
+#ifdef Xraw_NEED_PROTO
+#define Xraw_PROTO(args) args
+#else
+#define Xraw_PROTO(args) ()
+#endif
+
+#define Xraw_VERSION 1
+#define Xraw_REVISION 2
+
+#define Xraw_3d 1
+#define Xraw_SCROLLBAR 20
+#define Xraw_TABLE 40
+#define Xraw_SEPARATOR 60
+#define Xraw_FRAME 80
+
+#define streq(a,b) (XrmStringToQuark(a) == XrmStringToQuark(b))
+
+#define FULL_WIDTH(w) ((w)->core.width + ((w)->core.border_width << 1))
+#define FULL_HEIGHT(w) ((w)->core.height + ((w)->core.border_width << 1))
+#define WNULL (Widget)NULL
+
+/* called from ClassInit procs */
+extern void XawInitializeWidgetSet Xraw_PROTO((void));
+
+#if defined(XtSpecificationRelease) && XtSpecificationRelease < 5
+#define XPointer XtPointer
+#endif
+
+#endif /* _XawInit_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/color.h b/vendor/x11iraf/obm/ObmW/Xraw/color.h
new file mode 100644
index 00000000..47351d7b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/color.h
@@ -0,0 +1,73 @@
+/* $Header: /users/romsky/Xraw/last/Xraw/RCS/color.h,v 1.4 1995/12/14 00:13:07 romsky Exp romsky $ */
+
+/*
+ * color.h - color definitions
+ *
+ * Author: Christopher A. Kent
+ * Western Research Laboratory
+ * Digital Equipment Corporation
+ * Date: Sun Dec 13 1987
+ * Copyright (c) 1987 Christopher A. Kent
+ */
+
+/*
+ * $Log: color.h,v $
+ * Revision 1.4 1995/12/14 00:13:07 romsky
+ * Panner and MenuButton
+ *
+ * Revision 1.3 1995/11/24 03:35:16 romsky
+ * version 1.1.1
+ *
+ * Revision 1.3 1995/11/24 03:35:16 romsky
+ * version 1.1.1
+ *
+ * Revision 1.1 1995/11/24 03:28:25 romsky
+ * version 1.1.1
+ *
+ * Revision 1.2 1995/11/21 02:40:53 romsky
+ * *** empty log message ***
+ *
+ * Revision 1.1 1995/11/06 05:48:05 romsky
+ * Initial revision
+ *
+ * Revision 1.1 1995/11/06 05:48:05 romsky
+ * Initial revision
+ *
+ * Revision 1.1 1995/10/08 11:32:36 romsky
+ * Initial revision
+ *
+ * Revision 1.2 90/06/30 14:33:12 rlh2
+ * patchlevel 1
+ *
+ * Revision 1.1 90/05/10 11:16:54 rlh2
+ * Initial revision
+ *
+ * Revision 1.2 88/06/30 09:58:56 mikey
+ * Handles CMY also.
+ *
+ * Revision 1.1 88/06/30 09:10:53 mikey
+ * Initial revision
+ *
+ */
+
+#ifndef _color_h_
+#define _color_h_
+
+#include <X11/Xraw/XawInit.h>
+
+typedef struct _RGB {
+ unsigned short r, g, b;
+} RGB;
+
+typedef struct _HSV {
+ float h, s, v; /* [0.0, 1.0] */
+} HSV;
+
+typedef struct _CMY {
+ unsigned short c, m, y;
+} CMY;
+
+extern void HSVToRGB Xraw_PROTO((HSV *, RGB *));
+extern void RGBToHSV Xraw_PROTO((RGB *, HSV *));
+
+#endif /* _color_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h b/vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h
new file mode 100644
index 00000000..a8262f75
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h
@@ -0,0 +1,94 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _table_h_
+#define _table_h_
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xraw/Table.h>
+
+#if __STDC__ || defined(__cplusplus)
+#define F_PROTO(s) s
+#else
+#define F_PROTO(s) ()
+#endif
+
+typedef struct _XawTableNodeRec { /* Node of table grid */
+ struct _XawTableNodeRec *l;
+ struct _XawTableNodeRec *r;
+ struct _XawTableNodeRec *t;
+ struct _XawTableNodeRec *b;
+}XawTableNodeRec, *XawTableNode;
+
+
+extern XtPointer create_table F_PROTO((int rows,
+ int columns,
+ int node_size));
+
+extern Boolean row_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean row_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern Boolean column_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean column_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern XtPointer get_table F_PROTO((XtPointer f));
+
+extern XtPointer get_cell F_PROTO((XtPointer p,
+ int i,
+ int j));
+
+extern void get_table_size F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void get_cell_positions F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void row_delete F_PROTO((XtPointer p));
+
+extern void column_delete F_PROTO((XtPointer p));
+
+extern void delete_table F_PROTO((XtPointer p));
+
+extern Boolean go_table F_PROTO((XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *row,
+ register int *column,
+ XtPointer client_data));
+
+#ifdef EBUG_XRAW_MALLOC
+extern void _check_table F_PROTO((XtPointer table,
+ int rows,
+ int columns));
+#endif
+
+#undef F_PROTO
+
+#endif /* _table_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/_c b/vendor/x11iraf/obm/ObmW/_c
new file mode 100644
index 00000000..f507eb83
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/_c
@@ -0,0 +1,90 @@
+
+
+initColorResources (w)
+ GtermWidget w;
+{
+ w->gterm.color0 = ColorNameToPixel (w, w->gterm.color0Str);
+ w->gterm.color1 = ColorNameToPixel (w, w->gterm.color1Str);
+ w->gterm.color2 = ColorNameToPixel (w, w->gterm.color2Str);
+ w->gterm.color3 = ColorNameToPixel (w, w->gterm.color3Str);
+ w->gterm.color4 = ColorNameToPixel (w, w->gterm.color4Str);
+ w->gterm.color5 = ColorNameToPixel (w, w->gterm.color5Str);
+ w->gterm.color6 = ColorNameToPixel (w, w->gterm.color6Str);
+ w->gterm.color7 = ColorNameToPixel (w, w->gterm.color7Str);
+ w->gterm.color8 = ColorNameToPixel (w, w->gterm.color8Str);
+ w->gterm.color9 = ColorNameToPixel (w, w->gterm.color9Str);
+
+ w->gterm.dialogBgColor =
+ ColorNameToPixel (w, w->gterm.dialogBgColorStr);
+ w->gterm.dialogFgColor =
+ ColorNameToPixel (w, w->gterm.dialogFgColorStr);
+
+ w->gterm.idleCursorBgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorBgColorStr);
+ w->gterm.idleCursorFgColor =
+ ColorNameToPixel (w, w->gterm.idleCursorFgColorStr);
+
+ w->gterm.busyCursorBgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorBgColorStr);
+ w->gterm.busyCursorFgColor =
+ ColorNameToPixel (w, w->gterm.busyCursorFgColorStr);
+
+ w->gterm.ginmodeCursorBgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorBgColorStr);
+ w->gterm.ginmodeCursorFgColor =
+ ColorNameToPixel (w, w->gterm.ginmodeCursorFgColorStr);
+ w->gterm.crosshairCursorColor =
+ ColorNameToPixel (w, w->gterm.crosshairCursorColorStr);
+
+ w->gterm.gm_fillColor =
+ ColorNameToPixel (w, w->gterm.gm_fillColorStr);
+ w->gterm.gm_fillBgColor =
+ ColorNameToPixel (w, w->gterm.gm_fillBgColorStr);
+
+ w->gterm.gm_highlightColor =
+ ColorNameToPixel (w, w->gterm.gm_highlightColorStr);
+
+ w->gterm.gm_cursorFgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorFgColorStr);
+ w->gterm.gm_cursorBgColor =
+ ColorNameToPixel (w, w->gterm.gm_cursorBgColorStr);
+
+ w->gterm.gm_LineLineColor =
+ ColorNameToPixel (w, w->gterm.gm_LineLineColorStr);
+ w->gterm.gm_LineKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_LineKnotColorStr);
+
+ w->gterm.gm_TextLineColor =
+ ColorNameToPixel (w, w->gterm.gm_TextLineColorStr);
+ w->gterm.gm_TextColor =
+ ColorNameToPixel (w, w->gterm.gm_TextColorStr);
+ w->gterm.gm_TextBgColor =
+ ColorNameToPixel (w, w->gterm.gm_TextBgColorStr);
+
+ w->gterm.gm_RectLineColor =
+ ColorNameToPixel (w, w->gterm.gm_RectLineColorStr);
+ w->gterm.gm_RectKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_RectKnotColorStr);
+
+ w->gterm.gm_BoxLineColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxLineColorStr);
+ w->gterm.gm_BoxKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_BoxKnotColorStr);
+
+ w->gterm.gm_CircleLineColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleLineColorStr);
+ w->gterm.gm_CircleKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_CircleKnotColorStr);
+
+ w->gterm.gm_EllipseLineColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseLineColorStr);
+ w->gterm.gm_EllipseKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_EllipseKnotColorStr);
+
+ w->gterm.gm_PgonLineColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonLineColorStr);
+ w->gterm.gm_PgonKnotColor =
+ ColorNameToPixel (w, w->gterm.gm_PgonKnotColorStr);
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm b/vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm
new file mode 100644
index 00000000..6e129805
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm
@@ -0,0 +1,8 @@
+#define AnchoredImage_width 40
+#define AnchoredImage_height 10
+static unsigned char AnchoredImage_bits[] = {
+ 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x00, 0x80, 0x07, 0xfc, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0xff,
+ 0x1f, 0xfc, 0xff, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0x0f, 0x00,
+ 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
+ 0x80, 0x01};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm b/vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm
new file mode 100644
index 00000000..2b12a4b3
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm
@@ -0,0 +1,16 @@
+#define DelayedImage_width 40
+#define DelayedImage_height 30
+static unsigned char DelayedImage_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xfc,
+ 0x01, 0xfe, 0x3f, 0x00, 0xfe, 0x03, 0xfe, 0x3f, 0x00, 0xff, 0x07, 0xfe,
+ 0x3f, 0x80, 0xff, 0x0f, 0xfe, 0x3f, 0xc0, 0xff, 0x1f, 0xfe, 0x3f, 0xe0,
+ 0xff, 0x3f, 0xfe, 0x3f, 0xf0, 0xff, 0x7f, 0xfe, 0x3f, 0x00, 0x00, 0x00,
+ 0xfe, 0x3f, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0xfe, 0x3f,
+ 0xc0, 0x07, 0x00, 0xfe, 0x3f, 0xf0, 0x1f, 0x00, 0xfe, 0x3f, 0xf8, 0x3f,
+ 0x00, 0xfe, 0x3f, 0xfc, 0x7f, 0x00, 0xfe, 0x3f, 0xfc, 0x7f, 0x00, 0x00,
+ 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xfe,
+ 0xff, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00,
+ 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00,
+ 0xf8, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm b/vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm
new file mode 100644
index 00000000..93fbeb98
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm
@@ -0,0 +1,41 @@
+/* XPM */
+static char * ERROR [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"32 32 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s iconColor3 m black c red",
+"X s iconColor2 m white c white",
+/* pixels */
+" ......... ",
+" ............. ",
+" ................. ",
+" ................... ",
+" ..................... ",
+" ....................... ",
+" ......................... ",
+" ........................... ",
+" ........................... ",
+" ............................. ",
+" ............................. ",
+"............................... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"....XXXXXXXXXXXXXXXXXXXXXXX.... ",
+"............................... ",
+" ............................. ",
+" ............................. ",
+" ........................... ",
+" ........................... ",
+" ......................... ",
+" ....................... ",
+" ..................... ",
+" ................... ",
+" ................. ",
+" ............. ",
+" ......... ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm b/vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm
new file mode 100644
index 00000000..51c6a740
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm
@@ -0,0 +1,48 @@
+/* XPM */
+static char * FATAL [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"32 32 10 1 0 0",
+/* colors */
+" s none m none c none",
+". s iconGray1 m white c #e1e1e1e1e1e1",
+"X s iconColor2 m white c white",
+"o s iconGray3 m white c #afafafafafaf",
+"O s iconGray4 m white c #969696969696",
+"+ s iconGray2 m white c #c8c8c8c8c8c8",
+"@ s iconGray6 m black c #646464646464",
+"# s iconGray5 m black c #7d7d7d7d7d7d",
+"$ s iconColor1 m black c black",
+"% s iconGray7 m black c #4b4b4b4b4b4b",
+/* pixels */
+" ......... ",
+" ..XX......... ",
+" .XXX.....ooo.O+ ",
+" ..XXX.....oooOO@# ",
+" .XX.......oooOO@# ",
+" ..X+$$$....o$$$O+#% ",
+" .X+$$$$$...$$$$$##% ",
+" .XX$$$$$$X..$$$$$##@% ",
+" .XX.$$$$$X.@$$$$$+##% ",
+" .XX.....XX.@.o.O+##@% ",
+" .XX.....X$$$@ooOO##@% ",
+" ..XX....X$$$+ooO+###% ",
+" ..X.....$$$+o+OO##% ",
+" ..X....$$$$$oooO#@% ",
+" .X....$$$$$ooO#@% ",
+" .......$$$.oo#O@% ",
+" ..........o#O@% ",
+" .......ooo@@% ",
+" ....$$$o@@% ",
+" ..$$$$$%% ",
+" $$$$$$$ ",
+" ...$$$+O% ",
+" ......OO% ",
+" ....OO##% ",
+" ooo ..###@@ ..... ",
+" o...oooo ....+++@ ",
+" o.......ooooo ooooo++##+#@@ ",
+" oo@##.......oo....####+o@@@ ",
+" .......#########oooo ",
+" ...++###+#.........ooo ",
+" o++++#+oo@@@@@ooo......@ ",
+" oooo@@@ o@@@@@@ "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm b/vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm
new file mode 100644
index 00000000..c602b7cb
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm
@@ -0,0 +1,42 @@
+/* XPM */
+static char * INFO [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"32 32 4 1 0 0",
+/* colors */
+" s none m none c none",
+". c #54547070AAAA",
+"X s iconColor2 m white c white",
+"o s iconColor1 m black c black",
+/* pixels */
+" .......................... ",
+" ............................ ",
+" ...XXXXXXXXXXXXXXXXXXXXXXXX... ",
+"...XXXXXXXXXXXXXXXXXXXXXXXXXX...",
+"..XXXXXXXXXXXXXoooXXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXXoooXXXXXXXXXXXX..",
+"..XXXXXXXXXXXXXXXXXXXXXXXXXXXX..",
+"..XXXXXXXXXXXXXXXXXXXXXXXXXXXX..",
+"..XXXXXXXXXXXXXXXXXXXXXXXXXXXX..",
+"..XXXXXXXXXooooooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXooooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXXoooooXXXXXXXXXXX..",
+"..XXXXXXXXXXXoooooooXXXXXXXXXX..",
+"..XXXXXXXXXoooooooooooXXXXXXXX..",
+"...XXXXXXXXXXXXXXXXXXXXXXXXXX...",
+" ...XXXXXXXXXXXXXXXXXXXXXXXX... ",
+" ............................ ",
+" .......................... "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm b/vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm
new file mode 100644
index 00000000..49740a00
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm
@@ -0,0 +1,36 @@
+/* XPM */
+static char * NONE [] = {
+"32 32 1 1",
+" s None c None",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm b/vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm
new file mode 100644
index 00000000..d5ba4f75
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm
@@ -0,0 +1,46 @@
+#define NoImage_width 64
+#define NoImage_height 64
+static unsigned char NoImage_bits[] = {
+ 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x04, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0c,
+ 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1d, 0x00, 0x40, 0xc4, 0xff,
+ 0xff, 0xff, 0x7f, 0x1e, 0x00, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x40, 0xfe, 0x00, 0x00, 0x00, 0x50, 0x06, 0x00, 0x88, 0x0f, 0x55,
+ 0x55, 0x55, 0x05, 0x01, 0x00, 0xc0, 0x57, 0x00, 0x00, 0x00, 0x40, 0x01,
+ 0x00, 0xf2, 0x03, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x70, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x03, 0x00, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0x9f, 0x03,
+ 0x00, 0x18, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x03, 0x80, 0x2c, 0x7f, 0x50,
+ 0x55, 0x55, 0xc1, 0x01, 0x00, 0x4d, 0x4f, 0x05, 0x00, 0x00, 0x20, 0x00,
+ 0x80, 0x94, 0x13, 0x10, 0x11, 0x11, 0x31, 0x00, 0x00, 0xc1, 0x44, 0x44,
+ 0x44, 0x44, 0x64, 0x00, 0x40, 0x76, 0x10, 0xf1, 0xff, 0xff, 0x71, 0x00,
+ 0x00, 0x23, 0xc5, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x40, 0x30, 0xf8, 0x3f,
+ 0x00, 0x00, 0x7c, 0x00, 0x00, 0x55, 0xfc, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x08, 0x1f, 0x54, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x0f, 0x01,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x84, 0x43, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xcc, 0x01, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x10, 0x10,
+ 0x51, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x44, 0x84, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x08, 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x44,
+ 0x44, 0x01, 0x00, 0x00, 0x00, 0x18, 0x08, 0x11, 0x11, 0x01, 0x00, 0x00,
+ 0x00, 0x14, 0x40, 0x44, 0x44, 0x03, 0x00, 0x00, 0x00, 0x10, 0x08, 0x11,
+ 0x11, 0x03, 0x00, 0x00, 0x00, 0x10, 0x40, 0x44, 0x44, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x11, 0x11, 0x03, 0x02, 0x00, 0x00, 0x00, 0x40, 0x44,
+ 0xc4, 0x03, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x11, 0x91, 0x03, 0x09, 0x00,
+ 0x00, 0x00, 0x00, 0x44, 0xc4, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x40, 0x11,
+ 0xf1, 0x81, 0x65, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf4, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x11, 0x79, 0x20, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x46,
+ 0x3e, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x88, 0x27, 0x00,
+ 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc2, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00,
+ 0x80, 0xf0, 0x16, 0x00, 0x80, 0xa0, 0xaa, 0xaa, 0x2a, 0xf4, 0x90, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x7d, 0x4d, 0x00, 0x40, 0x44, 0x44, 0x44,
+ 0x44, 0x3f, 0xa9, 0x00, 0x00, 0x11, 0x11, 0x11, 0xd1, 0x4f, 0x5c, 0x00,
+ 0x80, 0xfc, 0xff, 0xff, 0xff, 0x13, 0x46, 0x00, 0x00, 0xfe, 0xff, 0xff,
+ 0xff, 0x44, 0x5b, 0x00, 0x40, 0x1c, 0x00, 0x00, 0x00, 0xd1, 0x27, 0x00,
+ 0x10, 0x55, 0x55, 0x55, 0x55, 0xe4, 0x31, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x40, 0x78, 0x35, 0x00, 0x08, 0x11, 0x11, 0x11, 0x11, 0x7e, 0x18, 0x00,
+ 0x40, 0x44, 0x44, 0x44, 0xc4, 0x5f, 0x1c, 0x00, 0x90, 0xff, 0xff, 0xff,
+ 0xff, 0x17, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x45, 0x07, 0x00,
+ 0x94, 0x01, 0x00, 0x00, 0x00, 0xd1, 0x03, 0x00, 0x40, 0x55, 0x55, 0x55,
+ 0x55, 0xf4, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00,
+ 0x44, 0x44, 0x44, 0x44, 0x44, 0x3f, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
+ 0xf1, 0x1f, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+ 0xf0, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm b/vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm
new file mode 100644
index 00000000..296ceefa
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm
@@ -0,0 +1,38 @@
+/* XPM */
+static char * QUESTION [] = {
+"32 32 3 1",
+" s None c None",
+". c black",
+"X s background m white g gray75 c green",
+" ",
+" ......... ",
+" ............... ",
+" ...XXXXXXXXXXX... ",
+" ...XXXXX.....XXXXX... ",
+" ...XXXX..XXXXX..XXXX... ",
+" ..XXXXX..XXXXXXX..XXXXX.. ",
+" ..XXXX..XXXXXXXXX..XXXX.. ",
+" ..XXXXX..XXXXXXXXX..XXXXX.. ",
+" ..XXXXXX....XXXXXXX..XXXXXX.. ",
+" ..XXXXXX....XXXXXXX..XXXXXX.. ",
+" .XXXXXXXX...XXXXXX..XXXXXXXX. ",
+"..XXXXXXXXXXXXXXXX..XXXXXXXXX.. ",
+"..XXXXXXXXXXXXXXX...XXXXXXXXX.. ",
+"..XXXXXXXXXXXXXX...XXXXXXXXXX.. ",
+"..XXXXXXXXXXXX....XXXXXXXXXXX.. ",
+"..XXXXXXXXXXX...XXXXXXXXXXXXX.. ",
+"..XXXXXXXXXX...XXXXXXXXXXXXXX.. ",
+"..XXXXXXXXX..XXXXXXXXXXXXXXXX.. ",
+"..XXXXXXXXX..XXXXXXXXXXXXXXXX.. ",
+"..XXXXXXXXX..XXXXXXXXXXXXXXXX.. ",
+" .XXXXXXXXXX..XX..XXXXXXXXXXX. ",
+" ..XXXXXXXXXX....XXXXXXXXXXX.. ",
+" ..XXXXXXXXXXXXXXXXXXXXXXXXX.. ",
+" ..XXXXXXXXXX...XXXXXXXXXX.. ",
+" ..XXXXXXXX.....XXXXXXXX.. ",
+" ..XXXXXXXX.....XXXXXXXX.. ",
+" ...XXXXXX.....XXXXXX... ",
+" ...XXXXXX...XXXXXX... ",
+" ...XXXXXXXXXXX... ",
+" ............... ",
+" ......... "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm b/vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm
new file mode 100644
index 00000000..6c7fda2b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm
@@ -0,0 +1,39 @@
+/* XPM */
+static char * WARNING [] = {
+"32 32 4 1",
+" s None c None",
+". s border m black g gray50 c red",
+"X c gray100",
+"o c black",
+" .. ",
+" .. ",
+" .... ",
+" .... ",
+" ...... ",
+" ...... ",
+" ........ ",
+" ........ ",
+" ....XX.... ",
+" ....XX.... ",
+" ....XXXX.... ",
+" ....XooX.... ",
+" ....XooooX.... ",
+" ....XooooX.... ",
+" ....XXooooXX.... ",
+" ....XXooooXX.... ",
+" ....XXXooooXXX.... ",
+" ....XXXooooXXX.... ",
+" ....XXXXooooXXXX.... ",
+" ....XXXXooooXXXX.... ",
+" ....XXXXXooooXXXXX.... ",
+" ....XXXXXXooXXXXXX.... ",
+" ....XXXXXXXXXXXXXXXX.... ",
+" ....XXXXXXXooXXXXXXX.... ",
+" ....XXXXXXXooooXXXXXXX.... ",
+" ....XXXXXXXooooXXXXXXX.... ",
+" ....XXXXXXXXXooXXXXXXXXX.... ",
+" ....XXXXXXXXXXXXXXXXXXXX.... ",
+" .............................. ",
+" .............................. ",
+"................................",
+"................................"};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm
new file mode 100644
index 00000000..6868704f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm
@@ -0,0 +1,26 @@
+/* XPM */
+static char * diamond0 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ",
+" ... ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" . . ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XXX ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG
new file mode 100644
index 00000000..652c2549
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG
@@ -0,0 +1,26 @@
+/* XPM */
+static char * diamond0 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ... ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+".. ..",
+". .",
+"XX XX",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XXX "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm
new file mode 100644
index 00000000..62ae149e
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm
@@ -0,0 +1,26 @@
+/* XPM */
+static char * diamond0m [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ",
+" ... ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" . . ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XXX ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm
new file mode 100644
index 00000000..017cbbc4
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm
@@ -0,0 +1,26 @@
+/* XPM */
+static char * diamond0s [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ",
+" ",
+" ... ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" . . ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XX XX ",
+" XXX ",
+" ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm
new file mode 100644
index 00000000..3ba177ae
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm
@@ -0,0 +1,27 @@
+/* XPM */
+static char * diamond1 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s foreground m white c white",
+"o s topShadowColor m white c #c8c8c8c8c8c8",
+/* pixels */
+" ",
+" ... ",
+" ..X.. ",
+" ..XXX.. ",
+" ..XXXXX.. ",
+" ..XXXXXXX.. ",
+" ..XXXXXXXXX.. ",
+" ..XXXXXXXXXXX.. ",
+" .XXXXXXXXXXXXX. ",
+" ooXXXXXXXXXXXoo ",
+" ooXXXXXXXXXoo ",
+" ooXXXXXXXoo ",
+" ooXXXXXoo ",
+" ooXXXoo ",
+" ooXoo ",
+" ooo ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG
new file mode 100644
index 00000000..5adbbc1a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG
@@ -0,0 +1,27 @@
+/* XPM */
+static char * diamond1 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s foreground m white c white",
+"o s topShadowColor m white c #c8c8c8c8c8c8",
+/* pixels */
+" ... ",
+" ..X.. ",
+" ..XXX.. ",
+" ..XXXXX.. ",
+" ..XXXXXXX.. ",
+" ..XXXXXXXXX.. ",
+" ..XXXXXXXXXXX.. ",
+"..XXXXXXXXXXXXX..",
+".XXXXXXXXXXXXXXX.",
+"ooXXXXXXXXXXXXXoo",
+" ooXXXXXXXXXXXoo ",
+" ooXXXXXXXXXoo ",
+" ooXXXXXXXoo ",
+" ooXXXXXoo ",
+" ooXXXoo ",
+" ooXoo ",
+" ooo "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm
new file mode 100644
index 00000000..575505fb
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm
@@ -0,0 +1,27 @@
+/* XPM */
+static char * diamond1m [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s topShadowColor m white c #c8c8c8c8c8c8",
+"o s highlightColor m black c black",
+/* pixels */
+" ",
+" ... ",
+" ..o.. ",
+" ..ooo.. ",
+" ..ooooo.. ",
+" ..ooooooo.. ",
+" ..ooooooooo.. ",
+" ..ooooooooooo.. ",
+" .ooooooooooooo. ",
+" XXoooooooooooXX ",
+" XXoooooooooXX ",
+" XXoooooooXX ",
+" XXoooooXX ",
+" XXoooXX ",
+" XXoXX ",
+" XXX ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm
new file mode 100644
index 00000000..65597fbe
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm
@@ -0,0 +1,27 @@
+/* XPM */
+static char * diamond1s [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"17 17 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s topShadowColor m white c #c8c8c8c8c8c8",
+"o s highlightColor m black c black",
+/* pixels */
+" ",
+" ",
+" ... ",
+" ..o.. ",
+" ..ooo.. ",
+" ..ooooo.. ",
+" ..ooooooo.. ",
+" ..ooooooooo.. ",
+" .ooooooooooo. ",
+" XXoooooooooXX ",
+" XXoooooooXX ",
+" XXoooooXX ",
+" XXoooXX ",
+" XXoXX ",
+" XXX ",
+" ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square0.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square0.pm
new file mode 100644
index 00000000..c111eca5
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square0.pm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * square0 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 3 1 0 0",
+/* colors */
+" s topShadowColor m white c #c8c8c8c8c8c8",
+". s bottomShadowColor m black c #646464646464",
+"X s none m none c none",
+/* pixels */
+" ",
+" .",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" .............",
+" .............."};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm
new file mode 100644
index 00000000..cb3a8e0d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * square0m [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ",
+" ............. ",
+" ............X ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" ..XXXXXXXXXXX ",
+" .XXXXXXXXXXXX ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm
new file mode 100644
index 00000000..42a30d8a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * square0s [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 3 1 0 0",
+/* colors */
+" s none m none c none",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s bottomShadowColor m black c #646464646464",
+/* pixels */
+" ",
+" ",
+" ........... ",
+" ..........X ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" .. XX ",
+" ..XXXXXXXXX ",
+" .XXXXXXXXXX ",
+" ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square1.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square1.pm
new file mode 100644
index 00000000..54726f47
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square1.pm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * square1 [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 3 1 0 0",
+/* colors */
+" s bottomShadowColor m black c #646464646464",
+". s topShadowColor m white c #c8c8c8c8c8c8",
+"X s foreground m white c white",
+/* pixels */
+" .",
+" ..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" XXXXXXXXXXX..",
+" ..............",
+"..............."};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm
new file mode 100644
index 00000000..c26562c8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm
@@ -0,0 +1,25 @@
+/* XPM */
+static char * square1m [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s topShadowColor m white c #c8c8c8c8c8c8",
+"o s highlightColor m black c black",
+/* pixels */
+" ",
+" ............. ",
+" ............X ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..oooooooooXX ",
+" ..XXXXXXXXXXX ",
+" .XXXXXXXXXXXX ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm b/vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm
new file mode 100644
index 00000000..ee933e85
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm
@@ -0,0 +1,25 @@
+/* XPM */
+static char * square1s [] = {
+/* width height ncolors cpp [x_hot y_hot] */
+"15 15 4 1 0 0",
+/* colors */
+" s none m none c none",
+". s bottomShadowColor m black c #646464646464",
+"X s topShadowColor m white c #c8c8c8c8c8c8",
+"o s highlightColor m black c black",
+/* pixels */
+" ",
+" ",
+" ........... ",
+" ..........X ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..oooooooXX ",
+" ..XXXXXXXXX ",
+" .XXXXXXXXXX ",
+" ",
+" "};
diff --git a/vendor/x11iraf/obm/ObmW/color.c b/vendor/x11iraf/obm/ObmW/color.c
new file mode 100644
index 00000000..ebd7707b
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/color.c
@@ -0,0 +1,309 @@
+/*LINTLIBRARY*/
+/* $Header: /users/romsky/Xraw/last/Xraw/RCS/color.c,v 1.4 1995/12/09 08:03:23 romsky Exp $ */
+
+/*
+ * color.c - color helper routines
+ *
+ * Author: Christopher A. Kent
+ * Western Research Laboratory
+ * Digital Equipment Corporation
+ * Date: Sun Dec 13 1987
+ * Copyright (c) 1987 Christopher A. Kent
+ */
+
+/*
+ * See David F. Rogers, "Procedural Elements for Computer Graphics",
+ * McGraw-Hill, for the theory behind these routines.
+ */
+
+/*
+ * $Log: color.c,v $
+ * Revision 1.4 1995/12/09 08:03:23 romsky
+ * Dec 09
+ *
+ * Revision 1.4 1995/12/09 08:03:23 romsky
+ * Dec 09
+ *
+ * Revision 1.3 1995/11/24 03:35:16 romsky
+ * version 1.1.1
+ *
+ * Revision 1.1 1995/11/24 03:28:25 romsky
+ * version 1.1.1
+ *
+ * Revision 1.2 1995/11/21 02:40:53 romsky
+ * *** empty log message ***
+ *
+ * Revision 1.1 1995/11/06 05:48:05 romsky
+ * Initial revision
+ *
+ * Revision 1.1 1995/11/06 05:48:05 romsky
+ * Initial revision
+ *
+ * Revision 1.2 1995/10/22 12:32:41 romsky
+ * *** empty log message ***
+ *
+ * Revision 1.1 1995/10/08 11:32:36 romsky
+ * Initial revision
+ *
+ * Revision 1.2 90/06/30 14:32:48 rlh2
+ * patchlevel 1
+ *
+ * Revision 1.1 90/05/10 11:17:30 rlh2
+ * Initial revision
+ *
+ * Revision 1.2 88/06/30 09:58:36 mikey
+ * Handles CMY also.
+ *
+ * Revision 1.1 88/06/30 09:10:32 mikey
+ * Initial revision
+ *
+ */
+
+static char rcs_ident[] = "$Header: /users/romsky/Xraw/last/Xraw/RCS/color.c,v 1.4 1995/12/09 08:03:23 romsky Exp $";
+
+#include <X11/Xlib.h>
+#include <X11/Xraw/color.h>
+
+#define MAX_INTENSITY 65535 /* for X11 */
+
+#define ABS(x) ((x)<0?-(x):(x))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+static RGB RGBWhite = { MAX_INTENSITY, MAX_INTENSITY, MAX_INTENSITY };
+static RGB RGBBlack = { 0, 0, 0 };
+
+/*
+ * Intensity percentages to RGB.
+ */
+
+static void PctToRGB(rgb, rr, gg, bb)
+ RGB *rgb;
+ float rr, gg, bb;
+{
+ if (rr > 1.0)
+ rr = 1.0;
+ if (gg > 1.0)
+ gg = 1.0;
+ if (bb > 1.0)
+ bb = 1.0;
+
+ rgb->r = (int)(0.5 + rr * MAX_INTENSITY);
+ rgb->g = (int)(0.5 + gg * MAX_INTENSITY);
+ rgb->b = (int)(0.5 + bb * MAX_INTENSITY);
+}
+
+/*
+ * Intensity percentages to HSV.
+ */
+
+static void PctToHSV(hsv, hh, ss, vv)
+ HSV *hsv;
+ float hh, ss, vv;
+{
+ if (hh > 1.0)
+ hh = 1.0;
+ if (ss > 1.0)
+ ss = 1.0;
+ if (vv > 1.0)
+ vv = 1.0;
+
+ hsv->h = hh;
+ hsv->s = ss;
+ hsv->v = vv;
+}
+
+/*
+ * The Manhattan distance between two colors, between 0.0 and 3.0.
+ */
+
+static float RGBDist(r, s)
+ RGB *r, *s;
+{
+ return (
+ ABS((float)(r->r - s->r)) +
+ ABS((float)(r->g - s->g)) +
+ ABS((float)(r->b - s->b))) / (float)MAX_INTENSITY;
+}
+
+/*
+ * Load an XColor with an RGB.
+ */
+
+static void RGBToXColor(r, x)
+ RGB *r;
+ XColor *x;
+{
+ x->red = r->r;
+ x->green = r->g;
+ x->blue = r->b;
+ x->flags = DoRed | DoGreen | DoBlue;
+}
+
+/*
+ * Convert a CMY to RGB.
+ */
+
+static void CMYToRGB(rgb, cmy)
+ RGB *rgb;
+ CMY *cmy;
+{
+ rgb->r = MAX_INTENSITY - cmy->c;
+ rgb->g = MAX_INTENSITY - cmy->m;
+ rgb->b = MAX_INTENSITY - cmy->y;
+}
+
+/*
+ * Convert an RGB to CMY.
+ */
+
+static void RGBToCMY(rgb, cmy)
+ RGB *rgb;
+ CMY *cmy;
+{
+ cmy->c = MAX_INTENSITY - rgb->r;
+ cmy->m = MAX_INTENSITY - rgb->g;
+ cmy->y = MAX_INTENSITY - rgb->b;
+}
+
+/*
+ * Mix two RGBs, with scale factors alpha and beta, in RGB space.
+ */
+
+static void MixRGB(r, alpha, s, beta, t)
+ RGB *r;
+ float alpha;
+ RGB *s;
+ float beta;
+ RGB *t;
+{
+ t->r = MAX(0, MIN(MAX_INTENSITY, (int)(alpha*(r->r) + beta*(s->r))));
+ t->g = MAX(0, MIN(MAX_INTENSITY, (int)(alpha*(r->g) + beta*(s->g))));
+ t->b = MAX(0, MIN(MAX_INTENSITY, (int)(alpha*(r->b) + beta*(s->b))));
+}
+
+/*
+ * Mix two RGBs with scale factors alpha and beta, in HSV space.
+ */
+
+static void MixHSV(r, alpha, s, beta, t)
+ RGB *r;
+ float alpha;
+ RGB *s;
+ float beta;
+ RGB *t;
+{
+ HSV rr, ss, tt;
+
+ RGBToHSV(r, &rr);
+ RGBToHSV(s, &ss);
+ tt.h = alpha*rr.h + beta*ss.h;
+ if (ABS(rr.h - ss.h) > 0.5) {
+ tt.h = tt.h + 0.5;
+ if (tt.h >= 1.0)
+ tt.h = tt.h - 1.0;
+ }
+ tt.s = alpha*rr.s + beta*ss.s;
+ tt.v = alpha*rr.v + beta*ss.v;
+ HSVToRGB(&tt, t);
+}
+
+/*
+ * Convert an HSV to an RGB.
+ */
+
+void
+#ifdef Xraw_NEED_PROTO
+HSVToRGB(HSV *hsv, RGB *rgb)
+#else
+HSVToRGB(hsv, rgb)
+ HSV *hsv;
+ RGB *rgb;
+#endif
+{
+ float p, q, t, f;
+ float h = hsv->h;
+ float s = hsv->s;
+ float v = hsv->v;
+ int i;
+
+ if (s == 0.0)
+ PctToRGB(rgb, v, v, v);
+ else {
+ if (s > 1.0)
+ s = 1.0;
+ if (s < 0.0)
+ s = 0.0;
+ if (v > 1.0)
+ v = 1.0;
+ if (v < 0.0)
+ v = 0.0;
+ if (h >= 1.0)
+ h = 0.0;
+
+ h = 6.0 * h;
+ i = (int) h;
+ f = h - (float) i;
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ switch(i) {
+ case 0: PctToRGB(rgb, v, t, p); break;
+ case 1: PctToRGB(rgb, q, v, p); break;
+ case 2: PctToRGB(rgb, p, v, t); break;
+ case 3: PctToRGB(rgb, p, q, v); break;
+ case 4: PctToRGB(rgb, t, p, v); break;
+ case 5: PctToRGB(rgb, v, p, q); break;
+ }
+ }
+}
+
+/*
+ * Convert an RGB to HSV.
+ */
+
+void
+#ifdef Xraw_NEED_PROTO
+RGBToHSV(RGB *rgb, HSV *hsv)
+#else
+RGBToHSV(rgb, hsv)
+ RGB *rgb;
+ HSV *hsv;
+#endif
+{
+ float rr, gg, bb;
+ float min, max;
+ float rc, gc, bc;
+
+ rr = (float) rgb->r / (float) MAX_INTENSITY;
+ gg = (float) rgb->g / (float) MAX_INTENSITY;
+ bb = (float) rgb->b / (float) MAX_INTENSITY;
+
+ max = MAX(MAX(rr, gg), bb);
+ min = MIN(MIN(rr, gg), bb);
+ hsv->v = max;
+ if (max == 0.0)
+ hsv->s = 0.0;
+ else
+ hsv->s = (max - min) / max;
+ if (hsv->s == 0.0)
+ hsv->h = 0.0;
+ else {
+ rc = (max - rr) / (max - min);
+ gc = (max - gg) / (max - min);
+ bc = (max - bb) / (max - min);
+ if (rr == max)
+ hsv->h = bc - gc;
+ else if (gg == max)
+ hsv->h = 2.0 + rc - bc;
+ else if (bb == max)
+ hsv->h = 4.0 + gc - rc;
+
+ if (hsv->h < 0.0)
+ hsv->h += 6.0;
+ hsv->h = hsv->h / 6.0;
+ }
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/cvtLong.c b/vendor/x11iraf/obm/ObmW/cvtLong.c
new file mode 100644
index 00000000..710b22af
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/cvtLong.c
@@ -0,0 +1,34 @@
+/*
+ A converter from string to long is defined in the Xmu library, but
+ the opposite direction is not. Here it is.
+
+ Bert Bos <bert@let.rug.nl>
+ 13 Aug 1993
+*/
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Converters.h"
+#include "done.h"
+
+
+Boolean XfwfCvtLongToString(display, args, num_args, from, to, converter_data)
+ Display *display;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr from;
+ XrmValuePtr to;
+ XtPointer *converter_data;
+{
+ char s[30];
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtLongToString", "wrongParameters",
+ "XtToolkitError",
+ "long to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ sprintf(s, "%ld", *((long*) from->addr));
+ done(String, s);
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/done.h b/vendor/x11iraf/obm/ObmW/done.h
new file mode 100644
index 00000000..d57c683a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/done.h
@@ -0,0 +1,16 @@
+#define done(type, value) \
+ do {\
+ if (to->addr != NULL) {\
+ if (to->size < sizeof(type)) {\
+ to->size = sizeof(type);\
+ return False;\
+ }\
+ *(type*)(to->addr) = (value);\
+ } else {\
+ static type static_val;\
+ static_val = (value);\
+ to->addr = (XtPointer)&static_val;\
+ }\
+ to->size = sizeof(type);\
+ return True;\
+ } while (0)
diff --git a/vendor/x11iraf/obm/ObmW/iconutil.c b/vendor/x11iraf/obm/ObmW/iconutil.c
new file mode 100644
index 00000000..d1392966
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/iconutil.c
@@ -0,0 +1,297 @@
+/*
+
+The converter from String to Icon knows about a few preloaded icons:
+FATAL, ERROR, WARNING, QUESTION, INFO, emptysquare, filledsquare,
+emptydiamond, filleddiamond and none. Other names are assumed to be
+names of files in XPM format.
+
+An Icon is a combination of a Pixmap and a mask. The mask is
+constructed from the pixels that are marked `none' (i.e.,
+`transparent') in the XPM data. The other pixels end up in the icon's
+pixmap. The actual colors depend on many factors, but the XPM format
+offers a way of defining `dynamic' colors, i.e., colors that are
+chosen at run time instead of by the icon's designer. The designer can
+assign symbolic names to colors, such as `foreground' or `shadow'. The
+application can then replace the symbolic names with actual colors
+when the icon is loaded.
+
+The type converter tries to automate this process. When an icon is
+loaded, the function looks for symbolic color names that match
+resources of the widget into which the icon isloaded. E.g., if the
+icon has a symbolic color `mainColor' and the widget has resource of
+the same name, the value of the resource will be used as the actual
+color for the icon.
+
+In this way, icons can be created that fit the widget, whatever the
+colors of that widget.
+
+Good symbolic names to use are `background' (defined in every widget),
+`foreground' (defined e.g., in |XfwfLabel|), `topShadowColor' and
+`bottomShadowColor' (defined in |XfwfFrame|).
+
+The implementation is as follows: the pixmap for the icon actually has
+to be created twice; once to get the list of symbolic colors and again
+with the replacement colors. When the XPM data is not preloaded, it is
+read from a file. The data is converted to an icon, converted back,
+and then again converted to an icon with new colors.
+
+The converter is passed one extra argument: the widget that the icon
+is loaded into. It must be in |args[0].addr|.
+
+The table of colors to override is set to a fixed size of 20. This
+should be enough for most applications: how many widgets have more
+than 20 color resources?
+
+*/
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Converters.h"
+#include "done.h"
+#include "bitmaps/FATAL.pm"
+#include "bitmaps/ERROR.pm"
+#include "bitmaps/WARNING.pm"
+#include "bitmaps/QUESTION.pm"
+#include "bitmaps/INFO.pm"
+#include "bitmaps/square0.pm"
+#include "bitmaps/square1.pm"
+#include "bitmaps/diamond0.pm"
+#include "bitmaps/diamond1.pm"
+#include "bitmaps/square0s.pm"
+#include "bitmaps/square1s.pm"
+#include "bitmaps/diamond0s.pm"
+#include "bitmaps/diamond1s.pm"
+#include "bitmaps/square0m.pm"
+#include "bitmaps/square1m.pm"
+#include "bitmaps/diamond0m.pm"
+#include "bitmaps/diamond1m.pm"
+
+#define MAXCOLORSYM 20
+
+
+
+/* Here are the quarks for the built-in icons names. */
+
+static XrmQuark filleddiamondq, emptydiamondq, filledsquareq, emptysquareq,
+ QUESTIONq, FATALq, ERRORq, WARNINGq, INFOq, noneq;
+static XrmQuark diamond0sq, diamond1sq, square0sq, square1sq;
+static XrmQuark diamond0mq, diamond1mq, square0mq, square1mq;
+
+static Boolean initialized = False;
+
+
+
+/* This function initializes the quarks. */
+
+static void init_icon_quarks()
+{
+ filleddiamondq = XrmPermStringToQuark("filleddiamond");
+ emptydiamondq = XrmPermStringToQuark("emptydiamond");
+ filledsquareq = XrmPermStringToQuark("filledsquare");
+ emptysquareq = XrmPermStringToQuark("emptysquare");
+
+ diamond0sq = XrmPermStringToQuark("diamond0s");
+ diamond1sq = XrmPermStringToQuark("diamond1s");
+ square0sq = XrmPermStringToQuark("square0s");
+ square1sq = XrmPermStringToQuark("square1s");
+
+ diamond0mq = XrmPermStringToQuark("diamond0m");
+ diamond1mq = XrmPermStringToQuark("diamond1m");
+ square0mq = XrmPermStringToQuark("square0m");
+ square1mq = XrmPermStringToQuark("square1m");
+
+ QUESTIONq = XrmPermStringToQuark("QUESTION");
+ FATALq = XrmPermStringToQuark("FATAL");
+ ERRORq = XrmPermStringToQuark("ERROR");
+ WARNINGq = XrmPermStringToQuark("WARNING");
+ INFOq = XrmPermStringToQuark("INFO");
+ noneq = XrmPermStringToQuark("none");
+
+ initialized = True;
+}
+
+
+/* The function |file_to_xpmimage| is called by the type converter
+ * |cvtStringToIcon|. It reads a file in XPM format into an XPM image and
+ * prints error messages in case of failure.
+ */
+static void file_to_xpmimage (dpy, file, image)
+ Display *dpy;
+ String file;
+ XpmImage *image;
+{
+ Cardinal one = 1;
+ int status;
+
+ status = XpmReadFileToXpmImage (file, image, NULL, NULL);
+
+ switch (status) {
+ case XpmOpenFailed:
+ case XpmFileInvalid:
+ case XpmNoMemory:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "fileError", "XtToolkitError", "Failed to create icon \"%s\"",
+ (XtPointer) &file, &one);
+ break;
+ case XpmColorError:
+ case XpmColorFailed:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "allocColor", "XtToolkitError",
+ "Could not get (all) colors for image \"%s\"",
+ (XtPointer) &file, &one);
+ break;
+ case XpmSuccess:
+ ; /* skip */
+ }
+}
+
+
+/* The function |data_to_xpmimage| is also called by the type converter
+ * |cvtStringToIcon|. It converts data in XPM format into an XPM image and
+ * prints error messages in case of failure.
+ */
+static void data_to_xpmimage (dpy, data, image)
+ Display *dpy;
+ String *data;
+ XpmImage *image;
+{
+ int status;
+
+ status = XpmCreateXpmImageFromData (data, image, NULL);
+
+ switch (status) {
+ case XpmOpenFailed:
+ case XpmFileInvalid:
+ case XpmNoMemory:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "fileError", "XtToolkitError", "Failed to create an icon",
+ NULL, NULL);
+ break;
+ case XpmColorError:
+ case XpmColorFailed:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "allocColor", "XtToolkitError",
+ "Could not get (all) colors for some icon", NULL, NULL);
+ break;
+ case XpmSuccess:
+ ; /* skip */
+ }
+}
+
+
+/* The function |build_colortable| is also called from
+|cvtStringToIcon|. It looks through all the resources for resources that
+specify a color (|Pixel|). All such resources and their values are
+entered in the table.
+
+To get at the resource value, the |resource_offset| (an unsigned int)
+must be added to the base address of the widget. The widget pointer is
+first converted to an unsigned long, tehn the offset is added to it and
+the result is converted back to a pointer, in this case a pointer to a
+|Pixel|. */
+
+static void build_colortable(self, table, size, n)
+ Widget self;
+ XpmColorSymbol *table;
+ Cardinal size;
+ Cardinal *n;
+{
+ Cardinal nres, i;
+ XtResourceList res;
+
+ *n = 0;
+ XtGetResourceList(XtClass(self), &res, &nres);
+ for (i = 0; i < nres; i++)
+ if (strcmp(res[i].resource_type, XtRPixel) == 0 && *n < size) {
+ table[*n].name = res[i].resource_name;
+ table[*n].value = NULL;
+ table[*n].pixel =
+ * (Pixel*) ((unsigned long) self + res[i].resource_offset);
+ (*n)++;
+ }
+ if (res)
+ XtFree ((char *)res); /* MF037 */
+}
+
+
+
+Boolean cvtStringToIcon(dpy, args, num_args, from, to, converter_data)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *num_args;
+ XrmValue *from;
+ XrmValue *to;
+ XtPointer *converter_data;
+{
+ static XpmColorSymbol table[MAXCOLORSYM];
+ String *data = NULL, s = (String) from->addr;
+ Widget self = (Widget) args[0].addr;
+ XpmImage image;
+ Icon *view;
+ Cardinal n;
+ XrmQuark q;
+
+ if (! initialized) init_icon_quarks();
+
+ if (*num_args != 1)
+ XtAppErrorMsg
+ (XtDisplayToApplicationContext(dpy),
+ "cvtStringToIcon", "wrongParameters", "XtToolkitError",
+ "String to Icon conversion needs one argument: a widget",
+ (String*) NULL, (Cardinal*) NULL);
+
+ view = (Icon*) XtCalloc(1, sizeof(*view));
+ q = XrmStringToQuark(s);
+ /*
+ * Convert the input icon or XPM file into an XPM image.
+ */
+ if (q == filleddiamondq) data_to_xpmimage(dpy, diamond1, &image);
+ else if (q == emptydiamondq) data_to_xpmimage(dpy, diamond0, &image);
+ else if (q == filledsquareq) data_to_xpmimage(dpy, square1, &image);
+ else if (q == emptysquareq) data_to_xpmimage(dpy, square0, &image);
+ else if (q == diamond0sq) data_to_xpmimage(dpy, diamond0s, &image);
+ else if (q == diamond1sq) data_to_xpmimage(dpy, diamond1s, &image);
+ else if (q == square0sq) data_to_xpmimage(dpy, square0s, &image);
+ else if (q == square1sq) data_to_xpmimage(dpy, square1s, &image);
+ else if (q == diamond0mq) data_to_xpmimage(dpy, diamond0m, &image);
+ else if (q == diamond1mq) data_to_xpmimage(dpy, diamond1m, &image);
+ else if (q == square0mq) data_to_xpmimage(dpy, square0m, &image);
+ else if (q == square1mq) data_to_xpmimage(dpy, square1m, &image);
+ else if (q == QUESTIONq) data_to_xpmimage(dpy, QUESTION, &image);
+ else if (q == FATALq) data_to_xpmimage(dpy, FATAL, &image);
+ else if (q == ERRORq) data_to_xpmimage(dpy, ERROR, &image);
+ else if (q == WARNINGq) data_to_xpmimage(dpy, WARNING, &image);
+ else if (q == INFOq) data_to_xpmimage(dpy, INFO, &image);
+ else if (q == noneq) {XtFree((String)view); done(Icon*, NULL);}
+ else file_to_xpmimage(dpy, s, &image);
+
+ /*
+ * Convert back to String format
+ */
+ if (image.width > 0 && image.height > 0)
+ XpmCreateDataFromXpmImage(&data, &image, NULL);
+
+ /*
+ * Construct color replacement table and create icon.
+ */
+ if (data) {
+ build_colortable(self, table, XtNumber(table), &n);
+ view->attributes.colorsymbols = table;
+ view->attributes.numsymbols = n;
+ view->attributes.valuemask = XpmColorSymbols;
+ (void) XpmCreatePixmapFromData(dpy, DefaultRootWindow(dpy), data,
+ &view->pixmap, &view->mask,
+ &view->attributes);
+ XtFree((String) data);
+ XpmFreeXpmImage (&image);
+ done(Icon*, view);
+
+ } else {
+ XtFree ((String)view);
+ done(Icon*, NULL);
+ }
+}
diff --git a/vendor/x11iraf/obm/ObmW/iconutil.c.ORIG b/vendor/x11iraf/obm/ObmW/iconutil.c.ORIG
new file mode 100644
index 00000000..1b6c0079
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/iconutil.c.ORIG
@@ -0,0 +1,279 @@
+/*
+
+The converter from String to Icon knows about a few preloaded icons:
+FATAL, ERROR, WARNING, QUESTION, INFO, emptysquare, filledsquare,
+emptydiamond, filleddiamond and none. Other names are assumed to be
+names of files in XPM format.
+
+An Icon is a combination of a Pixmap and a mask. The mask is
+constructed from the pixels that are marked `none' (i.e.,
+`transparent') in the XPM data. The other pixels end up in the icon's
+pixmap. The actual colors depend on many factors, but the XPM format
+offers a way of defining `dynamic' colors, i.e., colors that are
+chosen at run time instead of by the icon's designer. The designer can
+assign symbolic names to colors, such as `foreground' or `shadow'. The
+application can then replace the symbolic names with actual colors
+when the icon is loaded.
+
+The type converter tries to automate this process. When an icon is
+loaded, the function looks for symbolic color names that match
+resources of the widget into which the icon isloaded. E.g., if the
+icon has a symbolic color `mainColor' and the widget has resource of
+the same name, the value of the resource will be used as the actual
+color for the icon.
+
+In this way, icons can be created that fit the widget, whatever the
+colors of that widget.
+
+Good symbolic names to use are `background' (defined in every widget),
+`foreground' (defined e.g., in |XfwfLabel|), `topShadowColor' and
+`bottomShadowColor' (defined in |XfwfFrame|).
+
+The implementation is as follows: the pixmap for the icon actually has
+to be created twice; once to get the list of symbolic colors and again
+with the replacement colors. When the XPM data is not preloaded, it is
+read from a file. The data is converted to an icon, converted back,
+and then again converted to an icon with new colors.
+
+The converter is passed one extra argument: the widget that the icon
+is loaded into. It must be in |args[0].addr|.
+
+The table of colors to override is set to a fixed size of 20. This
+should be enough for most applications: how many widgets have more
+than 20 color resources?
+
+*/
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "Converters.h"
+#include "done.h"
+#include "bitmaps/FATAL.pm"
+#include "bitmaps/ERROR.pm"
+#include "bitmaps/WARNING.pm"
+#include "bitmaps/QUESTION.pm"
+#include "bitmaps/INFO.pm"
+#include "bitmaps/square0.pm"
+#include "bitmaps/square1.pm"
+#include "bitmaps/diamond0.pm"
+#include "bitmaps/diamond1.pm"
+
+#define MAXCOLORSYM 20
+
+
+
+/* Here are the quarks for the built-in icons names. */
+
+static XrmQuark filleddiamondq, emptydiamondq, filledsquareq, emptysquareq,
+ QUESTIONq, FATALq, ERRORq, WARNINGq, INFOq, noneq;
+
+static Boolean initialized = False;
+
+
+
+/* This function initializes the quarks. */
+
+static void init_icon_quarks()
+{
+ filleddiamondq = XrmPermStringToQuark("filleddiamond");
+ emptydiamondq = XrmPermStringToQuark("emptydiamond");
+ filledsquareq = XrmPermStringToQuark("filledsquare");
+ emptysquareq = XrmPermStringToQuark("emptysquare");
+ QUESTIONq = XrmPermStringToQuark("QUESTION");
+ FATALq = XrmPermStringToQuark("FATAL");
+ ERRORq = XrmPermStringToQuark("ERROR");
+ WARNINGq = XrmPermStringToQuark("WARNING");
+ INFOq = XrmPermStringToQuark("INFO");
+ noneq = XrmPermStringToQuark("none");
+ initialized = True;
+}
+
+
+/* The function |file_to_icon| is called by the type converter
+|cvtStringToIcon|. It reads a file in XPM format and prints error
+messages in case of failure. Of the XPM attributes, only the color
+symbols are retained. */
+
+static void file_to_icon(dpy, file, icon)
+ Display *dpy;
+ String file;
+ Icon *icon;
+{
+ Cardinal one = 1;
+ int status;
+
+#ifdef OLD_XPM
+ icon->attributes.valuemask = XpmReturnInfos;
+#else
+ icon->attributes.valuemask = 0;
+#endif
+ status = XpmReadFileToPixmap(dpy, DefaultRootWindow(dpy), file,
+ &icon->pixmap, &icon->mask,
+ &icon->attributes);
+ switch (status) {
+ case XpmOpenFailed:
+ case XpmFileInvalid:
+ case XpmNoMemory:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "fileError", "XtToolkitError", "Failed to create icon \"%s\"",
+ (XtPointer) &file, &one);
+ icon->pixmap = icon->mask = None;
+ break;
+ case XpmColorError:
+ case XpmColorFailed:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "allocColor", "XtToolkitError",
+ "Could not get (all) colors for image \"%s\"",
+ (XtPointer) &file, &one);
+ break;
+ case XpmSuccess:
+ ; /* skip */
+ }
+}
+
+
+/* The function |data_to_icon| is also called by the type converter
+|cvtStringToIcon|. It converts data in XPM format and prints error
+messages in case of failure. Of the XPM attributes, only the color
+symbols are retained. */
+
+static void data_to_icon(dpy, data, icon)
+ Display *dpy;
+ String *data;
+ Icon *icon;
+{
+ int status;
+
+#ifdef OLD_XPM
+ icon->attributes.valuemask = XpmReturnInfos;
+#else
+ icon->attributes.valuemask = 0;
+#endif
+ status = XpmCreatePixmapFromData(dpy, DefaultRootWindow(dpy), data,
+ &icon->pixmap, &icon->mask,
+ &icon->attributes);
+ switch (status) {
+ case XpmOpenFailed:
+ case XpmFileInvalid:
+ case XpmNoMemory:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "fileError", "XtToolkitError", "Failed to create an icon",
+ NULL, NULL);
+ icon->pixmap = icon->mask = None;
+ break;
+ case XpmColorError:
+ case XpmColorFailed:
+ XtAppWarningMsg
+ (XtDisplayToApplicationContext(dpy), "cvtStringToIcon",
+ "allocColor", "XtToolkitError",
+ "Could not get (all) colors for some icon", NULL, NULL);
+ break;
+ case XpmSuccess:
+ ; /* skip */
+ }
+}
+
+
+/* The function |build_colortable| is also called from
+|cvtStringToIcon|. It looks through all the resources for resources that
+specify a color (|Pixel|). All such resources and their values are
+entered in the table.
+
+To get at the resource value, the |resource_offset| (an unsigned int)
+must be added to the base address of the widget. The widget pointer is
+first converted to an unsigned long, tehn the offset is added to it and
+the result is converted back to a pointer, in this case a pointer to a
+|Pixel|. */
+
+static void build_colortable(self, table, size, n)
+ Widget self;
+ XpmColorSymbol *table;
+ Cardinal size;
+ Cardinal *n;
+{
+ Cardinal nres, i;
+ XtResourceList res;
+
+ *n = 0;
+ XtGetResourceList(XtClass(self), &res, &nres);
+ for (i = 0; i < nres; i++)
+ if (strcmp(res[i].resource_type, XtRPixel) == 0 && *n < size) {
+ table[*n].name = res[i].resource_name;
+ table[*n].value = NULL;
+ table[*n].pixel =
+ * (Pixel*) ((unsigned long) self + res[i].resource_offset);
+ (*n)++;
+ }
+}
+
+
+
+Boolean cvtStringToIcon(dpy, args, num_args, from, to, converter_data)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *num_args;
+ XrmValue *from;
+ XrmValue *to;
+ XtPointer *converter_data;
+{
+ static XpmColorSymbol table[MAXCOLORSYM];
+ Cardinal n;
+ String *data, s = (String) from->addr;
+ Widget self = (Widget) args[0].addr;
+ Icon *view;
+ XrmQuark q;
+
+ if (! initialized) init_icon_quarks();
+
+ if (*num_args != 1)
+ XtAppErrorMsg
+ (XtDisplayToApplicationContext(dpy),
+ "cvtStringToIcon", "wrongParameters", "XtToolkitError",
+ "String to Icon conversion needs one argument: a widget",
+ (String*) NULL, (Cardinal*) NULL);
+
+ view = (Icon*) XtMalloc(sizeof(*view));
+ q = XrmStringToQuark(s);
+ /*
+ * Create the icon for the first time, store the color names
+ */
+ if (q == filleddiamondq) data_to_icon(dpy, diamond1, view);
+ else if (q == emptydiamondq) data_to_icon(dpy, diamond0, view);
+ else if (q == filledsquareq) data_to_icon(dpy, square1, view);
+ else if (q == emptysquareq) data_to_icon(dpy, square0, view);
+ else if (q == QUESTIONq) data_to_icon(dpy, QUESTION, view);
+ else if (q == FATALq) data_to_icon(dpy, FATAL, view);
+ else if (q == ERRORq) data_to_icon(dpy, ERROR, view);
+ else if (q == WARNINGq) data_to_icon(dpy, WARNING, view);
+ else if (q == INFOq) data_to_icon(dpy, INFO, view);
+ else if (q == noneq) {XtFree((String)view); done(Icon*, NULL);}
+ else file_to_icon(dpy, s, view);
+
+ /*
+ * Convert back to String format
+ */
+ (void) XpmCreateDataFromPixmap(dpy, &data, view->pixmap,
+ view->mask, &view->attributes);
+ /*
+ XFreePixmap(dpy, view->pixmap);
+ XFreePixmap(dpy, view->mask);
+ */
+ XpmFreeAttributes(&view->attributes);
+ /*
+ * Construct color replacement table and create icon again
+ */
+ build_colortable(self, table, XtNumber(table), &n);
+ view->attributes.colorsymbols = table;
+ view->attributes.numsymbols = n;
+ view->attributes.valuemask = XpmColorSymbols;
+ (void) XpmCreatePixmapFromData(dpy, DefaultRootWindow(dpy), data,
+ &view->pixmap, &view->mask,
+ &view->attributes);
+ XtFree((String) data);
+ done(Icon*, view);
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/inkstore.h b/vendor/x11iraf/obm/ObmW/inkstore.h
new file mode 100644
index 00000000..147e7d52
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/inkstore.h
@@ -0,0 +1,1844 @@
+/*--------------------------------------------------------------------------
+** File: inkstore.h
+**
+** Copyright 1993, Slate Corporation, All Rights Reserved.
+**
+** This document is part of the Jot specification for the storage and
+** interchange of electronic ink data. This specification is the joint work
+** of representatives of Slate Corporation, Lotus Development Corporation,
+** GO, Microsoft, Apple, General Magic, and others.
+**
+** This document and the accompanying code samples on disk comprise Version
+** 1.0 of the Jot specification for the storage and interchange of electronic
+** ink data. Permission is granted to incorporate and otherwise use any
+** portion of the specification. You may make copies of the specification
+** for distribution to others, provided you include the notice "Copyright
+** 1993, Slate Corporation. All Rights Reserved" on both the document and
+** the disk label. You may not modify this specification without written
+** permission from Slate Corporation.
+**
+** The specification is provided "as is" without warranty of any kind. Slate
+** further disclaims all implied warranties of merchantability or of fitness
+** for a particular purpose. The entire risk arising out of the use or
+** performance of the specification remains with you.
+**
+**--------------------------------------------------------------------------
+**
+** This is the main body of definitions for the ink storage specification.
+** See reference section 1.0 for revision history.
+**
+**------------------------------------------------------------------------*/
+
+#ifndef INKSTORE_INCLUDED
+#define INKSTORE_INCLUDED
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 0.0 */
+/*************************/
+
+/*--------------------------------------------------------------------------
+** "Rationale for the ink specification"
+**
+** This document defines a storage and interchange format for embedded ink
+** data. The format is device- and platform-independent. The goal is to
+** provide application programs on the same and different platforms and
+** operating systems a way to store and exchange ink data. Thus a PenPoint
+** user might scribble a note and send the untranslated ink as part of an
+** e-mail message to a colleague's pen computer running Windows for Pen
+** Computing using Magic Mail.
+**
+** This specification is for a publicly-defined, external format for
+** electronic ink data interchange, and neither assumes nor dictates the
+** nature of how the application deals with ink data internally. The format
+** is not intended to be the "internal" ink format of an application, though
+** there is no reason why it could not serve such a purpose.
+**
+** The scope and goals of this format design are limited to the represent-
+** ation of electronic ink data embedded in some other electronic document,
+** not to the larger document itself (such as an e-mail or enhanced word-
+** processing data file).
+**
+** The approach taken is to capture the complete user input for the
+** electronic ink, including not just X/Y coordinates, but also a large set
+** of current drawing attributes such as nib type and ink color. This
+** differs from other possible approaches, such as those based on certain
+** recognition models for handwritten text, which require decomposing the
+** handwritten ink data first into a set of pre-defined approximation curves
+** or sub-strokes, and then storing a list of encodings of these sub-strokes.
+** In other words, Jot preserves all information about the original input as
+** opposed attempting any sort of abstract characterization of the input.
+**
+** The storage format has a number of properties:
+**
+** * Simple. Typical operations on the ink data are easy. If you only wish
+** to read stroke coordinates and bounding information from the data,
+** complex information that might be present will not hinder the process.
+** Likewise, it is easy to write out just simple information. The
+** complex information is all optional.
+**
+** * Compact. The storage format is intended to be as compact as possible
+** without sacrificing simplicity or fidelity. Optional information such
+** as time stamps or color specifications occupy space only when they are
+** present. Specifications that apply to many strokes (such as line width
+** or color) are represented just once.
+**
+** * Compression. The stroke information that describes the ink can
+** optionally be represented in a compressed format. Compression
+** techniques include both compression and reduction of the ink data.
+**
+** * Inclusive. The format is capable of storing every property of ink
+** conceivable as of today.
+**
+** * Expandable and Compatible. The format is expandable, so as developers
+** discover new information that should be recorded in an ink storage
+** format, these new features can be added without changing the behavior of
+** existing application programs working with an older version of the
+** format. In general, new features can generally be ignored by
+** applications reading older versions of the format. Likewise, new
+** application programs can handle previous versions of the format without
+** special work.
+**
+** The format is not designed to easily support lots of in-memory
+** manipulation of the ink data, such as deleting strokes, changing line
+** widths, and so on. A format supporting these types of manipulations would
+** be at odds with the above goals. All the information needed to perform
+** these manipulations is present in this data format, so an application
+** might augment this format to facilitate manipulation of the ink data.
+**
+** Applications are likely to use some other format internally for real-time
+** ink manipulation. Many operating environments provide some internal means
+** for storing and manipulating ink data, the details of which may be hidden
+** to some extent from the application designer. Many such real-time data
+** structures store fewer types of and/or less information (such as not
+** preserving information about the tablet point data rate) than are covered
+** in this definition.
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 1.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** Jot Ink Specification
+** ---------------------
+**
+** Revision History:
+**
+** March 16, 1992 - First public draft.
+** July 13, 1992 - Major rewrite to put data into a series of records.
+** July 19, 1992 - Inclusion of ink-compacting definitions.
+** July 30, 1992 - Change of target rect to offset.
+** December 28, 1992 - Changes incorporated from August 1992 review meeting.
+** February 12, 1993 - Incremental fixes due to coding experience.
+** March 13, 1993 - Revised definition of a "group".
+** April 12, 1993 - Release of version 0.99 of the specification. Moved
+** reference sections 28 and 29 to a separate file called
+** sample.h
+** May 01, 1993 - Release of version 1.00 of the specification.
+** Changed INK_OFFSET_RECORD units from twips to pen
+** units for consistency and ease of implementation.
+** Fixed a typo in reference section 26.0 in the diagram.
+** The text accompanying the diagram was correct.
+** Fixed a typo in reference section 27.0. The old text
+** "delta-X == 0 or 1" was replaced with the correct text
+** "delta-X == 2". The accompanying diagram was correct.
+** Removed all sizeof() constructs and replaced with
+** appropriate #defines to reduce compiler dependencies.
+** Tagged all struct definitions with tag_ prefix.
+** Added comments and reordered some existing comments.
+** May 17, 1993 - Added a few more _SIZE #defines, clarified reserved
+** values.
+**
+**
+** GENERAL NOTES
+** -------------
+**
+**
+** Record Structure
+** ----------------
+**
+** If not otherwise specified, all words are stored in Intel order: low-order
+** word first, then high-order word, and inside of a word, low-order byte,
+** then high-order byte. For example, a 32 bit quantity 0x12345678 would be
+** written to the file as 0x78 0x56 0x34 0x12. The notable exception is the
+** storage of point data in "standard compression" format. Sign bits are
+** used to indicate item types, so the bytes are stored high-order to low-
+** order (exactly opposite). See the sample code and reference section 23.0
+** for more information on the compressed format. Uncompressed data is
+** written in Intel order.
+**
+** All structures are packed for the purposes of writing to a stream.
+**
+** Signed integer values are two's-complement. Rectangles are stored
+** x,y,w,h.
+**
+** These definitions are intended to insulate the sample ink compaction and
+** storage code from any possible variation in item alignment or structure
+** packing across architectures. The only possible area of portability
+** concern lies in the use of unions in colors (see 11.0) and pen tips (see
+** 14.0).
+**
+** Any use of units of mass to denote units of force ("grams of force"), or
+** similar common misuses of physical units, are noted here with an apology
+** to any purists, and should be interpreted in the common way by assuming
+** one standard gravity.
+**
+** Record Sequence
+** ---------------
+**
+** In this document, one piece of ink data is called an ink bundle.
+** Typically this might correspond to the strokes that make up the ink from
+** the time when the pen touches down until the user finishes writing
+** (usually determined by a timeout or the pen leaving proximity). Thus an
+** ink bundle usually contains many ink strokes, and the strokes do not have
+** to describe a continuous line of ink.
+**
+** As stated in reference section 5.0, all data conforming to this
+** specification appears as a stream of ink bundles each of which must begin
+** with an INK_BUNDLE_RECORD and end with an INK_END_RECORD. There may be
+** more than one INK_BUNDLE_RECORD/INK_END_RECORD pair in a given stream.
+** A record stream might look something like this:
+**
+** INK_BUNDLE_RECORD required // for bundle number one
+** INK_SCALE_RECORD optional // sets the scale for rendering
+** INK_OFFSET_RECORD optional // sets the offset for rendering
+** INK_COLOR_RECORD optional // sets the color for rendering
+** INK_START_TIME_RECORD optional // sets the relative start time
+** INK_PENTIP_RECORD optional // sets the pentip for rendering
+** INK_GROUP_RECORD optional // tags the following PENDATA
+** INK_PENDATA_RECORD recommended // actual points
+** INK_GROUP_RECORD optional // tags the following PENDATA
+** INK_PENDATA_RECORD recommended // actual points
+** INK_PENDATA_RECORD recommended // more points in same group
+** INK_SCALE_RESET_RECORD optional // resets to default scaling/offset
+** INK_PENDATA_RECORD recommended // actual points
+** INK_END_TIME_RECORD optional // relative time inking ended
+** INK_END_RECORD required // end of bundle number one
+**
+** It is perfectly reasonable to write out only the following (though doing
+** so will cause the ink to be rendered in a completely default manner --
+** black hairline width at 1:1 scaling with offset 0):
+**
+** INK_BUNDLE_RECORD
+** INK_PENDATA_RECORD
+** INK_END_RECORD
+**
+**
+** Specification Revisions
+** -----------------------
+**
+** Future enhancements to this specification may modify certain record types.
+** It is guaranteed that any record modified in a subsequent revision of the
+** specification will be a strict superset of that record's definition in any
+** previous revision of the specification. That is, modified record types
+** will only be lengthened, not shortened. If a particular record type must
+** be extended such that it would not be a superset of the original, a new
+** record type would be added to cover that particular extension.
+**
+** This extension strategy has two important ramifications:
+**
+** 1) A reading application should *ALWAYS* use the size of a record as
+** recorded in the record structure itself (i.e., the recordLength field
+** of the INK_RECORD_HEADERx structure) rather than the sizeof() or any
+** other size determined at compile time to determine how may bytes to
+** read as the data structures are parsed. This is due to the fact that
+** a record may grow in a future revision of the standard. The only
+** exception to this rule is the INK_BUNDLE_RECORD which contains a
+** version number that will be modified with each change to that record.
+** If an INK_BUNDLE_RECORD is encountered and its version matches the
+** version used at compile time, the size of the record should exactly
+** match the #define of inkRecordBundleSize.
+**
+** 2) Any particular record may be read into a target data structure up to
+** the size of the target data structure and the rest may be ignored.
+** This is due to the 'strict superset' rule which means that any
+** extension of any record type must leave the meaning, content, and size
+** of any existing fields as is. So, for example, if an INK_SCALE_RECORD
+** was modified by adding 2 bytes, the reading application can safely read
+** the data into the INK_SCALE_RECORD known at compile time and throw
+** away the extra two bytes: the header, x, and y will be in the same
+** place and will have the same meaning.
+**
+**
+** Files of Ink
+** ------------
+**
+** It is a recommended practice on DOS and UNIX style file systems to use the
+** extension ".JOT" for files consisting solely of ink recorded according to
+** this specification. The specification is designed such that ink data can
+** be embedded inside any file format and if such a file contains more than
+** strictly ink data, it should not use the .JOT extension.
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 2.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** Definitions used in this header.
+**
+** These definitions must be defined appropriately to the target environment
+** and compiler.
+**
+** For example, on some compilers for environments using segmented addressing
+** and 64K segments sizes, the correct definition of FAR would be "_huge",
+** rather than "_far", because the objects pointed to may be larger than 64K.
+**
+** In particular, check the definitions of FAR, U32, and S32 for
+** compatibility with your compiler, environment, and memory model.
+**
+**------------------------------------------------------------------------*/
+
+#ifndef FAR
+#define FAR
+#endif
+
+/* useful constants */
+
+#define flag0 (0x0001)
+#define flag1 (0x0002)
+#define flag2 (0x0004)
+#define flag3 (0x0008)
+#define flag4 (0x0010)
+#define flag5 (0x0020)
+#define flag6 (0x0040)
+#define flag7 (0x0080)
+#define flag8 (0x0100)
+#define flag9 (0x0200)
+#define flag10 (0x0400)
+#define flag11 (0x0800)
+#define flag12 (0x1000)
+#define flag13 (0x2000)
+#define flag14 (0x4000)
+#define flag15 (0x8000)
+
+#define flag16 (0x00010000L)
+#define flag17 (0x00020000L)
+#define flag18 (0x00040000L)
+#define flag19 (0x00080000L)
+#define flag20 (0x00100000L)
+#define flag21 (0x00200000L)
+#define flag22 (0x00400000L)
+#define flag23 (0x00800000L)
+#define flag24 (0x01000000L)
+#define flag25 (0x02000000L)
+#define flag26 (0x04000000L)
+#define flag27 (0x08000000L)
+#define flag28 (0x10000000L)
+#define flag29 (0x20000000L)
+#define flag30 (0x40000000L)
+#define flag31 (0x80000000L)
+
+#define TRUE 1
+#define FALSE 0
+
+/* void pointers */
+typedef void FAR *P_UNKNOWN;
+typedef P_UNKNOWN FAR *PP_UNKNOWN;
+
+#define pNull ((P_UNKNOWN)0)
+
+/* Unsigned integers */
+typedef unsigned char U8, FAR *P_U8;
+#define U8_SIZE 1
+typedef unsigned short U16, FAR *P_U16;
+#define U16_SIZE 2
+typedef unsigned long U32, FAR *P_U32;
+#define U32_SIZE 4
+
+/* Signed integers */
+/*
+typedef signed char S8, FAR *P_S8;
+#define S8_SIZE 1
+typedef signed short S16, FAR *P_S16;
+#define S16_SIZE 2
+typedef signed long S32, FAR *P_S32;
+#define S32_SIZE 4
+ */
+typedef char S8, FAR *P_S8;
+#define S8_SIZE 1
+typedef short S16, FAR *P_S16;
+#define S16_SIZE 2
+typedef long S32, FAR *P_S32;
+#define S32_SIZE 4
+
+/* geometry structures */
+typedef struct tag_XY32 {
+ S32 x;
+ S32 y;
+} XY32, FAR *P_XY32;
+#define XY32_SIZE (S32_SIZE+S32_SIZE)
+
+typedef struct tag_XY16 {
+ S16 x;
+ S16 y;
+} XY16, FAR *P_XY16;
+
+/*-------------------------------------------------------------------------
+** Note:
+** Angles from vertical can exceed +-90 degrees: in this case, the "back" end
+** of the stylus is nearer the tablet surface than the "front" end.
+**-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+** Note:
+** Standard compaction will normally store angles in nibbles, or single
+** bytes, rather than in four-byte records.
+**-------------------------------------------------------------------------*/
+
+typedef struct tag_ANGLE16 {
+ S16 theta; /* "X" angle of the stylus, degrees from vertical, */
+ /* increasing in the positive "X" direction. */
+ S16 phi; /* "Y" angle of the stylus. */
+} ANGLE16, FAR *P_ANGLE16;
+#define ANGLE16_SIZE (S16_SIZE+S16_SIZE)
+
+typedef struct tag_SIZE32 {
+ S32 w;
+ S32 h;
+} SIZE32, FAR *P_SIZE32;
+#define SIZE32_SIZE (S32_SIZE+S32_SIZE)
+
+typedef struct tag_SIZE16 {
+ S16 w;
+ S16 h;
+} SIZE16, FAR *P_SIZE16;
+#define SIZE16_SIZE (S16_SIZE+S16_SIZE)
+
+/*-------------------------------------------------------------------------
+** Note:
+** A rect where xmin==xmax and ymin==ymax has a size of zero:
+** size.w and size.h are both zero.
+**-------------------------------------------------------------------------*/
+
+typedef struct tag_RECT32 {
+ XY32 origin;
+ SIZE32 size;
+} RECT32, FAR *P_RECT32;
+#define RECT32_SIZE (XY32_SIZE+SIZE32_SIZE)
+
+typedef U32 FIXED_FRACTION; /* fixed point value, unity = 0x00010000 */
+#define FIXED_FRACTION_SIZE U32_SIZE
+
+#define INK_UNITY_SCALE ((U32) 0x00010000L)
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 3.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** A block of ink data is called an ink bundle. Each ink bundle consists of
+** a series of n records. Each record has a common header that indicates the
+** record type and the record length. An ink bundle always starts with an
+** INK_BUNDLE_RECORD and always ends with an INK_END_RECORD.
+**
+** Any records of unknown type can be skipped by simply reading the length of
+** the record.
+**
+** Note:
+** Within an ink bundle, time increases. This implies a drawing order of
+** back-to-front. Between adjacent sequential bundles, the implicit drawing
+** is also back-to-front.
+**
+** A number of record types are defined. The most common is the
+** inkRecordPenData which contains the actual pen data. Other records are
+** mostly attributes of the pen data and are optional. They will, in
+** general, only be present when a given attribute changes to something
+** different than the default value for that attribute.
+**
+** In order to have the most compact format and also allow large records,
+** several different record headers are defined, each with a different
+** length.
+**
+** The top two bits of the record type indicate what kind of record length
+** follows:
+**
+** The record length can be:
+**
+** - non-existent (the entire record consists of just the recordType)
+** - An 8 bit length (one byte) for records up to 255 bytes
+** - A 16 bit length (two bytes) for records up to 64k
+** - A 32 bit length (four bytes) for really big records
+**
+**------------------------------------------------------------------------*/
+
+#define inkRecordNoLength 0 /* no length, just recordType */
+#define inkRecordLength8 flag14 /* 8 bit length */
+#define inkRecordLength16 flag15 /* 16 bit length */
+#define inkRecordLength32 (flag15 | flag14) /* 32 bit length */
+
+/* useful defines for isolating or clearing the length type bits */
+#define inkRecordLengthMask (flag15 | flag14) /* mask for length bits */
+#define inkRecordLengthClearMask (~inkRecordLengthMask)
+
+/* some useful macros for declaring the various types of record types */
+#define MakeRec0(recType) (recType | inkRecordNoLength) /* no rec length */
+#define MakeRec8(recType) (recType | inkRecordLength8) /* 8 bit length */
+#define MakeRec16(recType) (recType | inkRecordLength16) /* 16 bit length */
+#define MakeRec32(recType) (recType | inkRecordLength32) /* 32 bit length */
+
+typedef U16 INK_RECORD_TYPE, FAR *P_INK_RECORD_TYPE;
+#define INK_RECORD_TYPE_SIZE U16_SIZE
+
+#define inkRecordHeaderLength(record_type) \
+ ( (((record_type) & inkRecordLength32) == inkRecordNoLength) ?\
+ INK_RECORD_TYPE_SIZE \
+ : (((record_type) & inkRecordLength32) == inkRecordLength8) ?\
+ INK_RECORD_TYPE_SIZE+U8_SIZE \
+ : (((record_type) & inkRecordLength32) == inkRecordLength16) ?\
+ INK_RECORD_TYPE_SIZE+U16_SIZE \
+ : INK_RECORD_TYPE_SIZE+U32_SIZE \
+ )
+
+/*-------------------------------------------------------------------------
+** Note: most compilers will not generate code for the above macro but will
+** determine the proper value at compile time.
+**-------------------------------------------------------------------------*/
+
+
+/*************************/
+/* REFERENCE SECTION 4.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** These are all the currently defined record types. The macro MakeRecX()
+** encodes the right bits in with the record Id to define its recordLength.
+**
+** For simplicity, recType values may not be repeated for different
+** INK_RECORD_TYPEs. Use of a record type defined as MakeRec32(63) thus
+** forbids the use of a record type defined as MakeRec16(63), MakeRec8(63),
+** or MakeRec0(63).
+**
+** Record type 63 is reserved explicitly for possible future extension beyond
+** 63 record types.
+**
+**------------------------------------------------------------------------*/
+
+#define inkRecordEnd MakeRec0( 0) /* end of bundle */
+#define inkRecordBundle MakeRec8( 1)
+#define inkRecordPenData MakeRec32( 2)
+#define inkRecordScale MakeRec8( 3)
+#define inkRecordScaleReset MakeRec0( 4)
+#define inkRecordColor MakeRec8( 5)
+#define inkRecordTip MakeRec8( 6)
+#define inkRecordGroup MakeRec8( 7)
+#define inkRecordOffset MakeRec8( 8)
+#define inkRecordStartTime MakeRec8( 9)
+#define inkRecordEndTime MakeRec8( 10)
+#define inkRecordPointsPerSecond MakeRec8( 11)
+#define inkRecordUnitsPerZ MakeRec8( 12)
+#define inkRecordUnitsPerForce MakeRec8( 13)
+
+/* Record types 14 .. 61 are reserved for future definition. */
+
+#define inkRecordApp MakeRec32(62) /* application-specific records*/
+#define inkRecordExt MakeRec32(63) /* reserved for extension */
+
+/*-------------------------------------------------------------------------
+** Every record starts with a header that contains the recordType and the
+** recordLength. The recordType indicates the type of data here. The
+** recordLength indicates the total length of all the data for the record
+** (including the size of the header).
+**-------------------------------------------------------------------------*/
+
+/* no recordLength */
+typedef struct tag_INK_RECORD_HEADER0 {
+ INK_RECORD_TYPE recordType;
+} INK_RECORD_HEADER0, FAR *P_INK_RECORD_HEADER0;
+
+/* 8 bit recordLength */
+typedef struct tag_INK_RECORD_HEADER8 {
+ INK_RECORD_TYPE recordType;
+ U8 recordLength;
+} INK_RECORD_HEADER8, FAR *P_INK_RECORD_HEADER8;
+
+/* 16 bit recordLength */
+typedef struct tag_INK_RECORD_HEADER16 {
+ INK_RECORD_TYPE recordType;
+ U16 recordLength;
+} INK_RECORD_HEADER16, FAR *P_INK_RECORD_HEADER16;
+
+/* 32 bit recordLength */
+typedef struct tag_INK_RECORD_HEADER32 {
+ INK_RECORD_TYPE recordType;
+ U32 recordLength;
+} INK_RECORD_HEADER32, FAR *P_INK_RECORD_HEADER32;
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 5.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** A bundle of ink consists of an INK_BUNDLE_RECORD, a series of records,
+** terminated with an INK_END_RECORD.
+**
+** An INK_BUNDLE_RECORD, along with a matching INK_END_RECORD, are the
+** mandatory records in the format. The ink data must start with an
+** INK_BUNDLE_RECORD.
+**
+** It is suggested that anyone reading this format do a number of validity
+** checks on the first record in any ink data. The first record should meet
+** the following minimum requirements:
+**
+** 1) header.recordType == INK_RECORD_BUNDLE
+** 2) header.recordLength >= inkRecordBundleSize (See general notes in
+** reference section 1.0 for important information about record sizes.)
+** 3) compactionType is an expected and supported value
+** 4) penUnitsPerX and penUnitsPerY seem reasonable and expected:
+** greater than, say, 1000 units per meter (25.4/inch), less than, say,
+** 400,000 (~10,000 units per inch)
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_END_RECORD {
+ INK_RECORD_HEADER0 header; /* value is inkRecordEnd */
+} INK_END_RECORD, FAR *P_INK_END_RECORD;
+#define inkRecordEndSize (inkRecordHeaderLength(inkRecordEnd))
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 6.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** The terms compression and compaction are used somewhat interchangeably
+** in this specification but they actually have slightly different meanings
+** and are both supported to a certain extent by Jot.
+**
+** Compression refers to a technique of encoding data such that the resuling
+** data, while smaller, is still whole. That is, compression under Jot is
+** loss-less. Compaction refers to a process where certain pieces of less
+** important data are actually omitted from the stream and are possibly
+** reconstructed by the reader of the data.
+**
+** Using Jot, a writing application may choose to compress only, compact only
+** or use some combination. The standard compression mechanism defined here
+** and implemented in the sample code supports both notions.
+**
+**------------------------------------------------------------------------*/
+
+typedef U8 INK_COMPACTION_TYPE, FAR *P_INK_COMPACTION_TYPE;
+#define INK_COMPACTION_TYPE_SIZE U8_SIZE
+#define inkNoCompression (0)
+#define inkStdCompression (1)
+
+/*-------------------------------------------------------------------------
+** Other compression schemes may be adopted in future revisions of this
+** specification.
+**-------------------------------------------------------------------------*/
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 7.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** The INK_BUNDLE_FLAGS contain some flags that apply to an entire bundle.
+** If you wanted to store several pieces of ink that had different
+** INK_BUNDLE_FLAGS, you would do it by storing several different bundles.
+**
+** Advisory flags:
+**
+** inkPointsRemoved
+** Indicates whether all original points are still present or whether
+** some points were removed to save space. For applications that are
+** only interested in the visual aspects of ink, many points can be
+** removed that do not affect the appearance (i.e. duplicate points,
+** collinear points, points which deviate less than some screen
+** resolution, etc..). Some other types of applications must know that
+** points are present at some consistent sampling rate (i.e. some forms
+** of handwriting translation). This flag indicates whether all
+** original points are still there.
+**
+** Note:
+** The purpose of "inkPointsRemoved" is to indicate that the timing
+** information cannot be accurately derived by counting points:
+** replacing individual points with an "elided point" item does not
+** constitute removing points. ("Elided" means omitted or skipped).
+**
+** inkProxDataRemoved
+** Indicates that the original points between strokes (proximity) were
+** removed to save space. An out-of-prox point should be stored between
+** strokes to delimit them. Some applications depend on knowing the
+** time between strokes or at the ends of strokes for certain
+** functions.
+**
+** Note:
+** "Proximity" is defined as the stylus being close enough to the tablet
+** for the tablet to report the stylus position, although perhaps at
+** lower accuracy and perhaps at a lower number of points per second. A
+** recommended practice is to include "out of proximity" points in the
+** recorded ink data when they are used as part of determining the
+** amount of time a stylus was out of contact with the tablet, or for
+** triggering the completion of an action such as a "gesture".
+**
+** inkStrokeLimitsPresent
+** Indicates that INK_BUTTONS items are also present, and that they
+** indicate what the storing app decided the stroke start/end points
+** were. (Note: the reading application may otherwise use a different
+** algorithm for using tip force values to delimit strokes.)
+**
+** Note:
+** If inkStrokeLimitsPresent is set, then inkButtonDataPresent must also
+** be set.
+**
+** Data flags:
+**
+** inkAngleDataPresent indicates angle data is present.
+** inkForceDataPresent indicates force data is present.
+** inkProxDataPresent indicates points are present when pen is lifted
+** up (i.e. the force drops below some threshold).
+** inkRotationDataPresent indicates pen rotation data is present.
+** inkHeightDataPresent indicates pen height data is present.
+** inkButtonDataPresent indicates "button state" information is present.
+** inkPreMultiplyScale indicates that scaling should be applied before
+** the offset value is added ("pre-multiply")
+** rather than after ("post-multiply")
+**
+** Note:
+** A previous draft version included a provision for compacting data to an
+** approximation based on Bezier curves. Initial results did not show
+** promise in terms of efficiency and performance.
+**
+** "inkBezierRepresentation" would have indicated that the X/Y ordinates
+** reflected a Bezier approximation to the original tablet data. This would
+** have meant that the ordinate data represented aggregates of anchor points
+** and control points for each piece wise approximation, and therefore could
+** not be used directly to render the data. The definition of these anchor
+** and control points, and the example code for the approximation and
+** regeneration of the "true" coordinates could not be worked out at this
+** time.
+**
+** Some standard values for pen units per meter follow:
+**
+** 1000 points per inch digitizer == 39370 pen units per meter
+** 500 points per inch digitizer == 19685 pen units per meter
+** 200 points per inch digitizer == 7874 pen units per meter
+** 254 points per inch (1/10 mm) == 10000 pen units per meter
+**
+** 1000 pen units per meter is a reasonable minimum; 400,000 is a reasonable
+** maximum value.
+**
+** The specific format for each of these types of data is described in the
+** INK_PENDATA_RECORD documentation (reference section 8.0).
+**
+** Note:
+** The order in which these flags are defined has nothing to do with the
+** order in which the data appears in the INK_POINT structure when reading
+** or writing point data. For more information, see reference section 21.0.
+**
+**------------------------------------------------------------------------*/
+
+typedef U16 INK_BUNDLE_FLAGS, FAR *P_INK_BUNDLE_FLAGS;
+#define INK_BUNDLE_FLAGS_SIZE U16_SIZE
+#define inkPointsRemoved (flag0)
+#define inkProxDataRemoved (flag1)
+#define inkAngleDataPresent (flag2)
+#define inkForceDataPresent (flag3)
+#define inkRotationDataPresent (flag4)
+#define inkHeightDataPresent (flag5)
+#define inkButtonDataPresent (flag6)
+#define inkStrokeLimitsPresent (flag7)
+#define inkPreMultiplyScale (flag8)
+
+/*-------------------------------------------------------------------------
+** Reserved: flag9, flag10, flag11, flag12, flag13, flag14, flag15.
+** More flags beyond flag15 can be added in a new record type
+** in a later revision to this specification.
+**-------------------------------------------------------------------------*/
+
+
+typedef struct tag_INK_BUNDLE_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordBundle */
+ U8 version; /* Value for release 1.0 is 1 */
+ INK_COMPACTION_TYPE compactionType;
+ INK_BUNDLE_FLAGS flags; /* flags for the whole bundle */
+ U32 penUnitsPerX; /* pen units per meter (x dir) */
+ U32 penUnitsPerY; /* pen units per meter (y dir) */
+} INK_BUNDLE_RECORD, FAR *P_INK_BUNDLE_RECORD;
+
+#define inkPointDefaultVersion (1)
+#define inkPointDefaultCompactionType (inkStdCompression)
+#define inkPointDefaultBundleFlags (0)
+#define inkPointDefaultPenUnitsPerX (1000)
+#define inkPointDefaultPenUnitsPerY (1000)
+
+#define inkRecordBundleSize \
+ (inkRecordHeaderLength(inkRecordBundle) + U8_SIZE + \
+ INK_COMPACTION_TYPE_SIZE + INK_BUNDLE_FLAGS_SIZE + \
+ U32_SIZE + U32_SIZE)
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 8.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** A penData record contains the actual pen data for one or more pen strokes.
+** The bounds applies to all the strokes contained within this record.
+** Multiple strokes are typically grouped into one record to increase the
+** efficiency of the compression algorithm, though strokes may be stored
+** individually, if desired.
+**
+** The bounds is the pure mathematical bounds of the raw pen points and does
+** not take into account any rendering information such as the pen tip or the
+** line width. All points in the INK_PENDATA have been normalized relative
+** to the lower bounds in the INK_PENDATA header.
+**
+** Some applications will prefer to know the bounds of individual strokes.
+** This can be accomplished in two ways.
+**
+** 1) The bounds for a given stroke can be computed when reading the file
+** by decompressing an INK_PENDATA_RECORD into its strokes and then
+** traversing the points in each stroke to build the bounds for each
+** stroke.
+**
+** 2) An application can decide to store only one stroke per
+** INK_PENDATA_RECORD (and thus the bounds of the PENDATA_RECORD is
+** already the bounds of one stroke). The sacrifice here is in
+** compression efficiency and the need to still support reading files
+** written by other applications that might group multiple strokes
+** into a single INK_PENDATA_RECORD.
+**
+** Note:
+** In practice, our experience is that unpacking the data in order to compute
+** the bounds for each stroke to check for strokes that intrude into a given
+** region is not an excessive burden. The checks that would have been done
+** on the bounds of each stroke can be done on the builds for each penData
+** group, and not all strokes must be checked individually.
+**
+** The format of the pen data is determined by the settings for
+** compactionType and flags in the INK_BUNDLE_RECORD structure, and
+** is described later in this file. Two formats are currently defined:
+** an uncompacted format and a delta-encoded compacted format, both with
+** optional components present or absent depending on the state of the flags
+** in the INK_BUNDLE_RECORD.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_PENDATA_RECORD {
+ INK_RECORD_HEADER32 header; /* value is inkRecordPenData */
+ RECT32 bounds;
+ U8 inkData[1]; /* ink data goes here: definitions */
+ /* follow later in this file. */
+} INK_PENDATA_RECORD, FAR *P_INK_PENDATA_RECORD;
+#define inkRecordPenDataSize(data_length) \
+ (inkRecordHeaderLength(inkRecordPenData) + RECT32_SIZE + (data_length))
+
+
+
+
+/*************************/
+/* REFERENCE SECTION 9.0 */
+/*************************/
+
+/*-------------------------------------------------------------------------
+** Ink scale is recorded in two fixed point values. A unity scale (scale
+** of one) is represented as 0x00010000, a scale of 0.5 as 0x00008000.
+**
+** Note:
+** All ink is located relative to the lower-left (0,0) corner of a logical
+** page or window. Scale and offset operations are cumulative, much in the
+** same way as in PostScript. One begins with a normalized graphics state
+** and sequentially applies the scale and offset operations to that matrix.
+** The INK_SCALE_RESET record returns the graphics state to its default state
+** (i.e., the transformation matrix is set to an identity matrix and the
+** offset is reset to the default of 0). By default, scaling is applied
+** after adding in any offset specified in an INK_OFFSET_RECORD. If the ink
+** bundle has the inkPreMultiplyScale bit set, for all ink in that bundle
+** scaling is applied before adding in any offset.
+**
+** As used in this format, ink scale and offset values are set by the storing
+** application, to be applied by the rendering application. If the storing
+** application collected the ink at scales of (2.0,2.0), the storing
+** application should insert an INK_SCALE_RECORD with a scale of (0.5,0.5)
+** for the rendering application to multiply all ink X and Y coordinates by.
+**
+** It is the responsibility of the storing application to deal with any
+** effects from round-off or truncation error due to the limits of precision
+** in the FIXED_FRACTION values used in INK_SCALE_RECORDs.
+**
+** An ink scale record indicates a scale change that stays in effect until
+** another ink scale record is encountered. Ink scale values compound: if
+** the current scale is (2.0,2.0) and an INK_SCALE_RECORD is encountered with
+** scale of (2.0,3.0), the scale to be applied to ink then becomes(4.0,6.0).
+** In absence of any ink scale record, the default ink scale is unity. In
+** general, a typical usage pattern for an application that supports drawing
+** ink while zoomed at scale is to record a number of strokes at a given
+** scale, reset the scale with an INK_SCALE_RESET_RECORD (which resets both
+** the scale and the offset to the default values), then switch to another
+** scale, then record a number more strokes, and so on.
+**
+** Note:
+** The extension scaling and offset to the Z ordinate value is not defined in
+** this version of the specification. The extension to Z scaling and offset
+** in a "standard" record type (i.e. not an application-specific record) may
+** be addressed in the future.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_SCALE {
+ FIXED_FRACTION x; /* scale in the x direction */
+ FIXED_FRACTION y; /* scale in the y direction */
+} INK_SCALE, FAR *P_INK_SCALE;
+#define INK_SCALE_SIZE (FIXED_FRACTION_SIZE+FIXED_FRACTION_SIZE)
+
+#define inkPointDefaultScale (INK_UNITY_SCALE) /* Unity. */
+
+typedef struct tag_INK_SCALE_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordScale */
+ INK_SCALE scale;
+} INK_SCALE_RECORD, FAR *P_INK_SCALE_RECORD;
+#define inkRecordScaleSize \
+ (inkRecordHeaderLength(inkRecordScale) + \
+ FIXED_FRACTION_SIZE + FIXED_FRACTION_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 10.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** The offset position is used to relocate ink data, after scaling. For
+** example, in a forms application, ink in a sketch field is drawn relative
+** to a given sketch field in the form. The location of this original field
+** is important to know so we know how the ink in this bundle relates to its
+** original field. If we wanted to move this ink to another field (i.e.
+** cut/paste or move), we would need to know the location of the original
+** field so we could render the ink in the new field in a manner consistent
+** with how it was drawn relative to its original field (i.e. a similar
+** baseline for a hand-written signature).
+**
+** This record is optional. If it exists, it will then apply to all
+** following pen data in the file. If it is not present it is assumed that
+** no information of this type is relevant. For example, while field ink
+** would have an offset position, markup ink over an entire form would not
+** have a offset position (or would have an offset position of (0,0) and a
+** scale of (1,1)) because it is relative to the entire form coordinate
+** system, not relative to some piece in the form.
+**
+** Note:
+** This approach allows a reader to "blindly" apply the scale and offset
+** values specified to ink data, and puts the burden for computing
+** compounding of multiple zoom levels, etc., on the writing application.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_OFFSET_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordOffset */
+ XY32 positionOffset; /* values are in pen units */
+} INK_OFFSET_RECORD, FAR *P_INK_OFFSET_RECORD;
+
+#define inkRecordOffsetSize \
+ (inkRecordHeaderLength(inkRecordOffset) + XY32_SIZE)
+
+#define inkPointDefaultOffset ((S32) 0) /* No offset. */
+
+
+typedef struct tag_INK_SCALE_RESET_RECORD {
+ INK_RECORD_HEADER0 header; /* value is inkRecordScaleReset */
+} INK_SCALE_RESET_RECORD, FAR *P_INK_SCALE_RESET_RECORD;
+
+#define inkRecordScaleResetSize (inkRecordHeaderLength(inkRecordScaleReset))
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 11.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Ink color is represented as an rgb value, plus opacity.
+**
+** The default color is black (r,g,b,o) = (0,0,0,255). A color change
+** present in the file remains in effect until another color change.
+** Typically, the color will stay the same for many ink strokes and thus
+** a color record will only be used occasionally when the color changes.
+**
+** "Opacity" is rather vaguely understood, especially in color environments.
+** In this context, opacity means the degree to which the display underneath
+** the ink shows through. An opacity value of 255 means that nothing under
+** the ink shows through; 0 means that everything shows through (the ink
+** is transparent). It is up to the reading application to define the
+** implementation of opacity on the reading platform.
+**
+** The color/opacity value of (255,255,255,0), or "transparent white" is
+** defined as an "erase" color. In inking applications that support a true
+** "erase" function, such as the ability to erase annotation ink on an
+** "original" document (perhaps a FAX image) the "erase" color restores the
+** background image where painted. The "background image" is defined by the
+** rendering application.
+**
+** Applications which do not support a true "erase" function may interpret
+** this as some other drawing function, such as drawing the "background"
+** color.
+**
+**------------------------------------------------------------------------*/
+
+typedef union {
+ U32 all;
+ struct {
+ U8 red,
+ green,
+ blue,
+ opacity; /* opaqueness: see defines below */
+ } rgb;
+} INK_COLOR, FAR *P_INK_COLOR;
+#define INK_COLOR_SIZE (U32_SIZE)
+
+typedef struct tag_INK_COLOR_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordColor */
+ INK_COLOR color;
+} INK_COLOR_RECORD, FAR *P_INK_COLOR_RECORD;
+#define inkRecordColorSize \
+ (inkRecordHeaderLength(inkRecordColor) + U32_SIZE)
+
+/*-------------------------------------------------------------------------
+** Standardized opacity values:
+** A recommended practice is that an opacity value of 128 (midway between
+** 0 and 255) be used for "highlighter" colors. A recommended practice is
+** that grey values as defined below be used for "standard grey"
+** highlighters.
+**-------------------------------------------------------------------------*/
+
+#define inkOpacityTransparent 0x00
+#define inkOpacityHighlight 0x80
+#define inkOpacityOpaque 0xFF
+
+/* Standard solid colors: */
+
+#define inkColorErase {0xFF,0xFF,0xFF,0x00}
+#define inkColorWhite {0xFF,0xFF,0xFF,0xFF}
+#define inkColorLtGrey {0x80,0x80,0x80,0xFF}
+#define inkColorDkGrey {0x40,0x40,0x40,0xFF}
+#define inkColorBlack {0x00,0x00,0x00,0xFF}
+
+/* Standard highlighter (transparent) colors: */
+
+#define inkColorLtGreyHighlight {0x80,0x80,0x80,0x80}
+#define inkColorDkGreyHighlight {0x40,0x40,0x40,0x80}
+
+#define inkDefaultColor ((INK_COLOR) inkColorBlack)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 12.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Time is measured in milliseconds.
+**
+** Note:
+** Because of the difficulty synchronizing clocks on different machines
+** at the time granularity of digitizing tablets, and because the "editing"
+** of ink at a later time makes the definition of the absolute time for each
+** ink point ambiguous, the base for the time is arbitrary. All times in
+** strokes are just relative to each other with no absolute time
+** relationship.
+**
+** These records, when encountered in the file, apply to the next stroke data
+** in the file (so this record comes before the penData that it applies to).
+** End time records are not required. The interpretation of an end time
+** which is in conflict with the end time inferred from the assumed data rate
+** of points and the number of points (including elided points) is not
+** defined.
+**
+** Start time is the time for the first point in the following penData record
+** and end time is the time of the last point in the following penData
+** record, because if you are recording tip force, the exact definition of
+** pen up and pen down may be fuzzy and/or application dependent.
+**
+**------------------------------------------------------------------------*/
+
+typedef U32 INK_TIME, FAR *P_INK_TIME; /* milliseconds */
+#define INK_TIME_SIZE U32_SIZE
+
+#define inkDefaultTime ((INK_TIME) 0)
+
+typedef struct tag_INK_START_TIME_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordStartTime */
+ INK_TIME startTime;
+} INK_START_TIME_RECORD, FAR *P_INK_START_TIME_RECORD;
+#define inkRecordStartTimeSize \
+ (inkRecordHeaderLength(inkRecordStartTime) + INK_TIME_SIZE)
+
+typedef struct tag_INK_END_TIME_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordEndTime */
+ INK_TIME endTime;
+} INK_END_TIME_RECORD, FAR *P_INK_END_TIME_RECORD;
+#define inkRecordEndTimeSize \
+ (inkRecordHeaderLength(inkRecordEndTime) + INK_TIME_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 13.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** INK_PENDATA_RECORDs can be grouped. If they are grouped, each
+** INK_PENDATA_RECORD can be assigned a group number. All
+** INK_PENDATA_RECORDs with the same group number belong to the same group.
+**
+** The exact interpretation of grouping is up the applications involved.
+** Writing applications may group ink data, but not all reading applications
+** that read the data may interpret grouping in the same way.
+**
+** For example, grouping could be used in the traditional fashion as in
+** drawing programs so the user moves or copies an entire group of
+** INK_PENDATA_RECORDs together. A group could also be used to signify a
+** series of INK_PENDATA_RECORDs entered by the user all within some criteria
+** (i.e. all during one proximity session or all within some time frame).
+**
+** Group numbers are simply signed 16 bit values and can be anything. They
+** do not need to be contiguous (i.e. they do not need to be 0,1,2). They
+** can be 12,49,-12345 if that is useful.
+**
+** This record can also be used as a simple marker for starting a new group
+** when the groupId is not really used: Group numbers of 0,0,0,0 ... are
+** thus permitted.
+**
+** INK_GROUPs are nestable. Group 0 is reserved as the end-of-group marker
+** for disjoint groups. If no end-of-group marker is encountered before the
+** end of the file or the end of all ink data (as indicated by an
+** INK_END_RECORD), all current (and possibly nested) groups are terminated
+** as if end-of-groups markers for them had been encountered.
+**
+**------------------------------------------------------------------------*/
+
+typedef S32 INK_GROUP, FAR *P_INK_GROUP;
+#define INK_GROUP_SIZE S32_SIZE
+
+typedef struct tag_INK_GROUP_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordGroup */
+ INK_GROUP groupId; /* application-specific interpretation */
+} INK_GROUP_RECORD, FAR *P_INK_GROUP_RECORD;
+
+#define inkDefaultGroup ((INK_GROUP) 0)
+
+#define inkRecordGroupSize \
+ (inkRecordHeaderLength(inkRecordGroup) + INK_GROUP_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 14.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Some applications may support the idea of rendering ink as if it were
+** drawn by a certain shaped pen tip. The most common pen tips would be
+** round or rectangular. The exact details of how to render a given pen
+** tip will be application specific, but this record states what pen tip
+** parameters were used by the storing app.
+**
+** Pen tips determine, in part, how ink is rendered. For pen tip types
+** defined in future versions of this format which require additional
+** parameters (such as the X and Y rectangle for a simulated nib pen, or
+** brush dimensions for a simulated brush), additional data is included
+** at the end of the structure.
+**
+** The writing application should be aware that the reading application will
+** only do "the best possible" job of rendering and that fully compliant
+** reading applications may not be able to render certain nib types and/or
+** colors. Both reading and writing applications should pay particular
+** attention to the following notes regarding defaults and ink drawn at a
+** width of zero.
+**
+** A pen tip which is drawing ink in zero width renders at the minimum
+** visible width the reading application will support.
+**
+** A recommended practice is that ink which should not render (should this
+** be called for) be drawn with a color value of (0,0,0, 0), i.e., black,
+** completely transparent.
+**
+** Pen tip size should scale when an INK_SCALE_RECORD is encountered. The
+** writing application should write a new INK_PENTIP_RECORD after an
+** INK_SCALE_RECORD if the writing application does not want the pen tip
+** size to scale along with the ink. If the pen tip scales to zero width,
+** it should be rendered by the reading application according to the comment
+** above.
+**
+** The default pen tip if no pentip record exists is INK_PENTIP_ROUND, with a
+** width of one twip. The dimensions of a round nib specify diameter, not
+** radius: the X/Y coordinate is the center of this diameter. Similarly, for
+** for rectangular nibs, the X/Y coordinate is the center of the rectangle.
+**
+** Note:
+** This specification does not specify information for an algorithmic
+** variation in nib width, ink color, or other "brush" effects as a function
+** of tip force, speed or any other factor. An example would be for an
+** application to draw wider ink as the user presses down harder with the
+** stylus. Applications wishing to implement such features may do so using
+** application-specific record types for this revision of the specification.
+**
+**------------------------------------------------------------------------*/
+
+typedef S16 INK_PENTIP, FAR *P_INK_PENTIP;
+#define INK_PENTIP_SIZE S16_SIZE
+#define INK_PENTIP_ROUND (0) /* Diameter in twips */
+#define INK_PENTIP_RECTANGLE (1) /* Dimensions in twips */
+#define INK_PENTIP_SLANT_RECTANGLE (2)
+#define INK_PENTIP_ROUND_FLAT_END (3)
+/* ... more to be filled in here if needed */
+
+#define inkDefaultPentip INK_PENTIP_ROUND
+#define inkDefaultPentipData ((U16) 1)
+
+typedef struct tag_INK_PENTIP_SLANT {
+ SIZE16 rectangle_size; /* INK_PENTIP_SLANTRECTANGLE */
+ U16 angle; /* Whole degrees from vertical, counter-clockwise */
+} INK_PENTIP_SLANT, FAR *P_INK_PENTIP_SLANT;
+
+typedef union {
+ U16 round_width; /* INK_PENTIP_ROUND */
+ SIZE16 rectangle_size; /* INK_PENTIP_RECTANGLE */
+ INK_PENTIP_SLANT slant; /* INK_PENTIP_SLANT_RECTANGLE */
+ U16 round_flat_width; /* INK_PENTIP_ROUND_FLAT_END */
+} INK_PENTIP_DATA, FAR *P_INK_PENTIP_DATA;
+
+/* Size of the union is determined by INK_PENTIP_SLANT */
+#define INK_PENTIP_DATA_SIZE (SIZE16_SIZE+U16_SIZE)
+
+typedef struct tag_INK_PENTIP_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordTip */
+ INK_PENTIP tip;
+ INK_PENTIP_DATA tip_data;
+} INK_PENTIP_RECORD, FAR *P_INK_PENTIP_RECORD;
+#define inkRecordTipSize \
+ (inkRecordHeaderLength(inkRecordTip) + INK_PENTIP_SIZE + \
+ SIZE16_SIZE + U16_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 15.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** For some applications, it will be important to know the sampling rate of
+** the pen digitizer.
+**
+** This record would likely be present once in a bundle and would typically
+** be after the INK_BUNDLE_RECORD, but before the first pen data.
+**
+** Note:
+** Writing applications are not required to report the "true" sampling rate
+** of the digitizer, nor are rendering applications required to play back the
+** ink at the specified rate. It is likely that most types of rendering
+** applications will render ink as rapidly as possible to construct a display
+** in minimum time, and that some types of animation applications will
+** intentionally set an arbitrary sampling rate to vary the display rate.
+**
+** Note:
+** For hardware which supports a highly variable sampling rate, the writing
+** application can simulate a very high sampling rate (say, 1000 points/
+** second), and use skip records for "elided" points to achieve an exact time
+** value (at 1-millisecond resolution) for each point.
+**
+** A default value for sampling rate has been arbitrarily defined below.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_POINTS_PER_SECOND_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordPointsPerSecond */
+ U16 pointsPerSecond;
+} INK_POINTS_PER_SECOND_RECORD, FAR *P_INK_POINTS_PER_SECOND_RECORD;
+
+#define inkPointDefaultPointsPerSecond (100)
+
+#define inkRecordPointsPerSecondSize \
+ (inkRecordHeaderLength(inkRecordPointsPerSecond) + U16_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 16.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Units for Z height of stylus above the tablet.
+**
+** This record would only be present once in a bundle and would typically be
+** after the INK_BUNDLE_RECORD, but before the first pen data.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_UNITS_PER_Z_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordUnitsPerZ */
+ U32 unitsPerZ; /* pen units per meter (Z height) */
+} INK_UNITS_PER_Z_RECORD, FAR *P_INK_UNITS_PER_Z_RECORD;
+
+#define inkPointDefaultUnitsPerZ (10000) /* 0.1 mm units */
+
+#define inkRecordUnitsPerZSize \
+ (inkRecordHeaderLength(inkRecordUnitsPerZ) + U32_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 17.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Units for stylus tip force.
+**
+** This record would only be present once in a bundle and would typically be
+** after the INK_BUNDLE_RECORD, but before the first pen data.
+**
+** Note:
+** This specification assumes some level of accuracy and linearity for tip
+** force data, if such data is present. However, since tip force sensors in
+** current digitizer tablet and stylus designs may well vary in accuracy and
+** linearity from one unit to the next even for hardware of the same design
+** and model, and since algorithms for using tip force to determine stroke
+** start and end are likely to differ, a recommended practice for writing
+** applications that use the tip force value to determine the "touch" points
+** in a stroke is to mark those points using the touch bit in the INK_BUTTONS
+** structure.
+**
+** It is also recommended that vendors supporting tip force sensing in their
+** hardware linearize their transducers to the greatest extent possible.
+**
+** Because of the likelihood that tip force transducers may not be accurately
+** linearized, negative tip force values, while perhaps somewhat absurd
+** are possible and are permitted in this specification.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_UNITS_PER_FORCE_RECORD {
+ INK_RECORD_HEADER8 header; /* value is inkRecordUnitsPerForce */
+ U32 unitsPerForce; /* tip-force units per k-gram of force*/
+} INK_UNITS_PER_FORCE_RECORD, FAR *P_INK_UNITS_PER_FORCE_RECORD;
+
+#define inkPointDefaultUnitsPerForce (1000) /* grams of force */
+
+#define inkRecordUnitsPerForceSize \
+ (inkRecordHeaderLength(inkRecordUnitsPerForce) + U32_SIZE)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 18.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** The INK_APP_RECORD record is a universal record to be used by individual
+** applications to put data into the file that is not supported by an
+** additional publicly defined record type. The basic idea is that an
+** application puts its own unique application signature into the appData
+** bytes in the INK_APP_RECORD. This identifies the data as originating with
+** a particular application. Then, an application defines a set of
+** subRecordTypes that they wish to use. Then, using these subRecordTypes
+** they can put a wide variety of information into the file. By examining
+** the appData signature and comparing it to theirs, an application can
+** decide whether it knows how to interpret the various subRecordtypes.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_APP_RECORD {
+ INK_RECORD_HEADER32 header; /* value is inkRecordApp */
+ U8 appSignature[8];/* reserved for possible unique */
+ /* application signature */
+ U16 subRecordType;
+ /* data here appropriate to the subRecordType and appData signature */
+} INK_APP_RECORD, FAR *P_INK_APP_RECORD;
+#define inkRecordAppSize(data_length) \
+ (inkRecordHeaderLength(inkRecordApp) + 8 + U16_SIZE + (data_length))
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 19.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Definition of the inkData components of an INK_PENDATA_RECORD:
+**
+** Uncompacted point format:
+** -------------------------
+**
+** This structure immediately follows the rest of the INK_PENDATA_RECORD.
+** The structure has several optional components, present or not present as
+** indicated by the INK_BUNDLE_FLAGS in the INK_BUNDLE_RECORD. The format is
+** a sequence of "point values", each containing all the scalar data for each
+** sampled tablet point.
+**
+** In the uncompacted format, there is a single structure that contains all
+** of the state information for each point from the tablet. Components not
+** present (as indicated by the INK_BUNDLE_FLAGS) are just that: not present,
+** do not exist, do not occupy space.
+**
+** Compacted point format:
+** -----------------------
+**
+** In the compacted format, "State values", such as the stylus state of
+** touch/no-touch/out-of-prox or the on/off state of the barrel switches, are
+** stored in a compacted "INK_BUTTONS" item (represented using reserved
+** encodings in the INK_POINT coordinate values) interjected when their state
+** changes. The initial state is assumed to be "not touching", "out of
+** proximity", all barrel switches "off". It is possible to have both tip
+** force data, and explicit starts and ends of strokes: the starts and ends
+** of the strokes are then points that were considered to be such by the
+** original application storing the data. The INK_BUTTONS record reflects
+** the state of the next X/Y point following.
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 20.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** "INK_BUTTONS" items may most often be used only to indicate stylus touch
+** and out-of-prox state, and perhaps a single barrel button. The format is
+** optimized for this case. The format extends to a total of 28 stylus/puck
+** buttons.
+**
+**------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+** The lowest-order bit (flag0) is "0" when the stylus is out of
+** proximity, "1" when it is in proximity.
+** Second lowest-order bit (flag1) is "1" to indicate the next inkPoints are
+** when the stylus is touching (the start of a stroke: tip-switch "on"),
+** "0" to indicate that the stylus is not touching (end of a stroke).
+** Third bit (flag2) indicates state of first (or only) barrel switch,
+** etc.
+** 31'st bit (flag30) is normally "0", "1" is indicates there are more
+** than 29 barrel/puck buttons with state, and the rest are in the next
+** four-byte word.
+**-------------------------------------------------------------------------*/
+
+typedef U32 INK_BUTTONS, FAR * P_INK_BUTTONS;
+
+/*-------------------------------------------------------------------------
+** These definitions hold the maximum and minimum values that
+** can be used with the S15 and S31 representations described in
+** this document:
+**-------------------------------------------------------------------------*/
+
+#define MAX_S31 ((S32) 0x3FFFFFFF)
+#define MIN_S31 ((S32) 0xC0000000)
+
+#define MAX_S15 ((S16) 0x3FFF)
+#define MIN_S15 ((S16) 0xC000)
+
+#define MAX_S7 ((S16) 0x003F)
+#define MIN_S7 ((S16) 0xFFC0)
+
+#define MAX_S3 ((S16) 0x0003)
+#define MIN_S3 ((S16) 0xFFFC)
+
+/* SignExtend4/8/16/32: Sign-extend an S3, S7, S15, S31 to an S32: */
+
+#define SignExtend4(value) ((S32) \
+ (((value)&0x00000004l)== 0 ? ((value)&0x00000007l) \
+ : (((value)&0x00000007l) | 0xFFFFFFF8l)))
+
+#define SignExtend8(value) ((S32) \
+ (((value)&0x00000040l)== 0 ? ((value)&0x0000007Fl) \
+ : (((value)&0x0000007Fl) | 0xFFFFFF80l)))
+
+#define SignExtend16(value) ((S32) \
+ (((value)&0x00004000l)== 0 ? ((value)&0x00007FFFl) \
+ : (((value)&0x00007FFFl) | 0xFFFF8000l)))
+
+#define SignExtend32(value) ((S32) \
+ (((value)&0x40000000l)== 0 ? ((value)&0x7FFFFFFFl) \
+ : (((value)&0x7FFFFFFFl) | 0x80000000l)))
+
+
+
+/**************************/
+/* REFERENCE SECTION 21.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** INK_POINT data. The INK_POINT structure varies in size depending on
+** flags set in the bundle header. The XY32 position is always present, but
+** the force, rho, height, angle, and buttons members are only present when
+** indicated by the corresponding flag in the bundle header. When optional
+** data is present, it is present in the order defined by this structure;
+** that is, position, force, height, rho, angle, and finally buttons.
+**
+** The INK_POINT structure has the following elements:
+**
+** position - required and always present
+** Positions are measured with (0,0) at the lower-left, X increasing to
+** the right, Y increasing upwards. Values are actually S31, not S32.
+** The high bit in X and Y must be zero.
+** force - optional, present if inkForceDataPresent is asserted
+** Units are in pen force units, zero is no contact.
+** height - optional, present if inkHeightDataPresent is asserted
+** Units are in pen unitsPerZ as specified by inkPointDefaultUnitsPerZ or
+** by an INK_UNITS_PER_Z_RECORD, whichever is appropriate. Units increase
+** as the stylus is taken away from the tablet. Zero means "just in
+** contact". Negative values could possibly result from spring action if
+** the stylus is pressed hard, or if the tablet is not perfectly accurate.
+** rho - optional, present if inkRotationDataPresent is asserted
+** Angles are measured in degrees from some nominal orientation of
+** "stylus button on top" (somewhat arbitrary). Angles increase with
+** clockwise rotation as seen from the rear end of the stylus.
+** angle - optional, present if inkAngleDataPresent is asserted
+** Angles are measured in pen angle units from the vertical. Theta
+** increases in the positive-X direction, phi in the positive-Y.
+** buttons - optional, present if inkButtonDataPresent is asserted
+**
+** When the INK_BUNDLE_RECORD member compactionType is inkStdCompression,
+** all data in this structure is compressed according to the methods
+** described in reference section 23.0. For more details on how to interpret
+** the compressed data stream, see the sample code. The bundle flags which
+** indicate whether a particular piece of data is present are used regardless
+** of whether the data is compressed or not. Note that when data is written
+** in compressed format, it is NOT written in Intel order but rather most
+** significant byte first. In compressed form, some of the eight bit delta
+** values are reserved for button data and elided (skipped) point counts.
+** This has two important ramifications. 1) When expecting a point,
+** compacted button data or elided point data may be encountered instead, and
+** 2) when the inkButtonDataPresent flag is asserted in the bundle header,
+** button data will appear in the place of a point and not in addition to a
+** point. If inkButtonDataPresent is not asserted, the reader need not check
+** the point data for the special case of button data; however, the point
+** data must still be checked to see if it is a count of elided points rather
+** than an actual point.
+**
+**------------------------------------------------------------------------*/
+
+typedef struct tag_INK_POINT {
+ XY32 position; /* required x/y point data */
+ S16 force; /* optional force data */
+ S16 height; /* optional z height data */
+ S16 rho; /* optional rotational data */
+ ANGLE16 angle; /* optional theta and phi data */
+ INK_BUTTONS buttons; /* optional proximity, contact, button data */
+} INK_POINT, FAR *P_INK_POINT;
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 22.0 */
+/**************************/
+
+
+/*-------------------------------------------------------------------------
+** The following default values are assumed before the start of any
+** INK_BUNDLE:
+**
+**------------------------------------------------------------------------*/
+
+
+#define inkPointDefaultXYPosition ((S32) 0)
+#define inkPointDefaultForce ((S16) 0)
+#define inkPointDefaultHeight ((S16) 0)
+#define inkPointDefaultRho ((S16) 0)
+#define inkPointDefaultAngle ((S16) 0)
+#define inkPointDefaultButtons ((U32) 0)
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 23.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Compacted point format:
+** ---------------------
+**
+** A recommended practice is always to use the compacted point format, not
+** the uncompacted point format. Sample code for reading and writing the
+** compacted format is included in an appendix.
+**
+** This structure also immediately follows the rest of the
+** INK_PENDATA_RECORD.
+**
+** The uncompacted values above are stored in sequential bytes in a more
+** compact, delta-oriented format. Deltas are all signed values, a value to
+** add to the previous value. The first point in an INK_PENDATA_RECORD is
+** always relative to the defined default values for each component of the
+** point.
+**
+** The storing application, as an alternative to eliminating points, can
+** specify a "skip" record for elided points. The skipRecord indicates that
+** a number of points were skipped, and the reading application is free to
+** insert values for the elided points (interpolating where appropriate).
+** The intent is to allow for accurate time information to be maintained
+** between time stamps for synchronization with recorded voice, press-hold
+** gesture recognition, etc.
+**
+** Compacted data is written most significant byte first so that reading
+** applications can read the first byte and determine (from the top two bits)
+** how large the encoded delta is.
+**
+** Note:
+** "Reserved encodings" are those encodings that, if real points, would fit
+** into the next smaller delta size. 16 bit deltas and 8 bit deltas have
+** reserved encodings. The reserved encodings for 16 bit deltas are all 16
+** bit delta pairs where both X and Y are within the inclusive range MIN_S7
+** and MAX_S7. Similarly, the reserved encoding for 8 bit deltas are all 8
+** bit delta pairs where both X and Y are within the inclusive range MIN_S3
+** and MAX_S3. In revision 1.0 of Jot, three of the reserved encodings for 8
+** bit deltas are used for special cases: skip counts (reference section
+** 27.0) and button changes (reference section 26.0).
+**
+** x/y position:
+** ------------
+**
+** 32-bit absolute X/Y:
+**
+** Two 32 bit long words: Data is actually two S31s:
+**
+** |0|0| (30 low-order bits of X) |
+** ... Sign bit is taken from first bit of next word.
+** ----------------------------------------------------------------
+** |X| (sign bit of X plus 31 bits of Y) |
+** ----------------------------------------------------------------
+**
+** 16-bit short delta X/Y:
+**
+** Short words: two 16 bit words: Deltas are actually two S15s:
+** Values that would fit into an 8-bit byte delta are reserved.
+**
+** |0|1| (14 low-order bits of delta-X) |
+** ... Sign bit is taken from first bit of next word.
+** --------------------------------------------------
+** |X| (sign bit of X plus 15 bits of delta Y |
+** --------------------------------------------------
+**
+** 8-bit byte delta X/Y:
+**
+** Bytes: two bytes: Deltas are actually two S7s:
+** Values that would fit into a 4-bit nibble delta are reserved.
+**
+** |1|0| (6 low-order bits of delta-X) |
+** ... Sign bit is taken from first bit of next word.
+** ------------------------------------------
+** |X| (7 bits of delta-Y) |
+** ------------------------------------------
+**
+** 4-bit nibble delta X/Y:
+**
+** Nibbles: one byte: Deltas are actually S3:
+**
+** |1|1| (S3 delta-X) | (S3 delta-Y) |
+** -----------------------------------
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 24.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Tip force:
+** ----------
+**
+** 16-bit absolute force:
+**
+** Short word: one word: Value is actually S15:
+** Values that would fit into an 8-bit byte delta are reserved.
+**
+** |0| (15 bits of force) |
+** ---------------------------------------------
+**
+** 8-bit byte delta force:
+**
+** Byte: one byte: Deltas are actually S7:
+**
+** |1| (S7 delta-force) |
+** --------------------------
+**
+**
+** Height:
+** ------
+**
+** (Same encoding as tip force)
+**
+** Rho:
+** ---
+**
+** (Same encoding as tip force)
+**
+**
+** Stylus theta-phi:
+** ----------------
+**
+** 16-bit absolute theta-phi:
+**
+** Short words: two words: Data is actually S15:
+**
+** |0|0| (14 low-order bits of theta) |
+** -------------------------------------------
+** ... Sign bit is taken from first bit of next word.
+** |X| (15 bits of phi) |
+** -------------------------------------------
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 25.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** 8-bit byte delta theta-phi
+**
+** Bytes: two bytes: Deltas are actually S7:
+** Values that would fit into a 4-bit nibble delta are reserved.
+**
+** |0|1| (6 low-order bits of delta-theta)|
+** --------------------------------------------
+** ... Sign bit is taken from first bit of next word.
+** |X| (7 bits of delta-phi) |
+** --------------------------------------------
+**
+** 4-bit nibble delta theta-phi
+**
+** Nibbles: one byte: Deltas are actually S3:
+**
+** |1|0|(S3 delta-theta)|(S3 delta-phi)|
+** -------------------------------------
+**
+** Note:
+** Leading bit values of |1|1| are reserved
+**
+**------------------------------------------------------------------------*/
+
+
+
+
+/**************************/
+/* REFERENCE SECTION 26.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Since the X/Y data is always present, we use some of the reserved delta
+** encodings to encode button states and elided (skipped) points. We use the
+** 8-bit delta encodings that are unused: the values that can fit into the
+** smaller 4-bit delta encodings.
+**
+** Button/tip records:
+** ------------------
+**
+** It is assumed that the state of barrel buttons and the touching sensor on
+** the stylus change infrequently. A compacted button/tip record is only
+** included when the state changes in one of the switches. The button state
+** value applies to the X/Y point immediately following the button state
+** record.
+**
+**
+** (Taken from 8-bit byte delta X/Y: two bytes total)
+**
+** |1|0| 0|0|0|0|0|0/1| 0|X|.|.|.|.|X|X|
+** ---------------------------------------
+** (delta-X) (delta-Y)
+**
+** An eight-bit delta with delta-X == 0 or 1, and delta-Y in the range
+** (-4..3) indicates a button state encoding.
+**
+** It is likely to be the case that many hardware platforms have only one
+** barrel button.
+**
+** The three delta-Y bits indicate the "touch", "out-of-prox", and "first
+** barrel button" state as follows:
+**
+** low-order delta-Y bit: 1 --> in proximity, 0 --> out of prox
+** next delta-Y bit: 1 --> touching tablet, 0 --> not touching
+** high-order (sign) delta-Y bit: 1 --> first button closed, 0 --> open
+**
+**
+** The lowest order bit of the delta-X bits is used to indicate that
+** additional bytes follow: "1" indicates that the next byte is used for the
+** next 7 barrel buttons with state. The high order bit of each sequential
+** byte in the series is "1" if an additional byte must be fetched, "0"
+** otherwise. In these additional bytes, the additional buttons are
+** associated in order starting with the low-order bit.
+**
+**------------------------------------------------------------------------*/
+
+
+
+/**************************/
+/* REFERENCE SECTION 27.0 */
+/**************************/
+
+/*-------------------------------------------------------------------------
+** Skipped-point records:
+** ---------------------
+**
+** (Taken from 8-bit byte delta X/Y: two bytes total)
+**
+**
+** |1|0| 0|0|0|0|1|0| 0|X|.|.|.|.|X|X|
+** -------------------------------------
+** (delta-X) (delta-Y)
+**
+** An eight-bit delta with delta-X == 2, and delta-Y in the range
+** (-4..3) indicates a count of elided points. The delta-Y values in the
+** range (-4..-1) are used to represent skip counts of (4..7). If the
+** delta-Y value is zero "0", the next two bytes are fetched to get a U16
+** skip count value.
+**
+** The elided points are points removed between the point immediately prior
+** to the skipped-point record and the point immediately afterward. This
+** implies that at least one point must follow every skip record (though
+** the point may not appear next in the stream if there are intervening
+** button state transitions). Reading applications that are interested in
+** recovering elided points will typically interpolate. Skip counts of zero
+** are meaningless and not permitted.
+**
+** Reserved:
+** --------
+**
+** The remaining encodings from the 8-bit byte delta X/Y are reserved:
+**
+** delta-X of -4, -3, -2, -1, 3 AND ((delta-Y >= -4) & ((delta-Y <= 3))
+**
+**------------------------------------------------------------------------*/
+
+#endif /* end of INKSTORE_INCLUDED */
diff --git a/vendor/x11iraf/obm/ObmW/laygram.y b/vendor/x11iraf/obm/ObmW/laygram.y
new file mode 100644
index 00000000..c209b64a
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/laygram.y
@@ -0,0 +1,263 @@
+%{
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Misc.h>
+#include <X11/Xmu/Converters.h>
+#include "LayoutP.h"
+
+static LayoutPtr *dest;
+
+%}
+
+%union {
+ int ival;
+ XrmQuark qval;
+ BoxPtr bval;
+ BoxParamsPtr pval;
+ GlueRec gval;
+ LayoutDirection lval;
+ ExprPtr eval;
+ Operator oval;
+}
+
+%type <bval> box boxes compositebox
+%type <pval> bothparams oneparams
+%type <gval> glue opStretch opShrink
+%type <lval> orientation
+%type <eval> signedExpr simpleExpr expr
+
+%token OC CC OA CA OP CP
+%token <qval> NAME
+%token <ival> NUMBER
+%token <ival> INFINITY
+%token VERTICAL HORIZONTAL
+
+%token EQUAL DOLLAR
+
+%left <oval> PLUS MINUS
+%left <oval> TIMES DIVIDE PERCENTOF
+%right <oval> PERCENT
+%nonassoc WIDTH HEIGHT
+%right <oval> UMINUS UPLUS
+
+%%
+layout : compositebox
+ { *dest = $1; }
+ ;
+box : NAME bothparams
+ {
+ BoxPtr box = New(LBoxRec);
+ box->nextSibling = 0;
+ box->type = WidgetBox;
+ box->params = *$2;
+ Dispose ($2);
+ box->u.widget.quark = $1;
+ $$ = box;
+ }
+ | signedExpr oneparams
+ {
+ BoxPtr box = New(LBoxRec);
+ box->nextSibling = 0;
+ box->type = GlueBox;
+ box->params = *$2;
+ Dispose ($2);
+ box->u.glue.expr = $1;
+ $$ = box;
+ }
+ | NAME EQUAL signedExpr
+ {
+ BoxPtr box = New(LBoxRec);
+ box->nextSibling = 0;
+ box->type = VariableBox;
+ box->u.variable.quark = $1;
+ box->u.variable.expr = $3;
+ $$ = box;
+ }
+ | compositebox
+ {
+ $$ = $1;
+ }
+ ;
+compositebox : orientation OC boxes CC
+ {
+ BoxPtr box = New(LBoxRec);
+ BoxPtr child;
+
+ box->nextSibling = 0;
+ box->parent = 0;
+ box->type = BoxBox;
+ box->u.box.dir = $1;
+ box->u.box.firstChild = $3;
+ for (child = $3; child; child = child->nextSibling)
+ {
+ if (child->type == GlueBox)
+ {
+ child->params.stretch[!$1].expr = 0;
+ child->params.shrink[!$1].expr = 0;
+ child->params.stretch[!$1].order = 100000;
+ child->params.shrink[!$1].order = 100000;
+ child->params.stretch[!$1].value = 1;
+ child->params.shrink[!$1].value = 1;
+ }
+ child->parent = box;
+ }
+ $$ = box;
+ }
+ ;
+boxes : box boxes
+ {
+ $1->nextSibling = $2;
+ $$ = $1;
+ }
+ | box
+ { $$ = $1; }
+ ;
+bothparams : OA opStretch opShrink TIMES opStretch opShrink CA
+ {
+ BoxParamsPtr p = New(BoxParamsRec);
+
+ p->stretch[LayoutHorizontal] = $2;
+ p->shrink[LayoutHorizontal] = $3;
+ p->stretch[LayoutVertical] = $5;
+ p->shrink[LayoutVertical] = $6;
+ $$ = p;
+ }
+ |
+ {
+ BoxParamsPtr p = New(BoxParamsRec);
+
+ ZeroGlue (p->stretch[LayoutHorizontal]);
+ ZeroGlue (p->shrink[LayoutHorizontal]);
+ ZeroGlue (p->stretch[LayoutVertical]);
+ ZeroGlue (p->shrink[LayoutVertical]);
+ $$ = p;
+ }
+ ;
+oneparams : OA opStretch opShrink CA
+ {
+ BoxParamsPtr p = New(BoxParamsRec);
+
+ p->stretch[LayoutHorizontal] = $2;
+ p->shrink[LayoutHorizontal] = $3;
+ p->stretch[LayoutVertical] = $2;
+ p->shrink[LayoutVertical] = $3;
+ $$ = p;
+ }
+ |
+ {
+ BoxParamsPtr p = New(BoxParamsRec);
+
+ ZeroGlue (p->stretch[LayoutHorizontal]);
+ ZeroGlue (p->shrink[LayoutHorizontal]);
+ ZeroGlue (p->stretch[LayoutVertical]);
+ ZeroGlue (p->shrink[LayoutVertical]);
+ $$ = p;
+ }
+ ;
+opStretch : PLUS glue
+ { $$ = $2; }
+ |
+ { ZeroGlue ($$); }
+ ;
+opShrink : MINUS glue
+ { $$ = $2; }
+ |
+ { ZeroGlue ($$); }
+ ;
+glue : simpleExpr INFINITY
+ { $$.order = $2; $$.expr = $1; }
+ | simpleExpr
+ { $$.order = 0; $$.expr = $1; }
+ | INFINITY
+ { $$.order = $1; $$.expr = 0; $$.value = 1; }
+ ;
+signedExpr : MINUS simpleExpr %prec UMINUS
+ {
+ $$ = New(ExprRec);
+ $$->type = Unary;
+ $$->u.unary.op = $1;
+ $$->u.unary.down = $2;
+ }
+ | PLUS simpleExpr %prec UPLUS
+ { $$ = $2; }
+ | simpleExpr
+ ;
+simpleExpr : WIDTH NAME
+ { $$ = New(ExprRec);
+ $$->type = Width;
+ $$->u.width = $2;
+ }
+ | HEIGHT NAME
+ { $$ = New(ExprRec);
+ $$->type = Height;
+ $$->u.height = $2;
+ }
+ | OP expr CP
+ { $$ = $2; }
+ | simpleExpr PERCENT
+ {
+ $$ = New(ExprRec);
+ $$->type = Unary;
+ $$->u.unary.op = $2;
+ $$->u.unary.down = $1;
+ }
+ | NUMBER
+ { $$ = New(ExprRec);
+ $$->type = Constant;
+ $$->u.constant = $1;
+ }
+ | DOLLAR NAME
+ { $$ = New(ExprRec);
+ $$->type = Variable;
+ $$->u.variable = $2;
+ }
+ ;
+expr : expr PLUS expr
+ { binary: ;
+ $$ = New(ExprRec);
+ $$->type = Binary;
+ $$->u.binary.op = $2;
+ $$->u.binary.left = $1;
+ $$->u.binary.right = $3;
+ }
+ | expr MINUS expr
+ { goto binary; }
+ | expr TIMES expr
+ { goto binary; }
+ | expr DIVIDE expr
+ { goto binary; }
+ | expr PERCENTOF expr
+ { goto binary; }
+ | MINUS expr %prec UMINUS
+ { unary: ;
+ $$ = New(ExprRec);
+ $$->type = Unary;
+ $$->u.unary.op = $1;
+ $$->u.unary.down = $2;
+ }
+ | PLUS expr %prec UPLUS
+ { $$ = $2; }
+ | simpleExpr
+ ;
+orientation : VERTICAL
+ { $$ = LayoutVertical; }
+ | HORIZONTAL
+ { $$ = LayoutHorizontal; }
+ ;
+%%
+
+int yywrap ()
+{
+ return 1;
+}
+
+void yysetdest (c)
+ LayoutPtr *c;
+{
+ dest = c;
+}
diff --git a/vendor/x11iraf/obm/ObmW/laylex.l b/vendor/x11iraf/obm/ObmW/laylex.l
new file mode 100644
index 00000000..8764d066
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/laylex.l
@@ -0,0 +1,126 @@
+
+%{
+#ifndef FLEX_SCANNER
+#undef input
+#undef unput
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include "LayoutP.h"
+#include "laygram.h"
+static char *yysourcebase, *yysource;
+
+#ifndef FLEX_SCANNER
+#define input() (*yysource++)
+
+/* 18Mar94 DCT - The following doesn't work as the lex code assumes that (c) is
+ * evaluated.
+ *
+ * #define unput(c) (--yysource)
+ */
+#define unput(c) (--yysource, (c))
+
+#else
+#include <string.h>
+static void my_yyinput(char* buf, int* result, int max_size);
+#define YY_INPUT(buf, res, max) my_yyinput(buf, &(res), max);
+#endif
+
+#ifdef __STDC__
+static int count ();
+#endif
+%}
+%%
+vertical return VERTICAL;
+horizontal return HORIZONTAL;
+"{" return OC;
+"}" return CC;
+"(" return OP;
+")" return CP;
+"<" return OA;
+">" return CA;
+infinity { yylval.ival = 1; return INFINITY; }
+inff* { yylval.ival = count(yytext, 'f'); return INFINITY; }
+[0-9][0-9]* { yylval.ival = atoi(yytext); return NUMBER; }
+"=" { return EQUAL; }
+"$" { return DOLLAR; }
+"+" { yylval.oval = Plus; return PLUS; }
+"-" { yylval.oval = Minus; return MINUS; }
+"*" { yylval.oval = Times; return TIMES; }
+"/" { yylval.oval = Divide; return DIVIDE; }
+"%" { yylval.oval = Percent; return PERCENT; }
+%[ \t\n]*of { yylval.oval = Percent; return PERCENTOF; }
+width return WIDTH;
+height return HEIGHT;
+\\[a-zA-Z_][a-zA-Z0-9_]* {
+ /* yytext[yyleng] = '\0'; */
+ yylval.qval = XrmStringToQuark (yytext+1);
+ return NAME;
+ }
+
+[a-zA-Z_][a-zA-Z0-9_]* {
+ /* yytext[yyleng] = '\0'; */
+ yylval.qval = XrmStringToQuark (yytext);
+ return NAME;
+ }
+" " ;
+"\t" ;
+"\n" ;
+. fprintf (stderr, "ignoring %c\n", *yytext);
+%%
+
+static int
+count (s, c)
+ char *s;
+ char c;
+{
+ int i = 0;
+ while (*s)
+ if (*s++ == c)
+ i++;
+ return i;
+}
+
+yysetsource(s)
+ char *s;
+{
+ yysourcebase = yysource = s;
+}
+
+yyerror(s)
+ char *s;
+{
+ char *t;
+
+ fprintf (stderr, "%s\n", s);
+ t = yysource - 50;
+ if (t < yysourcebase)
+ t = yysourcebase;
+ while (*t && t < yysource + 50) {
+ if (t == yysource)
+ putc ('@', stderr);
+ putc (*t++, stderr);
+ }
+ if (t == yysource)
+ putc ('@', stderr);
+ if (!*t)
+ fprintf (stderr, "<EOF>");
+ fprintf (stderr, "\n");
+}
+
+#ifdef FLEX_SCANNER
+static void
+my_yyinput(buf, result, max_size)
+ char *buf; int *result; int max_size;
+{
+ int size = max_size < strlen(yysource) ? max_size : strlen(yysource);
+
+ strncpy(buf, yysource, size);
+ yysource += size;
+ *result = size;
+}
+#endif
diff --git a/vendor/x11iraf/obm/ObmW/laylex.l.ORIG b/vendor/x11iraf/obm/ObmW/laylex.l.ORIG
new file mode 100644
index 00000000..63cc87db
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/laylex.l.ORIG
@@ -0,0 +1,96 @@
+%{
+#undef input
+#undef unput
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include "LayoutP.h"
+#include "laygram.h"
+
+static char *yysourcebase, *yysource;
+static int count();
+
+#define input() (*yysource++)
+#define unput(c) (--yysource)
+
+%}
+%%
+vertical return VERTICAL;
+horizontal return HORIZONTAL;
+"{" return OC;
+"}" return CC;
+"(" return OP;
+")" return CP;
+"<" return OA;
+">" return CA;
+infinity { yylval.ival = 1; return INFINITY; }
+inff* { yylval.ival = count(yytext, 'f'); return INFINITY; }
+[0-9][0-9]* { yylval.ival = atoi(yytext); return NUMBER; }
+"=" { return EQUAL; }
+"$" { return DOLLAR; }
+"+" { yylval.oval = Plus; return PLUS; }
+"-" { yylval.oval = Minus; return MINUS; }
+"*" { yylval.oval = Times; return TIMES; }
+"/" { yylval.oval = Divide; return DIVIDE; }
+"%" { yylval.oval = Percent; return PERCENT; }
+%[ \t\n]*of { yylval.oval = Percent; return PERCENTOF; }
+width return WIDTH;
+height return HEIGHT;
+\\[a-zA-Z_][a-zA-Z0-9_]* {
+ /* yytext[yyleng - 1] = '\0'; */
+ yylval.qval = XrmStringToQuark (yytext+1);
+ return NAME;
+ }
+
+[a-zA-Z_][a-zA-Z0-9_]* {
+ /* yytext[yyleng - 1] = '\0'; */
+ yylval.qval = XrmStringToQuark (yytext);
+ return NAME;
+ }
+" " ;
+"\t" ;
+"\n" ;
+. fprintf (stderr, "ignoring %c\n", *yytext);
+%%
+
+static int
+count (s, c)
+ char *s;
+ char c;
+{
+ int i = 0;
+ while (*s)
+ if (*s++ == c)
+ i++;
+ return i;
+}
+
+yysetsource(s)
+ char *s;
+{
+ yysourcebase = yysource = s;
+}
+
+yyerror(s)
+ char *s;
+{
+ char *t;
+
+ fprintf (stderr, "%s\n", s);
+ t = yysource - 50;
+ if (t < yysourcebase)
+ t = yysourcebase;
+ while (*t && t < yysource + 50) {
+ if (t == yysource)
+ putc ('@', stderr);
+ putc (*t++, stderr);
+ }
+ if (t == yysource)
+ putc ('@', stderr);
+ if (!*t)
+ fprintf (stderr, "<EOF>");
+ fprintf (stderr, "\n");
+}
diff --git a/vendor/x11iraf/obm/ObmW/scroll.c b/vendor/x11iraf/obm/ObmW/scroll.c
new file mode 100644
index 00000000..5a618d44
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/scroll.c
@@ -0,0 +1,46 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/CharSet.h>
+#include "scroll.h"
+
+void XfwfConnectScrollingWidgets(w1, w2)
+ Widget w1, w2;
+{
+ XtCallbackProc response_cb_1 = NULL, response_cb_2 = NULL;
+
+ /* Error checking omitted */
+ XtVaGetValues(w1, "scrollResponse", &response_cb_1, NULL);
+ XtVaGetValues(w2, "scrollResponse", &response_cb_2, NULL);
+
+ XtAddCallback(w1, "scrollCallback", response_cb_2, (XtPointer)w2);
+
+ XtAddCallback(w2, "scrollCallback", response_cb_1, (XtPointer)w1);
+}
+
+XfwfSReason XfwfCvtStringToScrollReason(s)
+ String s;
+{
+ if (XmuCompareISOLatin1(s, "Notify") == 0) return XfwfSNotify;
+ if (XmuCompareISOLatin1(s, "Move") == 0) return XfwfSMove;
+ if (XmuCompareISOLatin1(s, "Drag") == 0) return XfwfSDrag;
+ if (XmuCompareISOLatin1(s, "Zoom") == 0) return XfwfSZoom;
+ if (XmuCompareISOLatin1(s, "Stretch") == 0) return XfwfSStretch;
+ if (XmuCompareISOLatin1(s, "Up") == 0) return XfwfSUp;
+ if (XmuCompareISOLatin1(s, "Down") == 0) return XfwfSDown;
+ if (XmuCompareISOLatin1(s, "Left") == 0) return XfwfSLeft;
+ if (XmuCompareISOLatin1(s, "Right") == 0) return XfwfSRight;
+ if (XmuCompareISOLatin1(s, "PageUp") == 0) return XfwfSPageUp;
+ if (XmuCompareISOLatin1(s, "PageDown") == 0) return XfwfSPageDown;
+ if (XmuCompareISOLatin1(s, "PageLeft") == 0) return XfwfSPageLeft;
+ if (XmuCompareISOLatin1(s, "PageRight") == 0) return XfwfSPageRight;
+ if (XmuCompareISOLatin1(s, "ZoomIn") == 0) return XfwfSZoomIn;
+ if (XmuCompareISOLatin1(s, "ZoomOut") == 0) return XfwfSZoomOut;
+ if (XmuCompareISOLatin1(s, "Top") == 0) return XfwfSTop;
+ if (XmuCompareISOLatin1(s, "Bottom") == 0) return XfwfSBottom;
+ if (XmuCompareISOLatin1(s, "LeftSide") == 0) return XfwfSLeftSide;
+ if (XmuCompareISOLatin1(s, "RightSide") == 0) return XfwfSRightSide;
+ if (XmuCompareISOLatin1(s, "ZoomInFull") == 0) return XfwfSZoomInFull;
+ if (XmuCompareISOLatin1(s, "ZoomOutFull") == 0) return XfwfSZoomOutFull;
+ return XfwfSNotify; /* Should be: error */
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/scroll.h b/vendor/x11iraf/obm/ObmW/scroll.h
new file mode 100644
index 00000000..1ecbe1ed
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/scroll.h
@@ -0,0 +1,96 @@
+/*
+ * File: <Xfwf/scroll.h>
+ *
+ * Declarations and typedefs for the Free Widget Foundation
+ * Scrolling Widget Interface Policy.
+ * =
+
+ */
+
+#ifndef _XFWF_SCROLL_H
+#define _XFWF_SCROLL_H 1
+
+/*
+ * The XfwfSReason typedef defines all the possible types
+ * of scroll messages. XfwfSNotify indicates a _notify_
+ * message, and all others indicate a _command_ message.
+ */
+typedef enum _XfwfSReason
+{
+ XfwfSNotify, /* Widget has changed position or size */
+
+ XfwfSMove, /* Request to move widget */
+ XfwfSDrag, /* widget is being moved continuously */
+
+ XfwfSZoom, /* Request to Zoom (resize visible area) */
+ XfwfSStretch, /* widget is being zoomed continuously */
+
+ XfwfSUp, /* User request to ``move up one unit'' */
+ XfwfSLeft, /* User request to ``move left one unit'' */
+ XfwfSDown, XfwfSRight, /* similar */
+
+ XfwfSPageUp, /* User request to ``move up one page'' */
+ XfwfSPageLeft, XfwfSPageDown, XfwfSPageRight, /* similar */
+
+ XfwfSZoomIn, /* User invoked ``Zoom In'' */
+ XfwfSZoomOut, /* User invoked ``Zoom Out'' */
+
+ XfwfSTop, /* User invoked ``Scroll to top'' */
+ XfwfSBottom, XfwfSLeftSide, XfwfSRightSide, /* similar */
+
+ XfwfSZoomInFull, XfwfSZoomOutFull /* similar, but wrt zoom state */
+
+} XfwfSReason;
+
+/* =
+
+ * #define's for the 'flags' field:
+ */
+typedef unsigned short XfwfSFlags;
+#define XFWF_VPOS 0x1 /* vpos set */
+#define XFWF_VSIZE 0x2 /* vsize set */
+#define XFWF_HPOS 0x4 /* hpos set */
+#define XFWF_HSIZE 0x8 /* hsize set */
+
+/*
+ * The XfwfScrollInfo structure defines the scroll message passed
+ * between scrolling widgets:
+ */
+typedef struct _XfwfScrollInfo
+{
+ XfwfSReason reason; /* see above */
+ XfwfSFlags flags; /* defines which fields are relev=
+ant */
+ float vpos; /* "top" position, [0..1] */
+ float vsize; /* total visible vertical size [0=
+=2E.1] */
+ float hpos; /* "left" position */
+ float hsize; /* total visible horizontal size =
+*/
+} XfwfScrollInfo;
+
+
+/*
+ * Application convenience functions:
+ *
+ * XfwfConnectScrollingWidgets(Widget, Widget) attaches two
+ * widgets, which must have the scrollCallback and scrollResponse
+ * resources.
+ */
+
+extern void XfwfConnectScrollingWidgets( /* Widget w1, Widget w2 */);
+
+
+/*
+ * Widget convenience functions:
+ *
+ * =
+
+ * XcwfCvtStringToScrollReason(char *s) converts 's' to one
+ * of the XfwfS* enumerated values. The comparison is case-insensitive,
+ * and the XfwfS prefix may be present but is not necessary.
+ */
+
+extern XfwfSReason XfwfCvtStringToScrollReason(/* char * */);
+
+#endif /* _XFWF_SCROLL_H */
diff --git a/vendor/x11iraf/obm/ObmW/stip4.bm b/vendor/x11iraf/obm/ObmW/stip4.bm
new file mode 100644
index 00000000..8173f891
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/stip4.bm
@@ -0,0 +1,4 @@
+#define stip4_width 2
+#define stip4_height 2
+static char stip4_bits[] = {
+ 0x01, 0x02};
diff --git a/vendor/x11iraf/obm/ObmW/strnchr.c b/vendor/x11iraf/obm/ObmW/strnchr.c
new file mode 100644
index 00000000..2dc2e1cd
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/strnchr.c
@@ -0,0 +1,17 @@
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "TabString.h"
+
+/*
+ * Like strchr, except has a length limit.
+ */
+char *
+strnchr(s, c, n)
+ char *s;
+ int c;
+ int n;
+{
+ while (n--)
+ if (*s == c) return s; else ++s;
+ return NULL;
+}
diff --git a/vendor/x11iraf/obm/ObmW/zz/Separator.c b/vendor/x11iraf/obm/ObmW/zz/Separator.c
new file mode 100644
index 00000000..f7669a76
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Separator.c
@@ -0,0 +1,357 @@
+/*
+ * Separator.c - Separator widget Vladimir Romanovski
+ *
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/RectObjP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/SeparatorP.h>
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xmu/Drawing.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+#define offset(field) XtOffsetOf(SeparatorRec, field)
+
+static XtResource resources[] = {
+ {
+ XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
+ offset(separator.orientation), XtRImmediate, (XtPointer) XtorientHorizontal
+ },
+ {
+ XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(separator.margin), XtRImmediate, (caddr_t)1
+ },
+ {
+ XtNseparatorType, XtCSeparatorType, XtRSeparatorType,
+ sizeof(XawSeparatorType), offset(separator.separatorType),
+ XtRImmediate,(caddr_t)XawSHADOW_ETCHED_IN
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(simple.shadow_thickness), XtRImmediate, (XtPointer)0
+ }
+};
+#undef offset
+
+static void Initialize();
+static void Resize();
+static void Redisplay();
+static Boolean SetValues();
+static void ClassInitialize();
+static void Destroy();
+
+SeparatorClassRec separatorClassRec = {
+ {
+ /* core_class fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Separator",
+ /* widget_size */ sizeof(SeparatorRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* Simple class fields initialization */
+ /* change_sensitive */ XtInheritChangeSensitive,
+ /* display_rect */ XtInheritDisplayRectProc,
+ /* extension */ NULL
+ },
+ { /* Separator class fields initialization */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass separatorWidgetClass = (WidgetClass)&separatorClassRec;
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+/*---------------------------------------------*/
+#define done( type, value ) \
+{ \
+ if ( toVal->addr != NULL ) \
+ { \
+ if ( toVal->size < sizeof( type ) ) \
+ { \
+ toVal->size = sizeof( type ); \
+ return False; \
+ } \
+ *(type*)(toVal->addr) = (value); \
+ } \
+ else \
+ { \
+ static type static_val; \
+ static_val = (value); \
+ toVal->addr = (caddr_t)&static_val; \
+ } \
+ toVal->size = sizeof(type); \
+ return True; \
+} \
+/*---------------------------------------------*/
+
+static XrmQuark QSingle, QDouble, QShadowIn, QShadowOut;
+
+/* ARGSUSED */
+static Boolean
+CvtStringToSeparatorType(dpy, args, num_args, fromVal, toVal, convData)
+ Display *dpy;
+ XrmValuePtr args; /* unused */
+ Cardinal *num_args; /* unused */
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+ XtPointer *convData; /* unused */
+{
+ static XawSeparatorType separatorType;
+ XrmQuark q;
+ char lowerName[BUFSIZ];
+
+ XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
+ q = XrmStringToQuark(lowerName);
+
+ separatorType = XawSINGLE_LINE;
+
+ if (q == QSingle) separatorType = XawSINGLE_LINE;
+ else if (q == QDouble) separatorType = XawDOUBLE_LINE;
+ else if (q == QShadowIn) separatorType = XawSHADOW_ETCHED_IN;
+ else if (q == QShadowOut) separatorType = XawSHADOW_ETCHED_OUT;
+ else
+ XtDisplayStringConversionWarning( dpy, (char *)fromVal->addr,
+ XtRSeparatorType);
+
+ done(XawSeparatorType, separatorType);
+}
+#undef done
+
+static void ClassInitialize()
+{
+ XawInitializeWidgetSet();
+ XtSetTypeConverter( XtRString, XtRSeparatorType, CvtStringToSeparatorType,
+ (XtConvertArgList)NULL, (Cardinal)0,
+ XtCacheNone, (XtDestructor)NULL);
+
+ QSingle = XrmStringToQuark(XawSingle_Line);
+ QDouble = XrmStringToQuark(XawDouble_Line);
+ QShadowIn = XrmStringToQuark(XawShadow_Etched_In);
+ QShadowOut = XrmStringToQuark(XawShadow_Etched_Out);
+}
+
+static void GetGC(sw)
+ SeparatorWidget sw;
+{
+ XGCValues values;
+ unsigned long mask;
+
+ values.foreground = sw->simple.foreground;
+ values.line_width = 0;
+ mask = GCForeground | GCLineWidth;
+
+ sw->separator.gc = XtGetGC ((Widget)sw, mask, (XGCValues*)&values);
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SeparatorWidget newsw = (SeparatorWidget) new;
+
+ if (newsw->core.width == 0)
+ newsw->core.width = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (newsw->core.height == 0)
+ newsw->core.height = 8 + 2*SIMPLE_MARGIN(new);
+
+ GetGC(newsw);
+
+}
+
+static void Resize(w)
+ Widget w;
+{
+ /* If widget is realized, clear and redisplay it */
+
+ if (XtIsRealized(w)) {
+ XClearWindow(XtDisplay(w), XtWindow(w));
+ (*separatorClassRec.core_class.expose) (w, (XEvent*)NULL, (Region)NULL);
+ }
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SeparatorWidget cursw = (SeparatorWidget) current;
+ SeparatorWidget newsw = (SeparatorWidget) new;
+ Boolean redisplay = False;
+
+#define NE(field) (cursw->separator.field != newsw->separator.field)
+
+ if (newsw->core.width == 0)
+ newsw->core.width = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (newsw->core.height == 0)
+ newsw->core.height = 8 + 2*SIMPLE_MARGIN(new);
+
+ if (NE(margin) || NE(separatorType))
+ redisplay = True;
+
+ if (cursw->simple.foreground != newsw->simple.foreground)
+ {
+ XtReleaseGC(new, cursw->separator.gc);
+ GetGC(newsw);
+ redisplay = True;
+ }
+
+ return redisplay;
+}
+
+static void Destroy(w)
+ Widget w;
+{
+ XtReleaseGC( w, ((SeparatorWidget)w)->separator.gc );
+}
+
+static void Redisplay(gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register SeparatorWidget sw = (SeparatorWidget) gw;
+ int x1, y1, x2, y2;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ if (sw->simple.shadow_thickness > 0)
+ (*simpleWidgetClass->core_class.expose) (gw, event, region);
+
+ if (sw->separator.orientation == XtorientHorizontal) {
+ x1 = sw->separator.margin;
+ x2 = sw->core.width - (x1 * 2);
+
+ switch(sw->separator.separatorType) {
+
+ case XawSHADOW_ETCHED_IN :
+ y1 = (sw->core.height - 2) / 2;
+ y2 = y1 + 1;
+
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x2, y1);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x1, y2, x2, y2);
+ break;
+ case XawSHADOW_ETCHED_OUT:
+ y1 = (sw->core.height - 2) / 2;
+ y2 = y1 + 1;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y2, x2, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x1, y1, x2, y1);
+ break;
+
+ case XawDOUBLE_LINE:
+ y1 = (sw->core.height - 2)/ 2;
+ y2 = y1 + 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x2, y1);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y2, x2, y2);
+ break;
+
+ case XawSINGLE_LINE :
+ y1 = sw->core.height / 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x2, y1);
+ default:
+ break;
+ }
+ } else {
+ y1 = sw->separator.margin;
+ y2 = sw->core.height - (y1 * 2);
+
+ switch(sw->separator.separatorType) {
+
+ case XawSHADOW_ETCHED_IN :
+ x1 = (sw->core.width - 2) / 2;
+ x2 = x1 + 1;
+
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x2, y1, x2, y2);
+ break;
+ case XawSHADOW_ETCHED_OUT:
+ x1 = (sw->core.width - 2) / 2;
+ x2 = x1 + 1;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.bottom_shadow_GC,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->simple.top_shadow_GC,
+ x2, y1, x2, y2);
+ break;
+
+ case XawDOUBLE_LINE:
+ x1 = (sw->core.width - 2)/ 2;
+ x2 = x1 + 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x1, y2);
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x2, y1, x2, y2);
+ break;
+
+ case XawSINGLE_LINE :
+ x1 = sw->core.width / 2;
+ XDrawLine(XtDisplay(gw), XtWindow(gw), sw->separator.gc,
+ x1, y1, x1, y2);
+ default:
+ break;
+ }
+ }
+}
+
+
diff --git a/vendor/x11iraf/obm/ObmW/zz/Separator.h b/vendor/x11iraf/obm/ObmW/zz/Separator.h
new file mode 100644
index 00000000..6d5ad87f
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Separator.h
@@ -0,0 +1,99 @@
+#ifndef _XawSeparator_h
+#define _XawSeparator_h
+
+/***********************************************************************
+ *
+ * Separator Widget
+ *
+ ***********************************************************************/
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Simple.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ cursorName Cursor String NULL
+ destroyCallback Callback XtCallbackList NULL
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+
+
+
+typedef enum {
+ XawSINGLE_LINE = Xraw_SEPARATOR,
+ XawDOUBLE_LINE,
+ XawSHADOW_ETCHED_IN,
+ XawSHADOW_ETCHED_OUT
+} XawSeparatorType;
+
+
+#define XawSingle_Line "singleline"
+#define XawDouble_Line "doubleline"
+#define XawShadow_Etched_In "shadowetchedin"
+#define XawShadow_Etched_Out "shadowetchedout"
+
+
+
+#ifndef XtNmargin
+#define XtNmargin "margin"
+#endif
+
+#ifndef XtCMargin
+#define XtCMargin "Margin"
+#endif
+
+#ifndef XtNseparatorType
+#define XtNseparatorType "separatorType"
+#endif
+
+#ifndef XtCSeparatorType
+#define XtCSeparatorType "SeparatorType"
+#endif
+
+#ifndef XtRSeparatorType
+#define XtRSeparatorType "SeparatorType"
+#endif
+
+#define XawTextEncoding8bit 0
+#define XawTextEncodingChar2b 1
+
+#define XtNleftBitmap "leftBitmap"
+#define XtCLeftBitmap "LeftBitmap"
+#define XtNencoding "encoding"
+#define XtCEncoding "Encoding"
+
+#ifndef _XtStringDefs_h_
+#define XtNbitmap "bitmap"
+#define XtNforeground "foreground"
+#define XtNseparator "separator"
+#define XtNfont "font"
+#define XtNinternalWidth "internalWidth"
+#define XtNinternalHeight "internalHeight"
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#define XtCBitmap "Bitmap"
+#endif
+
+/* Class record constants */
+
+extern WidgetClass separatorWidgetClass;
+
+typedef struct _SeparatorClassRec *SeparatorWidgetClass;
+typedef struct _SeparatorRec *SeparatorWidget;
+
+#endif /* _XawSeparator_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/zz/SeparatorP.h b/vendor/x11iraf/obm/ObmW/zz/SeparatorP.h
new file mode 100644
index 00000000..75250d38
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/SeparatorP.h
@@ -0,0 +1,60 @@
+/*
+ * SeparatorP.h - Private definitions for Separator widget
+ *
+ */
+
+#ifndef _XawSeparatorP_h
+#define _XawSeparatorP_h
+
+/***********************************************************************
+ *
+ * Separator Widget Private Data
+ *
+ ***********************************************************************/
+
+#include <X11/Xmu/Converters.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/Separator.h>
+
+
+/* New fields for the Separator widget class record */
+
+typedef struct {int foo;} SeparatorClassPart;
+
+/* Full class record declaration */
+typedef struct _SeparatorClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ SeparatorClassPart separator_class;
+} SeparatorClassRec;
+
+extern SeparatorClassRec separatorClassRec;
+
+/* New fields for the Separator widget record */
+
+typedef struct {
+
+ /* Public Resources */
+ XtOrientation orientation;
+ Dimension margin;
+ XawSeparatorType separatorType;
+
+ /* Private part */
+ GC gc;
+
+} SeparatorPart;
+
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _SeparatorRec {
+ CorePart core;
+ SimplePart simple;
+ SeparatorPart separator;
+} SeparatorRec;
+
+#endif /* _XawSeparatorP_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/Simple.c b/vendor/x11iraf/obm/ObmW/zz/Simple.c
new file mode 100644
index 00000000..83797833
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Simple.c
@@ -0,0 +1,489 @@
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Drawing.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleP.h>
+#include <X11/Xraw/ContainerP.h>
+
+#define UnspecifiedPixmap (Pixmap)2
+#define UndefinedGC (GC)2
+
+static void InsPixel();
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(SimpleWidget, simple.field)
+ {
+ XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNinsensitiveBorder, XtCInsensitive, XtRPixmap, sizeof(Pixmap),
+ offset(insensitive_border), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(foreground), XtRImmediate, (XtPointer) XtDefaultForeground
+ },
+ {
+ "top.gc", "Top.gc", XtRString, sizeof(String),
+ offset(top_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "bottom.gc", "Bottom.gc", XtRString, sizeof(String),
+ offset(bottom_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "highlight.gc", "Highlight.gc", XtRString, sizeof(String),
+ offset(highlight_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(shadow_thickness), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNtopShadowPixmap, XtCTopShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(top_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(top_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNbottomShadowPixmap, XtCBottomShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(bottom_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(bottom_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNhighlightPixmap, XtCHighlightPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(highlight_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNhighlightPixel, XtCHighlightPixel, XtRPixel, sizeof(Pixel),
+ offset(highlight_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNhighlightThickness, XtCHighlightThickness, XtRDimension,
+ sizeof(Dimension),
+ offset(highlight_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNuserData, XtCUserData, XtRPixmap, sizeof(Pixmap),
+ offset(user_data), XtRImmediate, (XtPointer) NULL
+ },
+ {
+ XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0
+ }
+
+};
+
+static void InsPixel(w, off, value)
+ Widget w;
+ int off;
+ XrmValue *value;
+{
+ register SimpleWidget p = (SimpleWidget) w;
+ static Pixel pixel;
+
+ if (off == offset(top_shadow_color))
+ {
+ p->simple.top_shadow_GC = UndefinedGC;
+ }
+ else if (off == offset(bottom_shadow_color))
+ {
+ p->simple.bottom_shadow_GC = UndefinedGC;
+ }
+ else
+ {
+ p->simple.highlight_GC = UndefinedGC;
+ }
+ value->addr = (XtPointer) &pixel;
+}
+
+#undef offset
+
+static void ClasstInitialize();
+static void ClassPartInitialize();
+static void Initialize();
+static void Realize();
+static void Redisplay();
+static void Destroy();
+
+static Boolean SetValues();
+static Boolean DisplayRectProc();
+static Boolean ChangeSensitive();
+
+static XtGeometryResult QueryGeometry();
+
+SimpleClassRec simpleClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &widgetClassRec,
+ /* class_name */ "Simple",
+ /* widget_size */ sizeof(SimpleRec),
+ /* class_initialize */ ClasstInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ NULL,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ ChangeSensitive,
+ /* display_rect */ DisplayRectProc,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass simpleWidgetClass = (WidgetClass)&simpleClassRec;
+
+static void ClasstInitialize()
+{
+/* EMPTY */
+}
+
+static void ClassPartInitialize(class)
+ WidgetClass class;
+{
+ register SimpleWidgetClass c = (SimpleWidgetClass)class;
+
+ if (c->simple_class.change_sensitive == NULL)
+ {
+ char buf[BUFSIZ];
+
+ sprintf(buf,
+ "%s Widget: The Simple Widget class method 'change_sensitive' is undefined.\nA function must be defined or inherited.",
+ c->core_class.class_name);
+ XtWarning(buf);
+ c->simple_class.change_sensitive = ChangeSensitive;
+ }
+
+ if (c->simple_class.change_sensitive == XtInheritChangeSensitive)
+ c->simple_class.change_sensitive = ChangeSensitive;
+
+ if (c->simple_class.display_rect == XtInheritDisplayRectProc)
+ c->simple_class.display_rect = DisplayRectProc;
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SimpleWidget sw = (SimpleWidget)new;
+ SimplePart* sp = (SimplePart*)&(sw->simple);
+
+ if (sp->top_shadow_pixmap == UnspecifiedPixmap)
+ sp->top_shadow_pixmap = None;
+
+ if (sp->top_shadow_GC == NULL){
+ if (sp->top_shadow_pixmap != None)
+ sp->top_shadow_GC = AllocGCFromPixmap (new, sp->top_shadow_pixmap);
+ else
+ sp->top_shadow_GC = AllocGCFromPixel (new, sp->top_shadow_color);
+ } else if (sp->top_shadow_GC == UndefinedGC)
+ sp->top_shadow_GC = MakeTopShadowGC (new, new->core.background_pixel);
+
+
+ if (sp->bottom_shadow_pixmap == UnspecifiedPixmap)
+ sp->bottom_shadow_pixmap = None;
+
+ if (sp->bottom_shadow_GC == NULL){
+ if (sp->bottom_shadow_pixmap != None)
+ sp->bottom_shadow_GC = AllocGCFromPixmap (new, sp->bottom_shadow_pixmap);
+ else
+ sp->bottom_shadow_GC = AllocGCFromPixel (new, sp->bottom_shadow_color);
+ } else if (sp->bottom_shadow_GC == UndefinedGC)
+ sp->bottom_shadow_GC =MakeBottomShadowGC (new, new->core.background_pixel);
+
+
+ if (sp->highlight_pixmap == UnspecifiedPixmap)
+ sp->highlight_pixmap = None;
+
+ if (sp->highlight_GC == NULL){
+ if (sp->highlight_pixmap != None)
+ sp->highlight_GC = AllocGCFromPixmap (new, sp->highlight_pixmap);
+ else
+ sp->highlight_GC = AllocGCFromPixel (new, sp->highlight_color);
+ } else if (sp->highlight_GC == UndefinedGC)
+ sp->highlight_GC = MakeBottomShadowGC (new, new->core.background_pixel);
+
+}
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ Mask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ Pixmap border_pixmap;
+
+ if (!XtIsSensitive(w))
+ {
+ /* change border to gray; have to remember the old one,
+ * so XtDestroyWidget deletes the proper one */
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ border_pixmap = w->core.border_pixmap;
+ attributes->border_pixmap =
+ w->core.border_pixmap = ((SimpleWidget)w)->simple.insensitive_border;
+
+ *valueMask |= CWBorderPixmap;
+ *valueMask &= ~CWBorderPixel;
+ }
+
+ if ((attributes->cursor = ((SimpleWidget)w)->simple.cursor) != None)
+ *valueMask |= CWCursor;
+
+ XtCreateWindow( w, (unsigned int)InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attributes );
+
+ if (!XtIsSensitive(w))
+ w->core.border_pixmap = border_pixmap;
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ SimpleWidget s_old = (SimpleWidget) current;
+ SimpleWidget s_new = (SimpleWidget) new;
+ SimplePart* sp = (SimplePart*)&(s_new->simple);
+ Boolean redraw = False;
+
+#define NE(field) (s_new->simple.field != s_old->simple.field)
+
+ if ( XtIsSensitive(current) != XtIsSensitive(new) )
+ (*((SimpleWidgetClass)XtClass(new))->
+ simple_class.change_sensitive) ( new );
+
+ if ( NE(cursor) && XtIsRealized(new))
+ XDefineCursor(XtDisplay(new), XtWindow(new), s_new->simple.cursor);
+
+ if (NE(top_shadow_pixmap))
+ {
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixmap (new, sp->top_shadow_pixmap);
+ redraw = True;
+ }
+ else if (NE(top_shadow_color) && sp->top_shadow_pixmap == None)
+ {
+ XtReleaseGC (new, sp->top_shadow_GC);
+ sp->top_shadow_GC = AllocGCFromPixel (new, sp->top_shadow_color);
+ redraw = True;
+ }
+
+ if (NE(bottom_shadow_pixmap))
+ {
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixmap (new, sp->bottom_shadow_pixmap);
+ redraw = True;
+ }
+ else if (NE(bottom_shadow_color) && sp->bottom_shadow_pixmap == None)
+ {
+ XtReleaseGC (new, sp->bottom_shadow_GC);
+ sp->bottom_shadow_GC = AllocGCFromPixel (new, sp->bottom_shadow_color);
+ redraw = True;
+ }
+
+ if (NE(highlight_pixmap))
+ {
+ XtReleaseGC (new, sp->highlight_GC);
+ sp->highlight_GC = AllocGCFromPixmap (new, sp->highlight_pixmap);
+ redraw = True;
+ }
+ else if (NE(highlight_color) && sp->highlight_pixmap)
+ {
+ XtReleaseGC (new, sp->highlight_GC);
+ sp->highlight_GC = AllocGCFromPixel (new, sp->highlight_color);
+ redraw = True;
+ }
+
+#undef NE
+
+ return redraw;
+}
+
+
+static void Unhighlight (gw)
+ Widget gw;
+{
+ register Dimension thick = ((SimpleWidget)gw)->simple.highlight_thickness;
+ register Dimension width = gw->core.width;
+ register Dimension height = gw->core.height;
+
+ if (!XtIsRealized(gw))
+ return;
+
+ if ( XtIsSubclass(XtParent(gw), containerWidgetClass))
+ {
+ XRectangle rectangles[4];
+ GC gc = ((ContainerWidget) XtParent(gw))->container.background_GC;
+
+#define SET_RECTANGLE(I,X,Y,W,H) \
+ rectangles[I].x = X; rectangles[I].y = Y; \
+ rectangles[I].width = W; rectangles[I].height = H
+
+ SET_RECTANGLE(0, 0, 0, thick, height);
+ SET_RECTANGLE(1, 0, height - thick, width, thick);
+ SET_RECTANGLE(2, 0, 0, width, thick);
+ SET_RECTANGLE(3, width - thick, 0, thick, height);
+
+ XFillRectangles (XtDisplay(gw), XtWindow(gw), gc, rectangles, 4);
+
+ }
+ else
+ {
+ Display *dpy = XtDisplay(gw);
+ Window win = XtWindow(gw);
+
+ XClearArea( dpy, win, 0, 0, thick, height, False);
+ XClearArea( dpy, win, 0, height - thick, width, thick, False);
+ XClearArea( dpy, win, 0, 0, width, thick, False);
+ XClearArea( dpy, win, width - thick, 0, thick, height, False);
+ }
+}
+
+
+/* ARGSUSED */
+static void Redisplay( gw, event, region )
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ register SimpleWidget s = (SimpleWidget)gw;
+
+ if (XtIsRealized(gw))
+ {
+ Unhighlight (gw);
+
+ if (s->simple.shadow_thickness)
+ XawDrawFrame (gw,
+ s->simple.highlight_thickness,
+ s->simple.highlight_thickness,
+ s->core.width - 2 * s->simple.highlight_thickness,
+ s->core.height - 2 * s->simple.highlight_thickness,
+ XawRAISED,
+ s->simple.shadow_thickness,
+ s->simple.top_shadow_GC,
+ s->simple.bottom_shadow_GC);
+ }
+}
+
+static void Destroy(w)
+ Widget w;
+{
+ register SimpleWidget s = (SimpleWidget)w;
+
+ XtReleaseGC(w, s->simple.top_shadow_GC);
+ XtReleaseGC(w, s->simple.bottom_shadow_GC);
+}
+
+static Boolean DisplayRectProc (w, rect)
+ Widget w;
+ XRectangle *rect;
+{
+ register SimpleWidget s = (SimpleWidget)w;
+
+ rect->x =
+ rect->y = s->simple.highlight_thickness + s->simple.shadow_thickness;
+ rect->width = s->core.width - 2 * rect->x;
+ rect->height = s->core.height - 2 * rect->y;
+
+ return True;
+}
+
+
+static XtGeometryResult QueryGeometry(w, intended, preferred)
+ Widget w;
+ XtWidgetGeometry *intended, *preferred;
+{
+ register SimpleWidget sw = (SimpleWidget)w;
+
+
+ preferred->request_mode = CWWidth | CWHeight;
+
+ preferred->width = preferred->height = 2 * SIMPLE_MARGIN(sw) + 1;
+
+#define WIDTH_HEIGHT (CWWidth | CWHeight)
+
+ if (intended
+ && ((intended->request_mode & WIDTH_HEIGHT) == WIDTH_HEIGHT)
+ && intended->width == preferred->width
+ && intended->height == preferred->height)
+ {
+ return XtGeometryYes;
+ }
+ else if (preferred->width == w->core.width
+ && preferred->height == w->core.height)
+ {
+ return XtGeometryNo;
+ }
+ else
+ {
+ return XtGeometryAlmost;
+ }
+}
+
+
+static Boolean ChangeSensitive(w)
+ register Widget w;
+{
+ if (XtIsRealized(w)) {
+ if (XtIsSensitive(w))
+ if (w->core.border_pixmap != UnspecifiedPixmap)
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ w->core.border_pixmap );
+ else
+ XSetWindowBorder( XtDisplay(w), XtWindow(w),
+ w->core.border_pixel );
+ else {
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ ((SimpleWidget)w)->
+ simple.insensitive_border );
+ }
+ }
+ return False;
+}
diff --git a/vendor/x11iraf/obm/ObmW/zz/Simple.h b/vendor/x11iraf/obm/ObmW/zz/Simple.h
new file mode 100644
index 00000000..bbe11cda
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Simple.h
@@ -0,0 +1,96 @@
+/*
+ * $XConsortium: Simple.h,v 1.9 89/07/21 01:44:53 kit Exp $
+ */
+
+/***********************************************************
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifndef _Simple_h
+#define _Simple_h
+
+/****************************************************************
+ *
+ * Simple widgets
+ *
+ ****************************************************************/
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ insensitiveBorder Insensitive Pixmap Gray
+ mappedWhenManaged MappedWhenManaged Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+ shadowWidth ShadowWidth Dimension 2
+ topShadowPixel TopShadowPixel Pixel dynamic
+ bottomShadowPixel BottomShadowPixel Pixel dynamic
+ topShadowContrast TopShadowContrast Int 20
+ bottomShadowContrast BottomShadowContrast Int 40
+ userData UserData XtPointer NULL
+ beNiceToColormap BeNiceToColormap Boolean False
+
+*/
+
+#define XtNcursor "cursor"
+#define XtNinsensitiveBorder "insensitiveBorder"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+
+#define XtCInsensitive "Insensitive"
+
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNhighlightPixmap "highlightPixmap"
+#define XtCHighlightPixmap "HighlightPixmap"
+#define XtNhighlightThickness "highlightThickness"
+#define XtCHighlightThickness "HighlightThickness"
+
+
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNhighlightPixel "highlightPixel"
+#define XtCHighlightPixel "HighlightPixel"
+
+typedef struct _SimpleClassRec *SimpleWidgetClass;
+typedef struct _SimpleRec *SimpleWidget;
+
+extern WidgetClass simpleWidgetClass;
+
+#endif /* _Simple_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h b/vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h
new file mode 100644
index 00000000..32f5ccf9
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h
@@ -0,0 +1,113 @@
+/*
+ * $XConsortium: SimpleMenP.h,v 1.12 89/12/11 15:01:39 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * SimpleMenuP.h - Private Header file for SimpleMenu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SimpleMenuP_h
+#define _SimpleMenuP_h
+
+#include <X11/ShellP.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleMenu.h>
+#include <X11/Xraw/SmeP.h>
+
+#define SMW(w) ((SimpleMenuWidget)w)->simple_menu
+
+typedef struct {
+ XtPointer extension; /* For future needs. */
+} SimpleMenuClassPart;
+
+typedef struct _SimpleMenuClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ SimpleMenuClassPart simpleMenu_class;
+} SimpleMenuClassRec;
+
+extern SimpleMenuClassRec simpleMenuClassRec;
+
+typedef struct _SimpleMenuPart {
+ /* resources */
+ Dimension shadow_thickness;
+ Dimension bsb_shadow_thickness;
+
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+
+ GC top_shadow_GC;
+ GC bottom_shadow_GC;
+
+ XawFrameType frame_type;
+
+ XtPointer user_data;
+
+ /* resources */
+
+ String label_string; /* The string for the label or NULL. */
+ SmeObject label; /* If label_string is non-NULL then this is
+ the label widget. */
+ WidgetClass label_class; /* Widget Class of the menu label object. */
+
+ Dimension top_margin; /* Top and bottom margins. */
+ Dimension bottom_margin;
+ Dimension row_height; /* height of each row (menu entry) */
+
+ Cursor cursor; /* The menu's cursor. */
+ SmeObject popup_entry; /* The entry to position the cursor on for
+ when using XawPositionSimpleMenu. */
+ Boolean menu_on_screen; /* Force the menus to be fully on the screen.*/
+ int backing_store; /* What type of backing store to use. */
+
+ /* private state */
+
+ Boolean recursive_set_values; /* contain a possible infinite loop. */
+
+ Boolean menu_width; /* If true then force width to remain
+ core.width */
+ Boolean menu_height; /* Just like menu_width, but for height. */
+
+ SmeObject entry_set; /* The entry that is currently set or
+ highlighted. */
+} SimpleMenuPart;
+
+typedef struct _SimpleMenuRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ SimpleMenuPart simple_menu;
+} SimpleMenuRec, *SimpleMenu;
+
+#endif /* _SimpleMenuP_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c b/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c
new file mode 100644
index 00000000..eeade452
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c
@@ -0,0 +1,1467 @@
+/* $XConsortium: SimpleMenu.c,v 1.32 89/12/11 15:01:50 kit Exp $ */
+
+/*
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * SimpleMenu.c - Source code file for SimpleMenu widget.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ * --------------------------------
+ *
+ * Date: Jul 4, 1995
+ *
+ * Changes: Vladimir T. Romanovski
+ * romsky@hp1.oea.ihep.su // IHEP (Russia)
+ * romsky@munin.ucsf.edu // University of California San Francisco
+ *
+ */
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/SimpleMenP.h>
+#include <X11/Xraw/SmeBSB.h>
+#include <X11/Xraw/Cardinals.h>
+#include <X11/Xraw/SmeLineP.h>
+
+#include <X11/Xmu/Initer.h>
+#include <X11/Xmu/CharSet.h>
+
+#define CORE(w) (w)->core
+
+#define ForAllChildren(smw, childP) \
+ for ( (childP) = (SmeObject *) (smw)->composite.children ; \
+ (childP) < (SmeObject *) ((smw)->composite.children + \
+ (smw)->composite.num_children ) ; \
+ (childP)++ )
+
+
+#define UnspecifiedPixmap (Pixmap)2
+#define UndefinedGC (GC)2
+
+static void InsPixel();
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(SimpleMenuWidget, simple_menu.field)
+ {
+ "top.gc", "Top.gc", XtRString, sizeof(String),
+ offset(top_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ "bottom.gc", "Bottom.gc", XtRString, sizeof(String),
+ offset(bottom_shadow_GC), XtRImmediate, (XtPointer)NULL
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(shadow_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNbsbShadowWidth, XtCBsbShadowWidth, XtRDimension, sizeof(Dimension),
+ offset(bsb_shadow_thickness), XtRImmediate, (XtPointer) 2
+ },
+ {
+ XtNtopShadowPixmap, XtCTopShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(top_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(top_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNbottomShadowPixmap, XtCBottomShadowPixmap, XtRPixmap, sizeof(Pixmap),
+ offset(bottom_shadow_pixmap), XtRImmediate, (XtPointer) UnspecifiedPixmap
+ },
+ {
+ XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ offset(bottom_shadow_color), XtRCallProc, (XtPointer) InsPixel
+ },
+ {
+ XtNuserData, XtCUserData, XtRPixmap, sizeof(Pixmap),
+ offset(user_data), XtRImmediate, (XtPointer) NULL
+ },
+ {
+ XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
+ XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNframeType, XtCFrameType, XtRFrameType, sizeof(XawFrameType),
+ offset(frame_type), XtRImmediate, (XtPointer) XawRAISED
+ },
+
+/*
+ * Label Resources.
+ */
+
+ {
+ XtNlabel, XtCLabel, XtRString, sizeof(String),
+ offset(label_string), XtRString, NULL
+ },
+ {
+ XtNlabelClass, XtCLabelClass, XtRPointer, sizeof(WidgetClass),
+ offset(label_class), XtRImmediate, (XtPointer) NULL
+ },
+
+/*
+ * Layout Resources.
+ */
+
+ {
+ XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
+ offset(row_height), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(top_margin), XtRImmediate, (XtPointer) 0
+ },
+ {
+ XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(bottom_margin), XtRImmediate, (XtPointer) 0
+ },
+
+/*
+ * Misc. Resources
+ */
+
+ {
+ XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
+ XtOffset(SimpleMenuWidget, shell.allow_shell_resize),
+ XtRImmediate, (XtPointer) TRUE
+ },
+ {
+ XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None
+ },
+ {
+ XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
+ offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE
+ },
+ {
+ XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
+ offset(popup_entry), XtRWidget, NULL
+ },
+ {
+ XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
+ offset(backing_store), XtRImmediate,
+ (XtPointer) (Always + WhenMapped + NotUseful)
+ }
+};
+
+static void InsPixel(w, off, value)
+ Widget w;
+ int off;
+ XrmValue *value;
+{
+ register SimpleMenuWidget p = (SimpleMenuWidget) w;
+ static Pixel pixel;
+
+ if (off == offset(top_shadow_color))
+ {
+ p->simple_menu.top_shadow_GC = UndefinedGC;
+ }
+ else if (off == offset(bottom_shadow_color))
+ {
+ p->simple_menu.bottom_shadow_GC = UndefinedGC;
+ }
+ value->addr = (XtPointer) &pixel;
+}
+
+#undef offset
+
+static char defaultTranslations[] =
+ "<EnterWindow>: highlight() \n\
+ <LeaveWindow>: unhighlight() \n\
+ <BtnMotion>: highlight() \n\
+ <BtnUp>: MenuPopdown() notify() unhighlight()";
+
+/*
+ * Semi Public function definitions.
+ */
+
+static void Redisplay(), Realize(), Resize(), ChangeManaged();
+static void Initialize(), ClassInitialize(), ClassPartInitialize();
+static Boolean SetValues(), SetValuesHook();
+static XtGeometryResult GeometryManager();
+
+/*
+ * Action Routine Definitions
+ */
+
+static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
+
+/*
+ * Private Function Definitions.
+ */
+
+static void MakeSetValuesRequest(), CreateLabel(), Layout();
+static void AddPositionAction(), PositionMenu();
+static Dimension GetMenuWidth(), GetMenuHeight();
+static Widget FindMenu();
+static SmeObject GetEventEntry();
+
+static XtActionsRec actionsList[] =
+{
+ {"notify", Notify},
+ {"highlight", Highlight},
+ {"unhighlight", Unhighlight}
+};
+
+CompositeClassExtensionRec extension_rec = {
+ /* next_extension */ NULL,
+ /* record_type */ NULLQUARK,
+ /* version */ XtCompositeExtensionVersion,
+ /* record_size */ sizeof(CompositeClassExtensionRec),
+ /* accepts_objects */ TRUE,
+};
+
+#define superclass (&overrideShellClassRec)
+
+SimpleMenuClassRec simpleMenuClassRec = {
+ {
+ /* superclass */ (WidgetClass) superclass,
+ /* class_name */ "SimpleMenu",
+ /* size */ sizeof(SimpleMenuRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize*/ ClassPartInitialize,
+ /* Class init'ed */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actionsList,
+ /* num_actions */ XtNumber(actionsList),
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ False,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ SetValuesHook,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* intrinsics version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ NULL,
+ /* display_accelerator*/ NULL,
+ /* extension */ NULL
+ },{
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ },{
+ /* Shell extension */ NULL
+ },{
+ /* Override extension */ NULL
+ },{
+ /* Simple Menu extension*/ NULL
+ }
+};
+
+WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
+
+/************************************************************
+ *
+ * Semi-Public Functions.
+ *
+ ************************************************************/
+#define done(type, value) \
+ { \
+ if (to->addr != NULL) { \
+ if (to->size < sizeof(type)) { \
+ to->size = sizeof(type); \
+ return False; \
+ } \
+ *(type*)(to->addr) = (value); \
+ } else { \
+ static type static_val; \
+ static_val = (value); \
+ to->addr = (XtPointer)&static_val; \
+ } \
+ to->size = sizeof(type); \
+ return True; \
+ }
+
+
+/* ARGSUSED */
+static Boolean
+cvtStringToFrameType ( display, args, num_args, from, to, converter_data)
+ Display *display;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr from;
+ XrmValuePtr to;
+ XtPointer *converter_data;
+{
+ String s = (String) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToFrameType", "wrongParameters",
+ "XtToolkitError",
+ "String to frame type conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ if (XmuCompareISOLatin1(s, "raised") == 0) done(XawFrameType, XawRAISED);
+ if (XmuCompareISOLatin1(s, "sunken") == 0) done(XawFrameType, XawSUNKEN);
+ if (XmuCompareISOLatin1(s, "chiseled") == 0) done(XawFrameType, XawCHISELED);
+ if (XmuCompareISOLatin1(s, "ledged") == 0) done(XawFrameType, XawLEDGED);
+ if (XmuCompareISOLatin1(s, "tack") == 0) done(XawFrameType, XawTACK);
+
+ XtDisplayStringConversionWarning(display, s, XtRFrameType);
+ printf("SimpleMenu.c");
+
+ done(XawFrameType, XawRAISED);
+}
+
+/* Function Name: ClassInitialize
+ * Description: Class Initialize routine, called only once.
+ * Arguments: none.
+ * Returns: none.
+ */
+
+static void
+ClassInitialize()
+{
+ XawInitializeWidgetSet();
+ XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0 );
+ XmuAddInitializer( AddPositionAction, NULL);
+
+ XtSetTypeConverter(XtRString, XtRFrameType, cvtStringToFrameType,
+ NULL, 0, XtCacheNone, NULL);
+}
+
+/* Function Name: ClassPartInitialize
+ * Description: Class Part Initialize routine, called for every
+ * subclass. Makes sure that the subclasses pick up
+ * the extension record.
+ * Arguments: wc - the widget class of the subclass.
+ * Returns: none.
+ */
+
+static void
+ClassPartInitialize(wc)
+WidgetClass wc;
+{
+ SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
+
+/*
+ * Make sure that our subclass gets the extension rec too.
+ */
+
+ extension_rec.next_extension = smwc->composite_class.extension;
+ smwc->composite_class.extension = (XtPointer) &extension_rec;
+}
+
+/* Function Name: Initialize
+ * Description: Initializes the simple menu widget
+ * Arguments: request - the widget requested by the argument list.
+ * new - the new widget with both resource and non
+ * resource values.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+Initialize(request, new)
+Widget request, new;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) new;
+ register SimpleMenuPart* smwp = (SimpleMenuPart*)&smw->simple_menu;
+
+ XmuCallInitializers(XtWidgetToApplicationContext(new));
+
+ if (smwp->label_class == NULL)
+ smwp->label_class = smeBSBObjectClass;
+
+ smwp->label = NULL;
+ smwp->entry_set = NULL;
+ smwp->recursive_set_values = False;
+
+ if (smwp->label_string != NULL)
+ CreateLabel(new);
+
+ smwp->menu_width = TRUE;
+
+ if (smw->core.width == 0)
+ {
+ smwp->menu_width = False;
+ smw->core.width = GetMenuWidth(new, NULL);
+ }
+
+ smwp->menu_height = TRUE;
+
+ if (smw->core.height == 0)
+ {
+ smwp->menu_height = False;
+ smw->core.height = GetMenuHeight(new);
+ }
+
+
+ /*
+ * Top & Bottom Shadow GCs
+ */
+
+ if (smwp->top_shadow_pixmap == UnspecifiedPixmap)
+ smwp->top_shadow_pixmap = None;
+
+ if (smwp->top_shadow_GC == NULL){
+ if (smwp->top_shadow_pixmap != None)
+ smwp->top_shadow_GC = AllocGCFromPixmap (new, smwp->top_shadow_pixmap);
+ else
+ smwp->top_shadow_GC = AllocGCFromPixel (new, smwp->top_shadow_color);
+ } else if (smwp->top_shadow_GC == UndefinedGC)
+ smwp->top_shadow_GC = MakeTopShadowGC (new, new->core.background_pixel);
+
+
+ if (smwp->bottom_shadow_pixmap == UnspecifiedPixmap)
+ smwp->bottom_shadow_pixmap = None;
+
+ if (smwp->bottom_shadow_GC == NULL){
+ if (smwp->bottom_shadow_pixmap != None)
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixmap (new, smwp->bottom_shadow_pixmap);
+ else
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixel (new, smwp->bottom_shadow_color);
+ } else if (smwp->bottom_shadow_GC == UndefinedGC)
+ smwp->bottom_shadow_GC =
+ MakeBottomShadowGC (new, new->core.background_pixel);
+}
+
+/* Function Name: Redisplay
+ * Description: Redisplays the contents of the widget.
+ * Arguments: w - the simple menu widget.
+ * event - the X event that caused this redisplay.
+ * region - the region the needs to be repainted.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void Redisplay(w, event, region)
+ Widget w;
+ XEvent * event;
+ Region region;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+ SmeObjectClass class;
+
+ if (region == NULL)
+ XClearWindow(XtDisplay(w), XtWindow(w));
+
+ /*
+ * Check and Paint each of the entries
+ */
+
+ ForAllChildren(smw, entry)
+ if (XtIsManaged ((Widget)*entry))
+ {
+ class = (SmeObjectClass) (*entry)->object.widget_class;
+
+ if (class->rect_class.expose)
+ (*class->rect_class.expose) ((Widget)*entry, NULL, region);
+ }
+
+ XawDrawFrame(w,
+ 0, 0, CORE(w).width, CORE(w).height,
+ SMW(w).frame_type,
+ SMW(w).shadow_thickness,
+ SMW(w).top_shadow_GC,
+ SMW(w).bottom_shadow_GC);
+
+}
+
+/* Function Name: Realize
+ * Description: Realizes the widget.
+ * Arguments: w - the simple menu widget.
+ * mask - value mask for the window to create.
+ * attrs - attributes for the window to create.
+ * Returns: none
+ */
+
+static void
+Realize(w, mask, attrs)
+Widget w;
+XtValueMask * mask;
+XSetWindowAttributes * attrs;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ attrs->cursor = smw->simple_menu.cursor;
+ *mask |= CWCursor;
+ if ((smw->simple_menu.backing_store == Always) ||
+ (smw->simple_menu.backing_store == NotUseful) ||
+ (smw->simple_menu.backing_store == WhenMapped) ) {
+ *mask |= CWBackingStore;
+ attrs->backing_store = smw->simple_menu.backing_store;
+ }
+ else
+ *mask &= ~CWBackingStore;
+
+ *mask |= CWSaveUnder;
+ attrs->save_under = True;
+
+ (*superclass->core_class.realize) (w, mask, attrs);
+}
+
+/* Function Name: Resize
+ * Description: Handle the menu being resized bigger.
+ * Arguments: w - the simple menu widget.
+ * Returns: none.
+ */
+
+static void Resize(w)
+ Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+
+ if ( !XtIsRealized(w) ) return;
+
+ ForAllChildren(smw, entry) /* reset width of all entries. */
+ if (XtIsManaged( (Widget) *entry)) {
+ (*entry)->rectangle.width = smw->core.width -
+ 2 * SMW(w).shadow_thickness;
+ (*entry)->rectangle.x = SMW(w).shadow_thickness;
+ }
+
+ XClearWindow(XtDisplay(w), XtWindow(w));
+
+ Redisplay(w, (XEvent *) NULL, (Region) NULL);
+
+}
+
+/* Function Name: SetValues
+ * Description: Relayout the menu when one of the resources is changed.
+ * Arguments: current - current state of the widget.
+ * request - what was requested.
+ * new - what the widget will become.
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new)
+ Widget current;
+ Widget request;
+ Widget new;
+{
+ SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
+ SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
+ register SimpleMenuPart* smwp = (SimpleMenuPart*)&smw_new->simple_menu;
+ Boolean ret_val = False;
+ Boolean layout = False;
+ Boolean redisplay = False;
+
+#define NE(name) (smw_old->simple_menu.name != smw_new->simple_menu.name)
+
+ if (!XtIsRealized(current))
+ return False;
+
+ if (!smw_new->simple_menu.recursive_set_values)
+ {
+ if (smw_new->core.width != smw_old->core.width)
+ {
+ smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
+ layout = TRUE;
+ }
+ if (smw_new->core.height != smw_old->core.height)
+ {
+ smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
+ layout = TRUE;
+ }
+ }
+
+ if (NE(cursor))
+ XDefineCursor(XtDisplay(new),
+ XtWindow(new), smw_new->simple_menu.cursor);
+
+ if (NE(label_string))
+ if (smw_new->simple_menu.label_string == NULL) /* Destroy. */
+ XtDestroyWidget((Widget)smw_old->simple_menu.label);
+ else if (smw_old->simple_menu.label_string == NULL) /* Create. */
+ CreateLabel(new);
+ else /* Change. */
+ XtVaSetValues((Widget)smw_new->simple_menu.label,
+ XtNlabel, smw_new->simple_menu.label_string,
+ NULL);
+
+ if (NE(label_class))
+ XtAppWarning(XtWidgetToApplicationContext(new),
+ "No Dynamic class change of the SimpleMenu Label.");
+
+ if (NE(top_margin) || NE(bottom_margin)) /* filler................. */
+ {
+ layout = TRUE;
+ ret_val = TRUE;
+ }
+
+ if (layout)
+ Layout(new, NULL, NULL);
+ {
+
+ if ( NE(shadow_thickness) )
+ redisplay = TRUE;
+
+ if (NE(top_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->top_shadow_GC);
+ smwp->top_shadow_GC = AllocGCFromPixmap (new, smwp->top_shadow_pixmap);
+ redisplay = True;
+
+ }
+ else if (NE(top_shadow_color && smwp->top_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->top_shadow_GC);
+ smwp->top_shadow_GC = AllocGCFromPixel (new, smwp->top_shadow_color);
+ redisplay = True;
+
+ }
+
+ if (NE(bottom_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->bottom_shadow_GC);
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixmap (new, smwp->bottom_shadow_pixmap);
+
+ redisplay = True;
+
+ }
+ else if (NE(bottom_shadow_color && smwp->bottom_shadow_pixmap))
+ {
+
+ XtReleaseGC (new, smwp->bottom_shadow_GC);
+ smwp->bottom_shadow_GC =
+ AllocGCFromPixel (new, smwp->bottom_shadow_color);
+ redisplay = True;
+
+ }
+
+#undef NE
+ }
+
+ return(ret_val || redisplay);
+}
+
+/* Function Name: SetValuesHook
+ * Description: To handle a special case, this is passed the
+ * actual arguments.
+ * Arguments: w - the menu widget.
+ * arglist - the argument list passed to XtSetValues.
+ * num_args - the number of args.
+ * Returns: none
+ */
+
+/*
+ * If the user actually passed a width and height to the widget
+ * then this MUST be used, rather than our newly calculated width and
+ * height.
+ */
+
+static Boolean
+SetValuesHook(w, arglist, num_args)
+Widget w;
+ArgList arglist;
+Cardinal *num_args;
+{
+ register Cardinal i;
+ Dimension width, height;
+
+ width = w->core.width;
+ height = w->core.height;
+
+ for ( i = 0 ; i < *num_args ; i++) {
+ if ( streq(arglist[i].name, XtNwidth) )
+ width = (Dimension) arglist[i].value;
+ if ( streq(arglist[i].name, XtNheight) )
+ height = (Dimension) arglist[i].value;
+ }
+
+ if ((width != w->core.width) || (height != w->core.height))
+ MakeSetValuesRequest(w, width, height);
+ return(False);
+}
+
+/************************************************************
+ *
+ * Geometry Management routines.
+ *
+ ************************************************************/
+
+/* Function Name: GeometryManager
+ * Description: This is the SimpleMenu Widget's Geometry Manager.
+ * Arguments: w - the Menu Entry making the request.
+ * request - requested new geometry.
+ * reply - the allowed geometry.
+ * Returns: XtGeometry{Yes, No, Almost}.
+ */
+
+static XtGeometryResult
+GeometryManager(w, request, reply)
+Widget w;
+XtWidgetGeometry * request, * reply;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
+ SmeObject entry = (SmeObject) w;
+ XtGeometryMask mode = request->request_mode;
+ XtGeometryResult answer;
+ Dimension old_height, old_width;
+
+ if ( !(mode & CWWidth) && !(mode & CWHeight) )
+ return(XtGeometryNo);
+
+ reply->width = request->width;
+ reply->height = request->height;
+
+ old_width = entry->rectangle.width;
+ old_height = entry->rectangle.height;
+
+ Layout(w, &(reply->width), &(reply->height) );
+
+/*
+ * Since we are an override shell and have no parent there is no one to
+ * ask to see if this geom change is okay, so I am just going to assume
+ * we can do whatever we want. If you subclass be very careful with this
+ * assumption, it could bite you.
+ *
+ * Chris D. Peterson - Sept. 1989.
+ */
+
+ if ( (reply->width == request->width) &&
+ (reply->height == request->height) ) {
+
+ if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
+ entry->rectangle.width = old_width;
+ entry->rectangle.height = old_height;
+ }
+ else {
+ Layout(( Widget) smw, NULL, NULL);
+ }
+ answer = XtGeometryDone;
+ }
+ else {
+ entry->rectangle.width = old_width;
+ entry->rectangle.height = old_height;
+
+ if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
+ ((reply->height == request->height) && !(mode & CWWidth)) ||
+ ((reply->width == request->width) &&
+ (reply->height == request->height)) )
+ answer = XtGeometryNo;
+ else {
+ answer = XtGeometryAlmost;
+ reply->request_mode = 0;
+ if (reply->width != request->width)
+ reply->request_mode |= CWWidth;
+ if (reply->height != request->height)
+ reply->request_mode |= CWHeight;
+ }
+ }
+ return(answer);
+}
+
+/* Function Name: ChangeManaged
+ * Description: called whenever a new child is managed.
+ * Arguments: w - the simple menu widget.
+ * Returns: none.
+ */
+
+static void
+ChangeManaged(w)
+Widget w;
+{
+ Layout(w, NULL, NULL);
+}
+
+/************************************************************
+ *
+ * Global Action Routines.
+ *
+ * These actions routines will be added to the application's
+ * global action list.
+ *
+ ************************************************************/
+
+/* Function Name: PositionMenuAction
+ * Description: Positions the simple menu widget.
+ * Arguments: w - a widget (no the simple menu widget.)
+ * event - the event that caused this action.
+ * params, num_params - parameters passed to the routine.
+ * we expect the name of the menu here.
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+PositionMenuAction(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ Widget menu;
+ XPoint loc;
+
+ if (*num_params != 1) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s %s",
+ "Xaw - SimpleMenuWidget: position menu action expects only one",
+ "parameter which is the name of the menu.");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ if ( (menu = FindMenu(w, params[0])) == NULL) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s '%s'",
+ "Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ loc.x = event->xbutton.x_root;
+ loc.y = event->xbutton.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ loc.x = event->xcrossing.x_root;
+ loc.y = event->xcrossing.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ case MotionNotify:
+ loc.x = event->xmotion.x_root;
+ loc.y = event->xmotion.y_root;
+ PositionMenu(menu, &loc);
+ break;
+ default:
+ PositionMenu(menu, NULL);
+ break;
+ }
+}
+
+/************************************************************
+ *
+ * Widget Action Routines.
+ *
+ ************************************************************/
+
+/* Function Name: Unhighlight
+ * Description: Unhighlights current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Unhighlight(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry = smw->simple_menu.entry_set;
+ SmeObjectClass class;
+
+ if ( entry == NULL) return;
+
+ smw->simple_menu.entry_set = NULL;
+ class = (SmeObjectClass) entry->object.widget_class;
+ (class->sme_class.unhighlight) ( (Widget) entry);
+}
+
+/* Function Name: Highlight
+ * Description: Highlights current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Highlight(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry;
+ SmeObjectClass class;
+
+ if ( !XtIsSensitive(w) ) return;
+
+ entry = GetEventEntry(w, event);
+
+ if (entry == smw->simple_menu.entry_set) return;
+
+ Unhighlight(w, event, params, num_params);
+
+ if (entry == NULL) return;
+
+ if ( !XtIsSensitive( (Widget) entry)) {
+ smw->simple_menu.entry_set = NULL;
+ return;
+ }
+
+ smw->simple_menu.entry_set = entry;
+ class = (SmeObjectClass) entry->object.widget_class;
+
+ (class->sme_class.highlight) ( (Widget) entry);
+}
+
+/* Function Name: Notify
+ * Description: Notify user of current entry.
+ * Arguments: w - the simple menu widget.
+ * event - the event that caused this action.
+ * params, num_params - ** NOT USED **
+ * Returns: none
+ */
+
+/* ARGSUSED */
+static void
+Notify(w, event, params, num_params)
+Widget w;
+XEvent * event;
+String * params;
+Cardinal * num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry = smw->simple_menu.entry_set;
+ SmeObjectClass class;
+
+ if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
+
+ class = (SmeObjectClass) entry->object.widget_class;
+ (class->sme_class.notify)( (Widget) entry );
+}
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawSimpleMenuAddGlobalActions
+ * Description: adds the global actions to the simple menu widget.
+ * Arguments: app_con - the appcontext.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuAddGlobalActions(app_con)
+XtAppContext app_con;
+{
+ XtInitializeWidgetClass(simpleMenuWidgetClass);
+ XmuCallInitializers( app_con );
+}
+
+
+/* Function Name: XawSimpleMenuGetActiveEntry
+ * Description: Gets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: the currently set entry or NULL if none is set.
+ */
+
+Widget
+XawSimpleMenuGetActiveEntry(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ return( (Widget) smw->simple_menu.entry_set);
+}
+
+/* Function Name: XawSimpleMenuClearActiveEntry
+ * Description: Unsets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuClearActiveEntry(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ smw->simple_menu.entry_set = NULL;
+}
+
+/************************************************************
+ *
+ * Private Functions.
+ *
+ ************************************************************/
+
+/* Function Name: CreateLabel
+ * Description: Creates a the menu label.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ *
+ * Creates the label object and makes sure it is the first child in
+ * in the list.
+ */
+
+static void
+CreateLabel(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ register Widget * child, * next_child;
+ register int i;
+ Arg args[2];
+
+ if ( (smw->simple_menu.label_string == NULL) ||
+ (smw->simple_menu.label != NULL) ) {
+ char error_buf[BUFSIZ];
+
+ sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
+ "label string is NULL", "label already exists",
+ "no label is being created.");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+
+ XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
+ XtSetArg(args[1], XtNjustify, XtJustifyCenter);
+ smw->simple_menu.label = (SmeObject)
+ XtCreateManagedWidget("menuLabel",
+ smw->simple_menu.label_class, w,
+ args, TWO);
+
+ next_child = NULL;
+ for (child = smw->composite.children + smw->composite.num_children,
+ i = smw->composite.num_children ; i > 0 ; i--, child--) {
+ if (next_child != NULL)
+ *next_child = *child;
+ next_child = child;
+ }
+ *child = (Widget) smw->simple_menu.label;
+}
+
+/* Function Name: Layout
+ * Description: lays the menu entries out all nice and neat.
+ * Arguments: w - See below (+++)
+ * width_ret, height_ret - The returned width and
+ * height values.
+ * Returns: none.
+ *
+ * if width == NULL || height == NULL then it assumes the you do not care
+ * about the return values, and just want a relayout.
+ *
+ * if this is not the case then it will set width_ret and height_ret
+ * to be width and height that the child would get if it were layed out
+ * at this time.
+ *
+ * +++ "w" can be the simple menu widget or any of its object children.
+ */
+
+static void
+Layout(w, width_ret, height_ret)
+Widget w;
+Dimension *width_ret, *height_ret;
+{
+ SmeObject current_entry, *entry;
+ SimpleMenuWidget smw;
+ Dimension width, height;
+ Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
+ Boolean allow_change_size;
+ height = 0;
+
+ if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
+ smw = (SimpleMenuWidget) w;
+ current_entry = NULL;
+ }
+ else {
+ smw = (SimpleMenuWidget) XtParent(w);
+ current_entry = (SmeObject) w;
+ }
+
+ allow_change_size = (!XtIsRealized((Widget)smw) ||
+ (smw->shell.allow_shell_resize));
+
+ if ( smw->simple_menu.menu_height )
+ height = smw->core.height;
+ else
+ if (do_layout) {
+ height = smw->simple_menu.top_margin;
+ height += smw->simple_menu.shadow_thickness;
+ ForAllChildren(smw, entry) {
+ if (!XtIsManaged( (Widget) *entry)) continue;
+
+ if ( (smw->simple_menu.row_height != 0) &&
+ (*entry != smw->simple_menu.label) )
+ (*entry)->rectangle.height = smw->simple_menu.row_height;
+
+ (*entry)->rectangle.y = height;
+ (*entry)->rectangle.x = smw->simple_menu.shadow_thickness;
+ height += (*entry)->rectangle.height;
+ }
+ height += smw->simple_menu.bottom_margin;
+ height += smw->simple_menu.shadow_thickness;
+ }
+ else {
+ if ((smw->simple_menu.row_height != 0) &&
+ (current_entry != smw->simple_menu.label) )
+ height = smw->simple_menu.row_height;
+ }
+
+ if (smw->simple_menu.menu_width)
+ width = smw->core.width;
+ else if ( allow_change_size ){
+ width = GetMenuWidth((Widget) smw, (Widget) current_entry);
+ width +=2*smw->simple_menu.shadow_thickness;
+ }
+ else
+ width = smw->core.width;
+
+ if (do_layout) {
+ ForAllChildren(smw, entry)
+ if (XtIsManaged( (Widget) *entry))
+ (*entry)->rectangle.width = width -
+ 2*smw->simple_menu.shadow_thickness;
+
+ if (allow_change_size)
+ MakeSetValuesRequest((Widget) smw, width, height);
+ }
+ else {
+ *width_ret = width;
+ if (height != 0)
+ *height_ret = height;
+ }
+}
+
+/* Function Name: AddPositionAction
+ * Description: Adds the XawPositionSimpleMenu action to the global
+ * action list for this appcon.
+ * Arguments: app_con - the application context for this app.
+ * data - NOT USED.
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+AddPositionAction(app_con, data)
+XtAppContext app_con;
+XtPointer data;
+{
+ static XtActionsRec pos_action[] = {
+ { "XawPositionSimpleMenu", PositionMenuAction },
+ };
+
+ XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
+}
+
+/* Function Name: FindMenu
+ * Description: Find the menu give a name and reference widget.
+ * Arguments: widget - reference widget.
+ * name - the menu widget's name.
+ * Returns: the menu widget or NULL.
+ */
+
+static Widget
+FindMenu(widget, name)
+Widget widget;
+String name;
+{
+ register Widget w, menu;
+
+ for ( w = widget ; w != NULL ; w = XtParent(w) )
+ if ( (menu = XtNameToWidget(w, name)) != NULL )
+ return(menu);
+ return(NULL);
+}
+
+/* Function Name: MoveMenu
+ * Description: Actually moves the menu, may force it to
+ * to be fully visable if menu_on_screen is TRUE.
+ * Arguments: w - the simple menu widget.
+ * x, y - the current location of the widget.
+ * Returns: none
+ */
+
+static void
+MoveMenu(w, x, y)
+Widget w;
+Position x, y;
+{
+ Arg arglist[2];
+ Cardinal num_args = 0;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+
+ if (smw->simple_menu.menu_on_screen) {
+ int width = w->core.width + 2 * w->core.border_width;
+ int height = w->core.height + 2 * w->core.border_width;
+
+ if (x < 0)
+ x = 0;
+ else {
+ int scr_width = WidthOfScreen(XtScreen(w));
+ if (x + width > scr_width)
+ x = scr_width - width;
+ }
+
+ if (y < 0)
+ y = 0;
+ else {
+ int scr_height = HeightOfScreen(XtScreen(w));
+ if (y + height > scr_height)
+ y = scr_height - height;
+ }
+ }
+
+ XtSetArg(arglist[num_args], XtNx, x); num_args++;
+ XtSetArg(arglist[num_args], XtNy, y); num_args++;
+ XtSetValues(w, arglist, num_args);
+}
+
+/* Function Name: PositionMenu
+ * Description: Places the menu
+ * Arguments: w - the simple menu widget.
+ * location - a pointer the the position or NULL.
+ * Returns: none.
+ */
+
+static void
+PositionMenu(w, location)
+Widget w;
+XPoint * location;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject entry;
+ XPoint t_point;
+
+ if (location == NULL) {
+ Window junk1, junk2;
+ int root_x, root_y, junkX, junkY;
+ unsigned int junkM;
+
+ location = &t_point;
+ if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2,
+ &root_x, &root_y, &junkX, &junkY, &junkM) == False) {
+ char error_buf[BUFSIZ];
+ sprintf(error_buf, "%s %s", "Xaw - SimpleMenuWidget:",
+ "Could not find location of mouse pointer");
+ XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
+ return;
+ }
+ location->x = (short) root_x;
+ location->y = (short) root_y;
+ }
+
+ /*
+ * The width will not be correct unless it is realized.
+ */
+
+ XtRealizeWidget(w);
+
+ location->x -= (Position) w->core.width/2;
+
+ if (smw->simple_menu.popup_entry == NULL)
+ entry = smw->simple_menu.label;
+ else
+ entry = smw->simple_menu.popup_entry;
+
+ if (entry != NULL)
+ location->y -= entry->rectangle.y + entry->rectangle.height/2;
+
+ MoveMenu(w, (Position) location->x, (Position) location->y);
+}
+
+/* Function Name: MakeSetValuesRequest
+ * Description: Makes a (possibly recursive) call to SetValues,
+ * I take great pains to not go into an infinite loop.
+ * Arguments: w - the simple menu widget.
+ * width, height - the size of the ask for.
+ * Returns: none
+ */
+
+static void
+MakeSetValuesRequest(w, width, height)
+Widget w;
+Dimension width, height;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ Arg arglist[2];
+ Cardinal num_args = (Cardinal) 0;
+
+ if ( !smw->simple_menu.recursive_set_values ) {
+ if ( (smw->core.width != width) || (smw->core.height != height) ) {
+ smw->simple_menu.recursive_set_values = TRUE;
+ XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
+ XtSetArg(arglist[num_args], XtNheight, height); num_args++;
+ XtSetValues(w, arglist, num_args);
+ }
+ else if (XtIsRealized( (Widget) smw))
+ Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
+ }
+ smw->simple_menu.recursive_set_values = False;
+}
+
+/* Function Name: GetMenuWidth
+ * Description: Sets the length of the widest entry in pixels.
+ * Arguments: w - the simple menu widget.
+ * Returns: width of menu.
+ */
+
+static Dimension
+GetMenuWidth(w, w_ent)
+Widget w, w_ent;
+{
+ SmeObject cur_entry = (SmeObject) w_ent;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ Dimension width, widest = (Dimension) 0;
+ SmeObject * entry;
+
+ if ( smw->simple_menu.menu_width )
+ return(smw->core.width);
+
+ ForAllChildren(smw, entry) {
+ XtWidgetGeometry preferred;
+
+ if (!XtIsManaged( (Widget) *entry)) continue;
+
+ if (*entry != cur_entry) {
+ XtQueryGeometry((Widget)*entry, NULL, &preferred);
+
+ if (preferred.request_mode & CWWidth)
+ width = preferred.width;
+ else
+ width = (*entry)->rectangle.width;
+ }
+ else
+ width = (*entry)->rectangle.width;
+
+ if ( width > widest )
+ widest = width;
+ }
+
+ return(widest);
+}
+
+/* Function Name: GetMenuHeight
+ * Description: Sets the length of the widest entry in pixels.
+ * Arguments: w - the simple menu widget.
+ * Returns: width of menu.
+ */
+
+static Dimension
+GetMenuHeight(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+ Dimension height;
+
+ if (smw->simple_menu.menu_height)
+ return(smw->core.height);
+
+ height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
+
+ if (smw->simple_menu.row_height == 0)
+ ForAllChildren(smw, entry)
+ if (XtIsManaged ((Widget) *entry))
+ height += (*entry)->rectangle.height;
+ else
+ height += smw->simple_menu.row_height * smw->composite.num_children;
+
+ return(height);
+}
+
+/* Function Name: GetEventEntry
+ * Description: Gets an entry given an event that has X and Y coords.
+ * Arguments: w - the simple menu widget.
+ * event - the event.
+ * Returns: the entry that this point is in.
+ */
+
+static SmeObject
+GetEventEntry(w, event)
+Widget w;
+XEvent * event;
+{
+ Position x_loc, y_loc;
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ SmeObject * entry;
+
+ switch (event->type) {
+ case MotionNotify:
+ x_loc = event->xmotion.x;
+ y_loc = event->xmotion.y;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ x_loc = event->xcrossing.x;
+ y_loc = event->xcrossing.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ x_loc = event->xbutton.x;
+ y_loc = event->xbutton.y;
+ break;
+ default:
+ XtAppError(XtWidgetToApplicationContext(w),
+ "Unknown event type in GetEventEntry().");
+ break;
+ }
+
+ if ( (x_loc < 0) || (x_loc >= smw->core.width) || (y_loc < 0) ||
+ (y_loc >= smw->core.height) )
+ return(NULL);
+
+ ForAllChildren(smw, entry) {
+ if (!XtIsManaged ((Widget) *entry)) continue;
+
+ if ( ((*entry)->rectangle.y <= y_loc) &&
+ ((*entry)->rectangle.y + (*entry)->rectangle.height >= y_loc) )
+ if ( *entry == smw->simple_menu.label )
+ return(NULL); /* cannot select the label. */
+ else
+ return(*entry);
+ }
+
+ return(NULL);
+}
diff --git a/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h b/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h
new file mode 100644
index 00000000..752be892
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h
@@ -0,0 +1,169 @@
+/*
+ * $XConsortium: SimpleMenu.h,v 1.17 89/12/11 15:01:55 kit Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris D. Peterson, MIT X Consortium
+ */
+
+/*
+ * SimpleMenu.h - Public Header file for SimpleMenu widget.
+ *
+ * This is the public header file for the Athena SimpleMenu widget.
+ * It is intended to provide one pane pulldown and popup menus within
+ * the framework of the X Toolkit. As the name implies it is a first and
+ * by no means complete implementation of menu code. It does not attempt to
+ * fill the needs of all applications, but does allow a resource oriented
+ * interface to menus.
+ *
+ * Date: April 3, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifndef _SimpleMenu_h
+#define _SimpleMenu_h
+
+#include <X11/Shell.h>
+#include <X11/Xmu/Converters.h>
+
+/****************************************************************
+ *
+ * SimpleMenu widget
+ *
+ ****************************************************************/
+
+/* SimpleMenu Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background Pixel XtDefaultBackground
+ backgroundPixmap BackgroundPixmap Pixmap None
+ borderColor BorderColor Pixel XtDefaultForeground
+ borderPixmap BorderPixmap Pixmap None
+ borderWidth BorderWidth Dimension 1
+ bottomMargin VerticalMargins Dimension VerticalSpace
+ columnWidth ColumnWidth Dimension Width of widest text
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ height Height Dimension 0
+ label Label String NULL (No label)
+ labelClass LabelClass Pointer smeBSBObjectClass
+ mappedWhenManaged MappedWhenManaged Boolean True
+ rowHeight RowHeight Dimension Height of Font
+ sensitive Sensitive Boolean True
+ topMargin VerticalMargins Dimension VerticalSpace
+ width Width Dimension 0
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+typedef struct _SimpleMenuClassRec* SimpleMenuWidgetClass;
+typedef struct _SimpleMenuRec* SimpleMenuWidget;
+
+extern WidgetClass simpleMenuWidgetClass;
+
+#define XtNcursor "cursor"
+#define XtNbottomMargin "bottomMargin"
+#define XtNcolumnWidth "columnWidth"
+#define XtNlabelClass "labelClass"
+#define XtNmenuOnScreen "menuOnScreen"
+#define XtNpopupOnEntry "popupOnEntry"
+#define XtNrowHeight "rowHeight"
+#define XtNtopMargin "topMargin"
+
+#define XtCColumnWidth "ColumnWidth"
+#define XtCLabelClass "LabelClass"
+#define XtCMenuOnScreen "MenuOnScreen"
+#define XtCPopupOnEntry "PopupOnEntry"
+#define XtCRowHeight "RowHeight"
+#define XtCVerticalMargins "VerticalMargins"
+
+/* New fields */
+#define XtNshadowWidth "shadowWidth"
+#define XtCShadowWidth "ShadowWidth"
+#define XtNbsbShadowWidth "bsbShadowWidth"
+#define XtCBsbShadowWidth "BsbShadowWidth"
+#define XtNtopShadowPixel "topShadowPixel"
+#define XtCTopShadowPixel "TopShadowPixel"
+#define XtNbottomShadowPixel "bottomShadowPixel"
+#define XtCBottomShadowPixel "BottomShadowPixel"
+#define XtNtopShadowContrast "topShadowContrast"
+#define XtCTopShadowContrast "TopShadowContrast"
+#define XtNbottomShadowContrast "bottomShadowContrast"
+#define XtCBottomShadowContrast "BottomShadowContrast"
+#define XtNbeNiceToColormap "beNiceToColormap"
+#define XtCBeNiceToColormap "BeNiceToColormap"
+#define XtNtopShadowPixmap "topShadowPixmap"
+#define XtCTopShadowPixmap "TopShadowPixmap"
+#define XtNbottomShadowPixmap "bottomShadowPixmap"
+#define XtCBottomShadowPixmap "BottomShadowPixmap"
+#define XtNuserData "userData"
+#define XtCUserData "UserData"
+#define XtNframeType "frameType"
+#define XtCFrameType "FrameType"
+#define XtRFrameType "FrameType"
+
+/************************************************************
+ *
+ * Public Functions.
+ *
+ ************************************************************/
+
+/* Function Name: XawSimpleMenuAddGlobalActions
+ * Description: adds the global actions to the simple menu widget.
+ * Arguments: app_con - the appcontext.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuAddGlobalActions(/* app_con */);
+/*
+XtAppContext app_con;
+*/
+
+/* Function Name: XawSimpleMenuGetActiveEntry
+ * Description: Gets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: the currently set entry or NULL if none is set.
+ */
+
+Widget
+XawSimpleMenuGetActiveEntry( /* w */);
+/*
+Widget w;
+*/
+
+/* Function Name: XawSimpleMenuClearActiveEntry
+ * Description: Unsets the currently active (set) entry.
+ * Arguments: w - the smw widget.
+ * Returns: none.
+ */
+
+void
+XawSimpleMenuClearActiveEntry(/* w */);
+/*
+Widget w;
+*/
+
+#endif /* _SimpleMenu_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/SimpleP.h b/vendor/x11iraf/obm/ObmW/zz/SimpleP.h
new file mode 100644
index 00000000..f4044709
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/SimpleP.h
@@ -0,0 +1,62 @@
+#ifndef _SimpleP_h
+#define _SimpleP_h
+
+#include <X11/IntrinsicP.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/Simple.h>
+
+#define SIMPLE(w) ((SimpleWidget) w)->simple
+
+typedef Boolean (*XawDisplayRectProc) Xraw_PROTO((Widget, XRectangle * ));
+typedef Boolean (*XawChangeSensitive) Xraw_PROTO((Widget));
+
+typedef struct {
+ XawChangeSensitive change_sensitive;
+ XawDisplayRectProc display_rect;
+ caddr_t extension;
+} SimpleClassPart;
+
+typedef struct _SimpleClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+} SimpleClassRec;
+
+extern SimpleClassRec simpleClassRec;
+
+typedef struct {
+ /* resources */
+ Cursor cursor;
+ Pixmap insensitive_border;
+ Pixel foreground;
+
+ Dimension shadow_thickness;
+ Pixel top_shadow_color;
+ Pixmap top_shadow_pixmap;
+ Pixel bottom_shadow_color;
+ Pixmap bottom_shadow_pixmap;
+ Pixel highlight_color;
+ Pixmap highlight_pixmap;
+ Dimension highlight_thickness;
+
+ caddr_t user_data;
+
+ /* private state */
+ GC top_shadow_GC;
+ GC bottom_shadow_GC;
+ GC highlight_GC;
+} SimplePart;
+
+typedef struct _SimpleRec {
+ CorePart core;
+ SimplePart simple;
+} SimpleRec;
+
+#define SIMPLE_MARGIN(w) (((SimpleWidget)w)->simple.highlight_thickness + \
+ ((SimpleWidget)w)->simple.shadow_thickness)
+
+#define XtSimpleClass(w) ((SimpleWidgetClass)XtClass(w))
+#define XtInheritDisplayRectProc ((Boolean (*)())_XtInherit)
+#define XtInheritChangeSensitive ((Boolean (*)())_XtInherit)
+
+#endif /* _SimpleP_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/Table.c b/vendor/x11iraf/obm/ObmW/zz/Table.c
new file mode 100644
index 00000000..a5387810
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Table.c
@@ -0,0 +1,4529 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+#include <X11/IntrinsicP.h>
+#include <X11/RectObjP.h>
+#include <X11/StringDefs.h>
+#include <X11/keysym.h>
+#include <X11/Xos.h>
+
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/Drawing.h>
+
+#include <X11/Xraw/XawInit.h>
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/TableP.h>
+#include <X11/Xraw/Frame.h>
+#include <X11/Xraw/AsciiText.h>
+#include <X11/Xraw/Viewport.h>
+#include <X11/Xraw/Scrollbar.h>
+#include <X11/Xraw/ScrolledTable.h>
+
+#ifdef EBUG_XRAW_MALLOC
+#include <dbmalloc/malloc.h>
+#endif
+
+#define MULTI_LINE_TABLE 32767
+
+
+#undef CELL_IN /* */
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define CALLOC(num,type) (num * sizeof(type) <= 0 ? (type*)NULL : \
+ (type*)XtMalloc((Cardinal)(num) * (Cardinal)sizeof(type)))
+
+#define NOT_A_CUT_BUFFER (-1)
+
+#define MAXCUT 30000
+#define EDIT(w) (((XawTableWidget) w)->table.edit)
+#define InRange(n,a,b) MAX(a,MIN(n,b))
+
+#define LEFT_EDGE(tw) (((XawTableWidget)tw)->table.internal_width + \
+ ((XawTableWidget)tw)->table.label_shadow_thickness)
+
+#define TOP_EDGE(tw) (((XawTableWidget)tw)->table.internal_height + \
+ ((XawTableWidget)tw)->table.label_shadow_thickness)
+
+#define CELL(field) cell->field
+#define STUFF(w) ((XawTableWidget)w)->table.table_stuff
+#define COLUMNS(w) ((XawTableWidget)w)->table.columns
+#define ROWS(w) ((XawTableWidget)w)->table.rows
+#define GET_CELL_LABEL ((CELL(label) == NULL ? Dummy : CELL(label)))
+
+#define COLUMN_DATA(tw) ((XawTableColumnRec*)tw->table.column_data)
+#define COLUMN_WIDTH(tw,column) \
+(tw->table.literal ? \
+ ( \
+ (COLUMN_DATA(tw)[column].flag & _CL_width) ?\
+ COLUMN_DATA(tw)[column].width : \
+ tw->table.column_default_width \
+ ) \
+ * tw->table.literal_width + \
+ 2 * tw->table.internal_width \
+ : \
+ ( \
+ (COLUMN_DATA(tw)[column].flag & _CL_width) ?\
+ COLUMN_DATA(tw)[column].width : \
+ tw->table.column_default_width \
+ ) \
+/* _COLUMN_WIDTH_ */)
+
+
+#define MANAGE_EDIT(tw) \
+ if ( ! XtIsManaged(EDIT(tw))) \
+ { \
+ XtManageChild (EDIT(tw)); \
+ XtSetKeyboardFocus ((Widget)tw, EDIT(tw)); \
+ }
+
+
+#define UNMANAGE_EDIT(tw) \
+ if ( XtIsManaged(EDIT(tw))) \
+ { \
+ XtUnmanageChild (tw->table.edit); \
+ XtSetKeyboardFocus((Widget)tw, (Widget)None); \
+ }
+
+
+#define DO_CALLBACK(w,callback,data) \
+ if (XtCallbackHasSome == XtHasCallbacks(w, callback)) \
+ XtCallCallbacks (w, callback, (XtPointer)&data)
+
+
+#define IsEditInRowColumn(tw, row, column) \
+ (XtIsManaged(EDIT(tw)) && (row == tw->table.edit_row) \
+ && (column == tw->table.edit_column))
+
+
+
+#define REJECT (-1)
+#define ACCEPT (0)
+
+#define CHECK_TABLE(tw) \
+ _check_table ((XtPointer)STUFF(tw), ROWS(tw), COLUMNS(tw)); \
+ CheckAllLabels(tw)
+
+
+
+typedef struct _XawTableCellRec {
+ /* Node communication entity */
+ XawTableNodeRec node;
+ /* Cell label entity */
+ char *label;
+ Position label_x;
+ Dimension label_width;
+ Dimension label_len;
+ /* Cell colour entity */
+ Boolean highlight;
+ Boolean special_colour;
+ Pixel fore;
+ Pixel back;
+ GC normal;
+ GC reverse;
+ GC top;
+ GC bottom;
+
+}XawTableCellRec;
+
+#define _CL_width (1L<<0)
+#define _CL_font (1L<<1)
+#define _CL_label (1L<<2)
+#define _CL_justify (1L<<3)
+#define _CL_background (1L<<4)
+#define _CL_foreground (1L<<5)
+
+typedef struct _XawTableColumnRec {
+ int flag;
+ int width;
+ XFontStruct *font;
+ char *label;
+ XtJustify justify;
+ Pixel background;
+ Pixel foreground;
+ GC normal;
+ GC reverse;
+ GC top;
+ GC bottom;
+}XawTableColumnRec;
+
+
+#ifdef CRAY
+#define WORD64
+#endif
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+static void Def_pixel();
+static void Def_scroll();
+static void Def_column_default_width();
+static void Def_literal_width();
+static void Def_shadow_thickness();
+
+#define Offset(field) XtOffsetOf(TableRec, field)
+
+static XtResource resources[] = {
+ {
+ XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.foreground), XtRString, XtDefaultForeground
+ },
+ {
+ XtNeditForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.edit_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNeditBackground, XtCBackground, XtRPixel, sizeof(Pixel),
+ Offset(table.edit_back), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNrowForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.row_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNcolumnForeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(table.column_fore), XtRCallProc, (XtPointer)Def_pixel
+ },
+ {
+ XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ Offset(table.font), XtRString, XtDefaultFont
+ },
+ {
+ XtNliteral, XtCLiteral, XtRBoolean, sizeof(Boolean),
+ Offset(table.literal), XtRImmediate, (XtPointer)False
+ },
+ {
+ XtNrowOriented, XtCRowOriented, XtRBoolean, sizeof(Boolean),
+ Offset(table.row_oriented), XtRImmediate, (XtPointer)True
+ },
+ {
+ XtNmaskNumber, XtCMaskNumber, XtRInt, sizeof(int),
+ Offset(table.mask_number), XtRImmediate, (XtPointer)7
+ },
+ {
+ XtNcolumns, XtCColumns, XtRInt, sizeof(int),
+ Offset(table.columns), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNrows, XtCRows, XtRInt, sizeof(int),
+ Offset(table.rows), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNtableMargin, XtCTableMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.tab_margin), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNrowMargin, XtCRowMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.row_margin), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNcolumnMargin, XtCColumnMargin, XtRDimension, sizeof(Dimension),
+ Offset(table.col_margin), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNlabelShadowWidth, XtCLabelShadowWidth, XtRDimension,
+ sizeof(Dimension), Offset(table.label_shadow_thickness), XtRImmediate,
+ (XtPointer)1
+ },
+ {
+ XtNjustify, XtCJustify, XtRJustify, sizeof(XtJustify),
+ Offset(table.justify), XtRImmediate, (XtPointer)XtJustifyCenter
+ },
+ {
+ XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ Offset(table.internal_width), XtRImmediate, (XtPointer)4
+ },
+ {
+ XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
+ Offset(table.internal_height), XtRImmediate, (XtPointer)2
+ },
+ {
+ XtNencoding, XtCEncoding, XtRUnsignedChar, sizeof(unsigned char),
+ Offset(table.encoding), XtRImmediate, (XtPointer)XawTextEncoding8bit
+ },
+ {
+ XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ Offset(container.shadow_thickness), XtRCallProc,
+ (XtPointer) Def_shadow_thickness
+ },
+ {
+ XtNvetricalScroll, XtCScroll, XtRWidget, sizeof(Widget),
+ Offset(table.v_scroll), XtRCallProc, (XtPointer)Def_scroll
+ },
+ {
+ XtNhorizontalScroll, XtCScroll, XtRWidget, sizeof(Widget),
+ Offset(table.h_scroll), XtRCallProc, (XtPointer)Def_scroll
+ },
+ {
+ XtNrowHeight, XtCRowHeight, XtRInt, sizeof(int),
+ Offset(table.row_height), XtRImmediate, (XtPointer)0
+ },
+ {
+ XtNdefaultWidth, XtCDefaultWidth, XtRInt, sizeof(int),
+ Offset(table.column_default_width), XtRCallProc,
+ (XtPointer) Def_column_default_width
+ },
+ {
+ XtNeditable, XtCEditable, XtRBoolean, sizeof(Boolean),
+ Offset(table.editable), XtRImmediate, (XtPointer) TRUE
+ },
+ {
+ XtNliteralWidth, XtCLiteralWidth, XtRInt, sizeof(int),
+ Offset(table.literal_width), XtRCallProc, (XtPointer) Def_literal_width
+ },
+
+ /* ALLOWANCE CALLBACKS */
+ {
+ XtNallowAddColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_add_column), XtRCallback, NULL
+ },
+ {
+ XtNallowAddRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_add_row), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_column), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_row), XtRCallback, NULL
+ },
+ {
+ XtNallowDeleteTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.allow_delete_table), XtRCallback, NULL
+ },
+ /* INFORMATION CALLBACKS */
+
+ {
+ XtNaddColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.add_column), XtRCallback, NULL
+ },
+ {
+ XtNaddRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.add_row), XtRCallback, NULL
+ },
+ {
+ XtNcreateTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.create_table), XtRCallback, NULL
+ },
+ {
+ XtNchangedCell, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_cell), XtRCallback, NULL
+ },
+ {
+ XtNchangedColumnWidth, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_column_width), XtRCallback, NULL
+ },
+ {
+ XtNchangedRowHeight, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.changed_row_height), XtRCallback, NULL
+ },
+ {
+ XtNdeleteColumn, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_column), XtRCallback, NULL
+ },
+ {
+ XtNdeleteRow, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_row), XtRCallback, NULL
+ },
+ {
+ XtNdeleteTable, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.delete_table), XtRCallback, NULL
+ },
+ {
+ XtNwhatCell, XtCCallback, XtRCallback, sizeof(XtPointer),
+ Offset(table.what_cell), XtRCallback, NULL
+ },
+};
+
+#define PRINTF_BOOL(a) ((a) ? "TRUE":"FALSE")
+#define PRINTF_NULL(a) ((a)==NULL ? "NULL":"not NULL")
+
+static void Def_pixel(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ static Pixel pix = 0;
+
+
+ if ( offset == (int)Offset(table.edit_fore))
+ pix = tw->table.foreground;
+ else if ( offset == (int)Offset(table.edit_back))
+ {
+ if (!FetchPixel(w, "#d0d000", &pix))
+ pix = WhitePixelOfScreen(XtScreen(w));
+ }
+ else
+ pix = tw->core.background_pixel;
+
+ value->addr = (XtPointer)& pix;
+}
+
+/* ARGSUSED */
+static void Def_scroll(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ static Widget view;
+
+ for (view = XtParent(w);
+ (view != (Widget)NULL) && (!XtIsSubclass(view, viewportWidgetClass));
+ view = XtParent(view))
+ /* EMPTY */;
+
+ if (view)
+ {
+ if (offset == Offset(table.v_scroll))
+ {
+ if (((view = XtNameToWidget(view, "vertical")) == (Widget)NULL)
+ || !XtIsSubclass(view, scrollbarWidgetClass))
+ view = (Widget)NULL;
+ }
+ else
+ if (offset == Offset(table.h_scroll))
+ {
+ if (((view = XtNameToWidget(view, "horizontal")) == (Widget)NULL)
+ || !XtIsSubclass(view, scrollbarWidgetClass))
+ view = (Widget)NULL;
+ }
+ }
+
+ value->addr = (XtPointer)&view;
+}
+
+/* ARGSUSED */
+static void Def_column_default_width(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static int column_default_width;
+
+ if (tw->table.literal)
+ column_default_width = 10;
+ else
+ column_default_width = 60;
+
+ value->addr = (XtPointer)&column_default_width;
+}
+
+#ifndef WORD64
+#define TXT_16 XChar2b
+#else
+#define TXT_16 char
+#endif
+
+/* ARGSUSED */
+static void Def_literal_width(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static int literal_width;
+
+ if (tw->table.encoding)
+ tw->table.literal_width = XTextWidth16(tw->table.font, (TXT_16*)"mmm", 3);
+ else
+ tw->table.literal_width = XTextWidth(tw->table.font, "mmm", 3);
+
+ tw->table.literal_width /= 3;
+
+ value->addr = (XtPointer)& literal_width;
+}
+
+/* ARGSUSED */
+static void Def_shadow_thickness(w, offset, value)
+ Widget w;
+ int offset;
+ XrmValue *value;
+{
+ Widget parent = XtParent (w);
+ static Dimension shadow_thickness;
+
+ if (XtIsSubclass (parent, scrolledTableWidgetClass)
+ ||
+ XtIsSubclass (parent, viewportWidgetClass))
+ shadow_thickness = 0;
+ else
+ shadow_thickness = 2;
+
+ value->addr = (XtPointer)& shadow_thickness;
+}
+
+
+#undef offset
+
+static void MultipleChangeGC();
+static void Initialize();
+static void Realize();
+static void Resize();
+static void Redisplay();
+static void Destroy();
+
+static Boolean SetValues();
+
+static void WalkForCells();
+static void LoseSelection();
+
+static void CallEdit();
+static void InsertSelection();
+static void StoreBuffer();
+static void WhatCell();
+static void KeyReturn();
+static void HighlightCell();
+static void UnhighlightCell();
+static void DoingNothing();
+
+static char* DummyString();
+
+static Boolean InitCell();
+
+static XtGeometryResult QueryGeometry();
+static XtGeometryResult GeometryManager();
+
+static XtActionsRec actions[] = {
+ {"call-edit", (XtActionProc)CallEdit },
+ {"insert-selection", (XtActionProc)InsertSelection},
+ {"store-in-buffer", (XtActionProc)StoreBuffer },
+ {"what_cell", (XtActionProc)WhatCell },
+ {"key_return", (XtActionProc)KeyReturn },
+ {"highlight", (XtActionProc)HighlightCell },
+ {"unhighlight", (XtActionProc)UnhighlightCell},
+ {"no-op", (XtActionProc)DoingNothing }
+};
+
+static char translations[] =
+ "Ctrl<Btn1Up>: what_cell() \n\
+ <Btn1Up>: call-edit() \n\
+ <Btn2Up>: insert-selection(PRIMARY, CUT_BUFFER0) \n\
+ <Btn3Up>: highlight() store-in-buffer(PRIMARY,CUT_BUFFER0) ";
+
+static char edit_translations[] =
+ " <Key>Return: key_return() \n\
+ <Key>Linefeed: key_return() \n\
+ <Key>Down: no-op(r) \n\
+ <Key>Up: no-op(r) ";
+
+static char* Dummy = "";
+
+
+#define SuperClass ((ContainerWidgetClass)&containerClassRec)
+
+TableClassRec tableClassRec = {
+ { /* core_class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class_name */ "Table",
+ /* widget_size */ sizeof(TableRec),
+ /* classInitialize */ NULL,
+ /* class_partInitialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ FALSE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ TRUE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ translations,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ /* Composite class part */
+ {
+ /* geometry manager */ GeometryManager,
+ /* change_managed */ XtInheritChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL,
+ },
+ /* Constraint class part */
+ {
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ 0,
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL,
+ },
+ /* Container class part */
+ {
+ /* ignore */ 0,
+ },
+ { /* Table class fields initialization */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass tableWidgetClass = (WidgetClass)&tableClassRec;
+
+
+/****************************************************************
+ *
+ * Private procedures
+ *
+ ****************************************************************/
+#define NORMAL_INDEX(fore, back) \
+ (int)(((int)fore * (int)back) & tw->table.mask_hash_table)
+
+#define SHADOW_INDEX(back) (int)(((int)back) & tw->table.mask_hash_table)
+
+#define GET_NORMAL(tw,i) (tw->table.normal_hash_table+(i))
+#define GET_SHADOW(tw,i) (tw->table.shadow_hash_table+(i))
+
+#define NEXT(i) (int)((i+1) & tw->table.mask_hash_table)
+
+static int MaskStaticArray[] = {
+ 0x1, 0x3, 0x7, 0xF,
+ 0x1F, 0x3F, 0x7F, 0xFF,
+ 0x1FF, 0x3FF, 0x7FF, 0xFFF
+ };
+
+static NormalReverseGC* GetNormalGC(w, fore, back, font)
+ Widget w;
+ Pixel fore;
+ Pixel back;
+ Font font;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = NORMAL_INDEX(fore, back);
+
+ while (GET_NORMAL(tw,i)->used > 0)
+ {
+
+ if (GET_NORMAL(tw,i)->fore == fore && GET_NORMAL(tw,i)->back == back)
+ {
+ GET_NORMAL(tw,i)->used++;
+ return GET_NORMAL(tw,i);
+ }
+ i = NEXT(i);
+ }
+
+ if (GET_NORMAL(tw,i)->used == 0)
+ {
+ XtGCMask mask;
+ XGCValues values;
+ Display *dpy = XtDisplay(w);
+ Window win = XtIsRealized(w) ? XtWindow(w) : XDefaultRootWindow(dpy);
+
+
+ mask = GCForeground | GCBackground | GCFont;
+ values.foreground = fore;
+ values.background = back;
+ values.font = font;
+
+ GET_NORMAL(tw,i)->normal = XCreateGC(dpy, win, mask, &values);
+ values.foreground = back;
+ values.background = fore;
+ GET_NORMAL(tw,i)->reverse = XCreateGC(dpy, win, mask, &values);
+
+ GET_NORMAL(tw,i)->used = 1;
+ GET_NORMAL(tw,i)->fore = fore;
+ GET_NORMAL(tw,i)->back = back;
+
+ return GET_NORMAL(tw,i);
+ }
+
+ return (NormalReverseGC*)NULL;
+}
+
+static void GetGCByForeground(w, gc, fore)
+ Widget w;
+ GC *gc;
+ Pixel fore;
+{
+ XGCValues values;
+
+ values.foreground = fore;
+ (*gc) = XtGetGC(w, GCForeground, &values);
+}
+
+
+static ShadowGC* GetShadowGC(w, back)
+ Widget w;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = SHADOW_INDEX(back);
+
+ while (GET_SHADOW(tw,i)->used > 0)
+ {
+ if (GET_SHADOW(tw,i)->back == back)
+ {
+ GET_SHADOW(tw,i)->used++;
+ return GET_SHADOW(tw,i);
+ }
+ i = NEXT(i);
+ }
+
+ if (GET_SHADOW(tw,i)->used == 0)
+ {
+ Pixel top;
+ Pixel bottom;
+
+ GET_SHADOW(tw,i)->used = 1;
+ GET_SHADOW(tw,i)->back = back;
+
+ (void)TopShadowColor(w, back, &top);
+ (void)BottomShadowColor(w, back, &bottom);
+#ifdef CELL_IN
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->bottom, top);
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->top, bottom);
+#else
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->bottom, bottom);
+ GetGCByForeground(w, (GC*)&GET_SHADOW(tw,i)->top, top);
+#endif
+ return GET_SHADOW(tw,i);
+ }
+
+ return (ShadowGC*)NULL;
+}
+
+static void ReleaseNormalGC(w, fore, back)
+ Widget w;
+ Pixel fore;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = NORMAL_INDEX(fore, back);
+
+ while (GET_NORMAL(tw,i)->used > 0)
+ {
+ if ( GET_NORMAL(tw,i)->fore == fore && GET_NORMAL(tw,i)->back == back)
+ {
+ if (--GET_NORMAL(tw,i)->used == 0) {
+ XFreeGC(XtDisplay(w), GET_NORMAL(tw,i)->normal);
+ XFreeGC(XtDisplay(w), GET_NORMAL(tw,i)->reverse);
+ }
+ break;
+ }
+
+ i = NEXT(i);
+ }
+}
+
+static void ReleaseShadowGC(w, back)
+ Widget w;
+ Pixel back;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ int i = SHADOW_INDEX(back);
+
+ while (GET_SHADOW(tw,i)->used > 0)
+ {
+ if ( GET_SHADOW(tw,i)->back == back)
+ {
+ if (--GET_SHADOW(tw,i)->used == 0)
+ {
+ XtReleaseGC(w, GET_SHADOW(tw,i)->top);
+ XtReleaseGC(w, GET_SHADOW(tw,i)->bottom);
+ }
+ break;
+ }
+ i = NEXT(i);
+ }
+}
+
+static void MultipleChangeGC(w, fore, back, font, normal, reverse)
+ Widget w;
+ Pixel *fore;
+ Pixel *back;
+ Font *font;
+ GC *normal;
+ GC *reverse;
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if (normal != (GC*)NULL){
+ mask = (XtGCMask)0;
+ if (fore != (Pixel*)NULL) {
+ mask |= GCForeground;
+ values.foreground = *fore;
+ }
+ if (back != (Pixel*)NULL) {
+ mask |= GCBackground;
+ values.background = *back;
+ }
+ if (font != (Font*)NULL) {
+ mask |= GCFont;
+ values.font = *font;
+ }
+ XChangeGC(XtDisplay(w), *normal, mask, &values);
+ }
+
+ if (reverse != (GC*)NULL){
+ mask = (XtGCMask)0;
+ if (fore != (Pixel*)NULL) {
+ mask |= GCForeground;
+ values.foreground = *back; /* reverse */
+ }
+ if (back != (Pixel*)NULL) {
+ mask |= GCBackground;
+ values.background = *fore; /* reverse */
+ }
+ if (font != (Font*)NULL) {
+ mask |= GCFont;
+ values.font = *font;
+ }
+ XChangeGC(XtDisplay(w), *reverse, mask, &values);
+ }
+}
+
+#ifndef WORD64
+
+#define TXT16 XChar2b
+
+#else
+
+#define TXT16 char
+
+static XChar2b *buf2b;
+static int buf2blen = 0;
+
+#define XTextWidth16 _XawTableWidth16
+#define XDrawString16 _XawTableDraw16
+
+#endif /* WORD64 */
+
+
+static void CalculatePreferredSize(w, width, height)
+ Widget w;
+ Dimension *width;
+ Dimension *height;
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ register int wid;
+ register int hei;
+ int i;
+
+ /*
+ * Calculate preferred width
+ */
+
+ wid = 2 * (tw->table.tab_margin + tw->container.shadow_thickness);
+ wid += COLUMNS(tw) ? (COLUMNS(tw) - 1) * tw->table.col_margin : 0;
+ wid += 2 * COLUMNS(tw) * tw->table.label_shadow_thickness;
+
+ for(i = 0 ; i < COLUMNS(tw); i++)
+ wid += (Dimension)COLUMN_WIDTH(tw,i);
+
+ /*
+ * Calculate preferred height
+ */
+
+ hei = 2 * (tw->table.tab_margin + tw->container.shadow_thickness);
+ hei += ROWS(tw) ? (ROWS(tw) - 1) * tw->table.row_margin : 0;
+ hei += ROWS(tw) * tw->table.row_height;
+ hei += 2 * ROWS(tw) * tw->table.label_shadow_thickness;
+
+ tw->table.prefer_width = wid;
+ tw->table.prefer_height = hei;
+
+ if (width) *width = wid;
+ if (height) *height = hei;
+
+}
+
+static Position GetX(tw,j)
+ register XawTableWidget tw;
+ int j;
+{
+ register TablePart* table = (TablePart*)&tw->table;
+ register Position x;
+
+ x = j * (table->col_margin + 2 * table->label_shadow_thickness) +
+ (table->tab_margin + tw->container.shadow_thickness);
+
+ for(; j > 0 ; j--)
+ {
+ register int tmp = j - 1;
+ x += (Position)COLUMN_WIDTH(tw, tmp);
+ }
+ return x;
+}
+
+static Position GetY(tw,i)
+ XawTableWidget tw;
+ int i;
+{
+ return(i * (tw->table.row_margin + tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness) +
+ (tw->table.tab_margin + tw->container.shadow_thickness));
+}
+
+
+/*
+ * Calculate width and height of displayed text in pixels
+ */
+
+static void SetLabelHeight(tw)
+ XawTableWidget tw;
+{
+ register XFontStruct *fs = tw->table.font;
+ int row_height = tw->table.row_height;
+
+ if (tw->table.row_height < 1)
+ tw->table.row_height = (fs->max_bounds.ascent +
+ fs->max_bounds.descent +
+ 2 * tw->table.internal_height);
+ if (row_height != tw->table.row_height)
+ {
+ XawTableCallbackStruct callback_str;
+ callback_str.reason = XawTABLE_CHANGED_ROW_HEIGHT;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK((Widget)tw, XtNchangedRowHeight, callback_str);
+ }
+}
+
+static void SetLiteralWidth(tw)
+ XawTableWidget tw;
+{
+ if (tw->table.encoding)
+ tw->table.literal_width = XTextWidth16(tw->table.font, (TXT16*)"mmm", 3);
+ else
+ tw->table.literal_width = XTextWidth(tw->table.font, "mmm", 3);
+
+ tw->table.literal_width /= 3;
+}
+
+
+static void SetLabelWidth(tw,i,j)
+ XawTableWidget tw;
+ int i,j;
+{
+ register XFontStruct *fs = tw->table.font;
+ XawTableCell cell;
+
+ cell = (XawTableCell)get_cell(STUFF(tw),i,j);
+
+ if (CELL(label) == NULL) {
+ CELL(label_len) = 0;
+ CELL(label_width) = 0;
+ } else {
+ CELL(label_len) = strlen(CELL(label));
+ if (tw->table.encoding)
+ CELL(label_width) =
+ XTextWidth16(fs, (TXT16*)CELL(label), (int) CELL(label_len)/2);
+ else
+ CELL(label_width) =
+ XTextWidth(fs, CELL(label), (int) CELL(label_len));
+ }
+}
+
+
+static void CreateTableCellGC(w)
+ Widget w;
+{
+ Display *dpy = XtDisplay(w);
+ Drawable d = XtWindow(w);
+ XawTableWidget tw = (XawTableWidget)w;
+
+ tw->table.normal = XCreateGC(dpy, d, (XtGCMask)0, (XGCValues*)NULL);
+ tw->table.reverse = XCreateGC(dpy, d, (XtGCMask)0, (XGCValues*)NULL);
+
+ MultipleChangeGC(w,
+ (Pixel*)&tw->table.foreground,
+ (Pixel*)&tw->core.background_pixel,
+ (Font*)&tw->table.font->fid,
+ (GC*)&tw->table.normal,
+ (GC*)&tw->table.reverse);
+
+}
+
+static void DrawColumns(tw, b_column, e_column)
+ XawTableWidget tw;
+ int b_column, e_column;
+{
+ int j,y;
+
+ y = (int)GetY(tw,0);
+ for(j = MAX(b_column,0); j <= MIN(e_column, COLUMNS(tw) - 2); j++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.column_gc,
+ (int) (GetX(tw,j+1) - tw->table.col_margin),
+ y,
+ (unsigned int) tw->table.col_margin,
+ (unsigned int)(tw->table.prefer_height-(2*y)));
+
+ }
+}
+
+static void DrawRows(tw, b_row, e_row)
+ XawTableWidget tw;
+ int b_row, e_row;
+{
+ int i,x;
+
+ x = (int)GetX(tw,0);
+ for(i = MAX(b_row, 0); i <= MIN(e_row, ROWS(tw) - 2); i++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.row_gc,
+ x,
+ (int) (GetY(tw,i+1) - tw->table.row_margin),
+ (unsigned int) (tw->table.prefer_width-(2*x)),
+ (unsigned int) tw->table.row_margin);
+
+ }
+}
+
+static void DrawCage(tw, b_row, e_row, b_column, e_column)
+ XawTableWidget tw;
+ int b_row, e_row, b_column, e_column;
+{
+ int i,j;
+ Display* dpy = XtDisplay((Widget)tw);
+ Window win = XtWindow((Widget)tw);
+
+ if (tw->table.row_oriented)
+ {
+ if (tw->table.col_margin > (Dimension)0)
+ {
+ DrawRows(tw, b_row - 1, e_row);
+
+ for(i = b_row; i <= MIN(e_row,ROWS(tw) - 1); i++)
+ {
+ int y = (int) GetY(tw,i);
+
+ for(j = MAX(b_column - 1, 0); j <= MIN(e_column, COLUMNS(tw) - 2); j++)
+ {
+ XFillRectangle (dpy,
+ win,
+ tw->table.column_gc,
+ (int) (GetX(tw, j + 1) - tw->table.col_margin),
+ y,
+ (unsigned int) tw->table.col_margin,
+ (unsigned int) (tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness));
+
+ }
+ }
+ }
+ }
+ else
+ {
+ if (tw->table.row_margin > (Dimension)0)
+ {
+ DrawColumns(tw, b_column - 1, e_column);
+
+ for(j = b_column; j <= MIN(e_column, COLUMNS(tw) - 1); j++)
+ {
+ int x = (int) GetX(tw,j);
+
+ for(i = MAX(b_row - 1, 0); i <= MIN(e_row, ROWS(tw) - 2); i++)
+ {
+ XFillRectangle(XtDisplay((Widget)tw),
+ XtWindow((Widget)tw),
+ tw->table.row_gc,
+ x,
+ (int) (GetY(tw,i+1) - tw->table.row_margin),
+ (unsigned int) (COLUMN_WIDTH(tw,j) +
+ 2 * tw->table.label_shadow_thickness),
+ (unsigned int) tw->table.row_margin);
+ }
+ }
+ }
+ }
+}
+
+static void Reposition(tw, cell, i, j)
+ register XawTableWidget tw;
+ XawTableCell cell;
+ int i,j;
+{
+ Position newPos;
+ XtJustify justify;
+
+ if (cell == NULL)
+ cell = (XawTableCell)get_cell(STUFF(tw),i,j);
+
+ if (COLUMN_DATA(tw)[j].flag & _CL_justify)
+ justify = COLUMN_DATA(tw)[j].justify;
+ else
+ justify = tw->table.justify;
+
+ switch (justify) {
+ case XtJustifyLeft : newPos = tw->table.internal_width;
+ break;
+ case XtJustifyRight : newPos = (COLUMN_WIDTH(tw,j) -
+ CELL(label_width) -
+ tw->table.internal_width);
+ break;
+ case XtJustifyCenter :
+ default : newPos = (COLUMN_WIDTH(tw,j) -
+ CELL(label_width)) / 2;
+ break;
+ }
+
+ CELL(label_x) = MAX(newPos, tw->table.internal_width);
+}
+
+/* ARGSUSED */
+static Boolean DeleteCell(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableCell cell = (XawTableCell)call_data;
+
+
+ if (CELL(label) != (char*)NULL)
+ XtFree(CELL(label));
+
+ if (CELL(special_colour))
+ {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ return False;
+}
+
+
+static void UpdateTable(tw)
+ XawTableWidget tw;
+{
+ Dimension width;
+ Dimension height;
+
+ if (tw->table.no_refigure > 0)
+ return;
+
+ CalculatePreferredSize((Widget)tw, &width, &height);
+
+ tw->table.was_resized = False;
+
+ (void)XtMakeResizeRequest((Widget)tw, width, height,
+ (Dimension*)NULL, (Dimension*)NULL);
+ if (tw->table.was_resized == False)
+ {
+ tw->table.was_resized = True;
+ (*tableClassRec.core_class.resize) ((Widget)tw);
+ }
+}
+
+
+static int SetTableSize(w, rows, columns)
+ Widget w;
+ int rows;
+ int columns;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ int i;
+
+ if (rows < 0 || columns < 0) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetTableSize", "SetTableSize","XawToolkitError",
+ "rows or columns for a new table in TableWidget '%s' less then zero",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (STUFF(tw))
+ {
+ callback_str.reason = XawTABLE_ALLOW_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = STUFF(tw);
+ callback_str.new_cell = STUFF(tw);
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteTable, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+ callback_str.reason = XawTABLE_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = STUFF(tw);
+ callback_str.new_cell = STUFF(tw);
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK (w, XtNdeleteTable, callback_str);
+
+ WalkForCells (w, (XawTableProc)DeleteCell,
+ 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ delete_table ((XtPointer)STUFF(tw));
+
+ STUFF(tw) = (XawTableCell)NULL;
+ ROWS(tw) = 0;
+ COLUMNS(tw) = 0;
+ }
+
+ if (rows == 0 || columns == 0)
+ return ACCEPT;
+
+ STUFF(tw) = (XawTableCell)
+ create_table(rows, columns, sizeof(XawTableCellRec));
+
+ if (STUFF(tw) == (XawTableCell)NULL)
+ return ACCEPT;
+
+ ROWS(tw) = rows;
+ COLUMNS(tw) = columns;
+
+ WalkForCells((Widget)tw, (XawTableProc)InitCell, 0, rows-1, 0, columns-1);
+
+ if (COLUMNS(tw)) {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)COLUMN_DATA(tw),
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ for (i = 0; i < COLUMNS(tw); i++)
+ COLUMN_DATA(tw)[i].flag = 0;
+ }
+ else {
+ XtFree((XtPointer)tw->table.column_data);
+ tw->table.column_data = NULL;
+ }
+
+ callback_str.reason = XawTABLE_CREATE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNcreateTable, callback_str);
+
+ return ACCEPT;
+}
+
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+ Widget request;
+ Widget new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ register XawTableWidget tw = (XawTableWidget) new;
+ Dimension width;
+ Dimension height;
+ int i;
+
+ tw->table.no_refigure = 0;
+ tw->table.no_redraw = 0;
+ tw->table.num_selections = 0;
+ tw->table.cell_own = (XawTableCell)NULL;
+ STUFF(tw) = (XawTableCell)NULL;
+ tw->table.normal = (GC)NULL;
+ tw->table.reverse = (GC)NULL;
+
+ COLUMNS(tw) = MAX (COLUMNS(tw), 0);
+ ROWS(tw) = MAX (ROWS(tw), 0);
+
+ if (COLUMNS(tw)) {
+ tw->table.column_data = (XawTableColumn)
+ CALLOC (COLUMNS(tw), XawTableColumnRec);
+ for (i = 0; i < COLUMNS(tw); i++)
+ COLUMN_DATA(tw)[i].flag = 0;
+ }
+ else
+ tw->table.column_data = NULL;
+
+ SetLiteralWidth(tw);
+
+ EDIT(tw) = XtVaCreateWidget
+ ("edit", asciiTextWidgetClass, new,
+ XtNeditType, XawtextEdit,
+ XtNforeground, tw->table.edit_fore,
+ XtNbackground, tw->table.edit_back,
+ XtNborderWidth, (XtArgVal)0,
+ XtNleftMargin, 2,
+ XtNrightMargin, 2,
+ XtNtopMargin, 0, /* to be fixed in future */
+ XtNbottomMargin, 0, /* to be fixed in future */
+ XtNuseStringInPlace, False,
+ XtNfont, tw->table.font,
+ XtNuserData, (XtArgVal)new,
+ NULL);
+
+ XtOverrideTranslations(EDIT(tw), XtParseTranslationTable(edit_translations));
+
+ GetGCByForeground (new, (GC*)&tw->table.row_gc, tw->table.row_fore);
+ GetGCByForeground (new, (GC*)&tw->table.column_gc, tw->table.column_fore);
+
+ if ((COLUMNS(tw) > 0) && (ROWS(tw) > 0))
+ {
+ if (REJECT == SetTableSize(new, ROWS(tw), COLUMNS(tw)))
+ {
+ ROWS(tw) = 0;
+ COLUMNS(tw) = 0;
+ STUFF(tw) = (XawTableCell)NULL;
+ }
+ }
+
+ if ((tw->table.mask_number < 0)
+ || (tw->table.mask_number >= XtNumber(MaskStaticArray)))
+ tw->table.mask_number = 7;
+
+ tw->table.mask_hash_table = MaskStaticArray[tw->table.mask_number];
+
+ tw->table.normal_hash_table =
+ CALLOC(tw->table.mask_hash_table, NormalReverseGC);
+
+ tw->table.shadow_hash_table = CALLOC(tw->table.mask_hash_table, ShadowGC);
+
+ for(i = 0; i < tw->table.mask_hash_table; i++)
+ {
+ GET_NORMAL(tw,i)->used = 0;
+ GET_NORMAL(tw,i)->normal = (GC)NULL;
+ GET_NORMAL(tw,i)->reverse = (GC)NULL;
+ GET_SHADOW(tw,i)->used = 0;
+ GET_SHADOW(tw,i)->top = (GC)NULL;
+ GET_SHADOW(tw,i)->bottom = (GC)NULL;
+ }
+
+ SetLabelHeight(tw);
+
+ CalculatePreferredSize(new, &width, &height);
+
+ if (new->core.width == 0) new->core.width = width;
+ if (new->core.height == 0) new->core.height = height;
+}
+
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ ShadowGC *shadow;
+
+ (*SuperClass->core_class.realize) (w, valueMask, attributes);
+
+ CreateTableCellGC(w);
+
+ shadow = GetShadowGC(w, tw->table.edit_back);
+ tw->table.edit_top = shadow->top;
+ tw->table.edit_bottom = shadow->bottom;
+
+ shadow = GetShadowGC(w, tw->core.background_pixel);
+ tw->table.top = shadow->top;
+ tw->table.bottom = shadow->bottom;
+
+ XtRealizeWidget(EDIT(w));
+}
+
+/* ARGSUSED */
+static Boolean MatchLabel(w, i, j, call_data, client_data)
+ Widget w; /* unused */
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ XawTableCell cell = (XawTableCell)call_data;
+ XrmQuark* templ = (XrmQuark*)client_data;
+
+ return ((*templ) == XrmStringToQuark (GET_CELL_LABEL));
+}
+
+/* ARGSUSED */
+static Boolean InitCell(p, i, j, call_data, client_data)
+ XtPointer p; /* unused */
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ XawTableCell cell = (XawTableCell)call_data;
+
+ CELL(label) = DummyString();
+ CELL(label_len) = 0;
+ CELL(label_width) = 0;
+ CELL(highlight) = False;
+ CELL(special_colour) = False;
+ CELL(normal) = (GC)NULL;
+ CELL(reverse) = (GC)NULL;
+ CELL(top) = (GC)NULL;
+ CELL(bottom) = (GC)NULL;
+
+ return False;
+}
+
+/*
+ *
+ * Shadow drawing around cell
+ *
+ */
+static void PaintShadow(w, i, j, x, y, cell)
+ Widget w;
+ int i;
+ int j;
+ Position x;
+ Position y;
+ XawTableCell cell;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+
+ if (tw->table.label_shadow_thickness != (Dimension)0) {
+ GC top,bottom;
+
+ if (IsEditInRowColumn(tw,i,j))
+ {
+ top = tw->table.edit_bottom;
+ bottom = tw->table.edit_top;
+ }
+ else if (CELL(special_colour))
+ {
+ top = CELL(top);
+ bottom = CELL(bottom);
+ }else {
+ top = tw->table.top;
+ bottom = tw->table.bottom;
+ }
+
+ XawDrawFrame(w,
+ x,
+ y,
+ (Dimension)(COLUMN_WIDTH(tw,j) +
+ 2 * tw->table.label_shadow_thickness),
+ (Dimension)(tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness),
+ XawRAISED,
+ tw->table.label_shadow_thickness,
+ top,
+ bottom);
+ }
+
+}
+
+/* ARGSUSED */
+static void PaintLabel(w, i, j, x, y, cell)
+ Widget w;
+ int i;
+ int j;
+ Position x,y;
+ XawTableCell cell;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XRectangle rectangle[1];
+ Position label_x;
+ Position label_y;
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,j);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ x += tw->table.label_shadow_thickness;
+ y += tw->table.label_shadow_thickness;
+
+ if (CELL(special_colour) || CELL(highlight))
+ {
+ GC gc;
+
+ if (CELL(special_colour))
+ gc = CELL(highlight) ? CELL(normal) : CELL(reverse);
+ else
+ gc = tw->table.normal ;
+
+ /* Fill background for cell with a special colour */
+ XFillRectangle(XtDisplay(w), XtWindow(w), gc,
+ (int)x, (int)y, width, height);
+ }
+ else
+ {
+ XClearArea (XtDisplay(w), XtWindow(w), (int)x, (int)y,
+ width, height, FALSE);
+ }
+
+ if (CELL(label_len) > 0)
+ {
+ GC gc;
+ register XFontStruct *fs = tw->table.font;
+
+ if (CELL(special_colour))
+ gc = CELL(highlight) ? CELL(reverse) : CELL(normal);
+ else
+ gc = CELL(highlight) ? tw->table.reverse : tw->table.normal;
+
+ /* Set clip rectangle for label in cell */
+ rectangle[0].x = (short)x;
+ rectangle[0].y = (short)y;
+ rectangle[0].width = (unsigned short)COLUMN_WIDTH(tw,j);
+ rectangle[0].height = (unsigned short)tw->table.row_height;
+
+ XSetClipRectangles(XtDisplay(w), gc, 0, 0, rectangle, 1, YSorted);
+
+ /* Drawing label */
+ label_x = x + CELL(label_x);
+ label_y = y +
+ (tw->table.row_height-(fs->max_bounds.ascent+fs->max_bounds.descent))/2
+ /* tw->table.internal_height */
+ + fs->max_bounds.ascent;
+
+ if (tw->table.encoding)
+ XDrawString16(XtDisplay(w), XtWindow(w), gc,
+ label_x, label_y, (TXT16*)CELL(label),
+ (int)CELL(label_len)/2);
+ else
+ XDrawString(XtDisplay(w), XtWindow(w), gc,
+ label_x, label_y, CELL(label), (int)CELL(label_len));
+
+ XSetClipMask(XtDisplay(w), gc, (Pixmap)None);
+
+ }
+}
+
+/* ARGSUSED */
+static Boolean PaintCell(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell = (XawTableCell) call_data;
+ Position x;
+ Position y;
+
+ x = GetX(tw,j);
+ y = GetY(tw,i);
+
+ PaintLabel (w, i, j, x, y, cell);
+ PaintShadow (w, i, j, x, y, cell);
+
+ XFlush(XtDisplay(w));
+ return False;
+}
+
+static void WhatCellsToBeDraw(tw, rect, b_row, e_row, b_column , e_column)
+ XawTableWidget tw;
+ XRectangle rect;
+ register int *b_row, *e_row, *b_column , *e_column;
+{
+ Position x1 = (Position)rect.x,
+ y1 = (Position)rect.y,
+ x2 = (Position)(rect.x + rect.width - 1),
+ y2 = (Position)(rect.y + rect.height - 1);
+
+ for ((*b_column) = 0; (*b_column) < COLUMNS(tw); (*b_column)++)
+ {
+ if (x1 < (GetX(tw,(*b_column) + 1) - tw->table.col_margin))
+ break;
+ }
+
+ for ((*e_column) = (*b_column); (*e_column) < COLUMNS(tw); (*e_column)++)
+ {
+ if (x2 < (GetX(tw,(*e_column) + 1) - tw->table.col_margin))
+ break;
+ }
+
+
+ for ((*b_row) = 0; (*b_row) < ROWS(tw); (*b_row)++)
+ {
+ if (y1 < (GetY(tw,(*b_row) + 1) - tw->table.row_margin))
+ break;
+ }
+
+ for ((*e_row) = (*b_row); (*e_row) < ROWS(tw); (*e_row)++)
+ {
+ if (y2 < (GetY(tw,(*e_row) + 1) - tw->table.row_margin))
+ break;
+ }
+}
+
+
+static void Redisplay(w, event, region)
+ Widget w;
+ XEvent *event;
+ Region region;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XRectangle rect;
+ int b_row, e_row, b_column , e_column ;
+
+ if (!XtIsRealized(w) || !w->core.visible || tw->table.no_redraw)
+ return;
+
+ if (tw->container.shadow_thickness > 0)
+ (*SuperClass->core_class.expose) (w, event, region);
+
+ if (region != NULL)
+ {
+ XClipBox(region, (XRectangle*)&rect);
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ rect.x = (short) event->xexpose.x;
+ rect.y = (short) event->xexpose.y;
+ rect.width = (unsigned short) event->xexpose.width;
+ rect.height = (unsigned short) event->xexpose.height;
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+ }
+ else if (tw->table.v_scroll || tw->table.h_scroll)
+ {
+ rect.x = (short) 0;
+ rect.y = (short) 0;
+ rect.width = (unsigned short) tw->core.width;
+ rect.height = (unsigned short) tw->core.height;
+
+ if (tw->table.v_scroll && XtIsManaged(tw->table.v_scroll))
+ {
+ float top;
+ float shown;
+
+ XtVaGetValues (tw->table.v_scroll,
+ XtNtopOfThumb, &top,
+ XtNshown, &shown,
+ NULL);
+
+ rect.y = (short) ((float)(tw->core.height) * top);
+ rect.height = (unsigned short) ((float)(tw->core.height) * (top+shown));
+ }
+
+ if (tw->table.h_scroll && XtIsManaged(tw->table.h_scroll))
+ {
+ float top;
+ float shown;
+
+ XtVaGetValues (tw->table.h_scroll,
+ XtNtopOfThumb, &top,
+ XtNshown, &shown,
+ NULL);
+
+ rect.x = (short) ((float)(tw->core.width) * top);
+ rect.width = (unsigned short) ((float)(tw->core.width) * (top+shown));
+ }
+
+
+ WhatCellsToBeDraw(tw, rect, &b_row, &e_row, &b_column , &e_column);
+ }
+ else
+ {
+ b_row = 0;
+ e_row = ROWS(tw) - 1;
+ b_column = 0;
+ e_column = COLUMNS(tw) - 1;
+ }
+
+ DrawCage(tw, b_row, e_row, b_column, e_column);
+
+ WalkForCells(w, (XawTableProc)PaintCell, b_row, e_row, b_column, e_column);
+
+ XFlush(XtDisplay(w));
+}
+
+/* ARGSUSED */
+static Boolean SetValues(current, request, new, args, num_args)
+ Widget current;
+ Widget request; /* unused */
+ Widget new;
+ ArgList args; /* unused */
+ Cardinal *num_args; /* unused */
+{
+ XawTableWidget curtw = (XawTableWidget) current;
+ XawTableWidget newtw = (XawTableWidget) new;
+ register int i;
+ int j;
+ Boolean resize = False;
+ Boolean redisplay = False;
+
+#define NE(field) (curtw->table.field != newtw->table.field)
+
+ if (NE(mask_number))
+ XtWarning("Resource XtNmaskNumber in Table widget can not changed");
+
+ newtw->table.mask_number = curtw->table.mask_number;
+ newtw->table.literal = curtw->table.literal;
+
+ if (NE(font->fid))
+ XtVaSetValues (EDIT(newtw), XtNfont, curtw->table.font, NULL);
+
+ if (NE(foreground) ||
+ NE(row_fore) ||
+ NE(column_fore) ||
+ NE(row_oriented) ||
+ NE(font->fid) ||
+ NE(justify) ||
+ NE(tab_margin) ||
+ NE(row_margin) ||
+ NE(col_margin) ||
+ NE(internal_width) ||
+ NE(internal_height) ||
+ NE(label_shadow_thickness) ||
+ NE(encoding))
+ redisplay = True;
+
+ if (NE(font->fid) ||
+ NE(columns) ||
+ NE(rows) ||
+ NE(tab_margin) ||
+ NE(row_margin) ||
+ NE(col_margin) ||
+ NE(internal_width) ||
+ NE(internal_height) ||
+ NE(row_height) ||
+ NE(label_shadow_thickness))
+ resize = True;
+
+ if (NE(columns) || NE(rows))
+ if (REJECT == SetTableSize(new, ROWS(newtw), COLUMNS(newtw))) {
+ newtw->table.columns = curtw->table.columns;
+ newtw->table.rows = curtw->table.rows;
+ }
+
+ if(NE(row_height))
+ {
+ XawTableCallbackStruct callback_str;
+ callback_str.reason = XawTABLE_CHANGED_ROW_HEIGHT;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(new, XtNchangedRowHeight, callback_str);
+ }
+
+ if(NE(font->fid))
+ {
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ SetLabelWidth(newtw, i, j);
+
+ SetLabelHeight(newtw);
+ }
+
+ if(NE(font->fid) || NE(encoding))
+ {
+ SetLiteralWidth(newtw);
+
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ Reposition(newtw, NULL, i, j);
+ }
+ else if(NE(internal_width) || NE(label_shadow_thickness)) {
+ for(i = 0; i < ROWS(newtw); i++)
+ for(j = 0; j < COLUMNS(newtw); j++)
+ Reposition(newtw, NULL, i, j);
+ }
+
+
+ if (NE(internal_height) || NE(label_shadow_thickness))
+ {
+ SetLabelHeight(newtw);
+ }
+
+ if (resize)
+ CalculatePreferredSize(new, &newtw->core.width, &newtw->core.height);
+
+ if (NE(foreground) || NE(font->fid) ||
+ curtw->core.background_pixel != newtw->core.background_pixel)
+ {
+ MultipleChangeGC(new,
+ (Pixel*)&newtw->table.foreground,
+ (Pixel*)&newtw->core.background_pixel,
+ (Font*)&newtw->table.font->fid,
+ (GC*)&newtw->table.normal,
+ (GC*)&newtw->table.reverse);
+
+ }
+
+ if (NE(row_fore))
+ {
+ XtReleaseGC(new, curtw->table.row_gc);
+ GetGCByForeground(new,(GC*)&newtw->table.row_gc, newtw->table.row_fore);
+ }
+
+ if (NE(column_fore))
+ {
+ XtReleaseGC(new, curtw->table.column_gc);
+ GetGCByForeground(new, &newtw->table.column_gc,newtw->table.column_fore);
+ }
+
+ if (resize)
+ CalculatePreferredSize(new, &(new->core.width), &(new->core.height));
+
+ return redisplay;
+}
+
+
+static void Destroy(w)
+ Widget w;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) != (XawTableCell)NULL)
+ {
+ callback_str.reason = XawTABLE_DELETE_TABLE;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNdeleteTable, callback_str);
+ }
+
+ if (tw->table.row_gc != (GC)NULL) {
+ XtReleaseGC(w, tw->table.row_gc);
+ tw->table.row_gc = (GC)NULL;
+ }
+ if (tw->table.column_gc != (GC)NULL) {
+ XtReleaseGC(w, tw->table.column_gc);
+ tw->table.column_gc = (GC)NULL;
+ }
+ if (tw->table.normal != (GC)NULL) {
+ XFreeGC(XtDisplay(w), tw->table.normal);
+ tw->table.normal = (GC)NULL;
+ }
+
+ if (tw->table.reverse != (GC)NULL) {
+ XFreeGC(XtDisplay(w), tw->table.reverse);
+ tw->table.reverse = (GC)NULL;
+ }
+
+ WalkForCells(w, (XawTableProc)DeleteCell, 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ XtFree((XtPointer)tw->table.normal_hash_table);
+ XtFree((XtPointer)tw->table.shadow_hash_table);
+
+ delete_table(tw->table.table_stuff);
+ STUFF(tw) = (XawTableCell)NULL;
+
+ if (tw->table.column_data != NULL)
+ XtFree((XtPointer)tw->table.column_data);
+
+ if (EDIT(w) != WNULL && !EDIT(w)->core.being_destroyed)
+ XtDestroyWidget(EDIT(w));
+}
+
+
+static void Resize(w)
+ Widget w;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ /* If widget is realized, just redisplay it w/o clearing */
+ if (XtIsRealized(w) && tw->table.no_redraw == 0)
+ {
+ /* XClearWindow(XtDisplay(w), XtWindow(w)); */
+ (*tableClassRec.core_class.expose) (w, (XEvent*)NULL,(Region)NULL);
+ }
+
+ tw->table.was_resized = True;
+}
+
+
+static XtGeometryResult QueryGeometry(w, intended, preferred)
+ Widget w;
+ XtWidgetGeometry *intended, *preferred;
+{
+ preferred->request_mode = CWWidth | CWHeight;
+
+ CalculatePreferredSize(w, &preferred->width, &preferred->height);
+
+#define Set(bit) (intended->request_mode & bit)
+
+ if (Set(CWWidth) && intended->width == preferred->width &&
+ Set(CWHeight) && intended->height == preferred->height) {
+ return XtGeometryYes;
+ }
+
+ if (preferred->width == w->core.width &&
+ preferred->height == w->core.height) {
+ return XtGeometryNo;
+ }
+
+ return XtGeometryAlmost;
+
+#undef Set
+}
+
+/* ARGSUSED */
+static XtGeometryResult GeometryManager(w, desired, allowed)
+ Widget w;
+ XtWidgetGeometry *desired;
+ XtWidgetGeometry *allowed;
+{
+ return XtGeometryYes;
+}
+
+
+
+static void ExtractPosition(event, x, y , t)
+ XEvent *event;
+ Position *x, *y; /* RETURN */
+ Time *t; /* RETURN */
+{
+ if (event == NULL)
+ return;
+
+ switch(event->type) {
+ case MotionNotify:
+ *x = event->xmotion.x;
+ *y = event->xmotion.y;
+ *t = event->xmotion.time;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x;
+ *y = event->xbutton.y;
+ *t = event->xbutton.time;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x;
+ *y = event->xkey.y;
+ *t = event->xkey.time;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x;
+ *y = event->xcrossing.y;
+ *t = event->xcrossing.time;
+ break;
+ default:
+ *x = 0;
+ *y = 0;
+ *t = XtLastTimestampProcessed(event->xany.display);
+ }
+}
+
+/* ARGSUSED */
+static Boolean ExtractCell(tw, px, py, row, column)
+ XawTableWidget tw;
+ Position px,py;
+ int *row, *column; /* RETURN */
+{
+ Position x;
+ Position y;
+#define SH (tw->table.label_shadow_thickness)
+ for(*row = 0; *row < ROWS(tw); (*row)++) {
+ for(*column = 0; *column < COLUMNS(tw); (*column)++)
+ if ((x=GetX(tw,*column)+SH) <= px)
+ if ((y=GetY(tw,*row)+SH) <= py)
+ if ((x+COLUMN_WIDTH(tw,*column)) >= px)
+ if ((y+tw->table.row_height) >= py)
+ return False;
+ }
+#undef SH
+
+ return True;
+}
+
+
+/* ARGSUSED */
+static void WalkForCells(w, proc, b_r, e_r, b_c, e_c)
+ Widget w;
+ XawTableProc proc;
+ int b_r, e_r, b_c, e_c;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int i,j;
+
+ (void)go_table((XtPointer)w, proc, STUFF(tw),
+ b_r, e_r, b_c, e_c,
+ XawTABLE_RIGHT_DOWN,
+ &i, &j, (XtPointer)NULL);
+}
+
+static char* DummyString()
+{
+ return XtNewString("");
+}
+
+static char* CopyOnlyPrintable(raw)
+ char* raw;
+{
+ char* clear;
+ char *s,*h;
+ int lenght;
+
+ for(s = raw, lenght = 0; (*s) != '\0';)
+ {
+ if (isprint(*s++))
+ lenght++;
+ }
+
+ clear = CALLOC(++lenght, char);
+
+ for(s = raw, h = clear; (*s) != '\0';)
+ {
+ if (isprint(*s))
+ (*h++) = (*s++);
+ }
+
+ (*h) = '\0';
+
+ return clear;
+}
+
+#ifdef EBUG_XRAW_MALLOC
+/* ARGSUSED */
+static Boolean CheckLabel(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) p;
+ XawTableCell cell = (XawTableCell)call_data;
+ char* label = CELL(label);
+
+ for (label = CELL(label); *label != '\0'; label++)
+ if (!isprint(*label))
+ {
+ char message[80];
+ char *p = NULL;
+ sprintf(message, "wrong label '%s' in cell (%4d,%4d) in Table widget '%s'",
+ CELL(label), i, j, w->core.name);
+ XtWarning(message);
+ *p = '\0';
+ break;
+ }
+
+ return False;
+}
+#endif
+
+#ifdef EBUG_XRAW_MALLOC
+static void CheckAllLabels(tw)
+ XawTableWidget tw;
+{
+ WalkForCells((Widget)tw, (XawTableProc)CheckLabel,
+ 0, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+}
+#endif
+
+static void MoveEditCell (tw, row, column)
+ XawTableWidget tw;
+ int row;
+ int column;
+{
+ Position x,y;
+
+ x = GetX(tw,column);
+ y = GetY(tw,row);
+
+ XtConfigureWidget(EDIT(tw),
+ (Position)(x + tw->table.label_shadow_thickness),
+ (Position)(y + tw->table.label_shadow_thickness),
+ (Dimension) COLUMN_WIDTH(tw, column),
+ (Dimension) tw->table.row_height,
+ (Dimension)0);
+ XawDrawFrame((Widget)tw,
+ x,
+ y,
+ (Dimension)(COLUMN_WIDTH(tw, column) +
+ 2 * tw->table.label_shadow_thickness),
+ (Dimension)(tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness),
+ XawSUNKEN,
+ tw->table.label_shadow_thickness,
+ tw->table.edit_top,
+ tw->table.edit_bottom);
+
+}
+
+/* ARGSUSED */
+static Boolean CompareCells(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i; /* unused */
+ int j; /* unused */
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ XawTableCell cell = (XawTableCell)call_data;
+ XawTableCell test_cell = (XawTableCell)client_data;
+
+ return(cell == test_cell);
+}
+
+/******************************************************************
+ *
+ * CONVENIENCE FUNCTIONS
+ *
+ ******************************************************************/
+
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetSize (Widget w,
+ int *rows,
+ int *columns)
+#else
+XawTableGetSize (w, rows, columns)
+ Widget w;
+ int *rows;
+ int *columns;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ *rows = ROWS(tw);
+ *columns = COLUMNS(tw);
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableDoLayout (Widget w,
+ Boolean do_layout)
+#else
+XawTableDoLayout (w, do_layout)
+ Widget w;
+ Boolean do_layout;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (do_layout)
+ tw->table.no_redraw--;
+ else
+ tw->table.no_redraw++;
+
+ tw->table.no_redraw = MAX (tw->table.no_redraw, 0);
+
+ if (tw->table.no_redraw == 0)
+ Redisplay (w, (XEvent *)NULL, (Region)NULL);
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetNewSize (Widget w,
+ int rows,
+ int columns)
+#else
+XawTableSetNewSize (w, rows, columns)
+ Widget w;
+ int rows;
+ int columns;
+#endif
+{
+ if (REJECT == SetTableSize(w, rows, columns))
+ return REJECT;
+
+ UpdateTable((XawTableWidget)w);
+ return ACCEPT;
+}
+
+char *
+#ifdef Xraw_NEED_PROTO
+XawTableGetLabelByCell (XawTableCell cell)
+#else
+XawTableGetLabelByCell (cell)
+ XawTableCell cell;
+#endif
+{
+ return GET_CELL_LABEL;
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetEditPosition (Widget w, int *row, int *column)
+#else
+XawTableGetEditPosition(w, row, column)
+ Widget w;
+ int *row;
+ int *column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ *row = tw->table.edit_row;
+ *column = tw->table.edit_column;
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableWalk (
+ Widget w,
+ XawTableProc proc,
+ int b_row,
+ int e_row,
+ int b_column,
+ int e_column,
+ int direction,
+ int *i, /* returned */
+ int *j, /* returned */
+ XtPointer client_data)
+#else
+XawTableWalk(w, proc, b_row, e_row, b_column, e_column,
+ direction, i, j, client_data)
+ Widget w;
+ XawTableProc proc;
+ int b_row, e_row, b_column, e_column;
+ int direction;
+ int *i; /* returned */
+ int *j; /* returned */
+ XtPointer client_data;
+#endif
+{
+ return go_table((XtPointer)w, proc, STUFF(w),
+ b_row, e_row, b_column, e_column,
+ direction,
+ i, j, client_data);
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableSearchLabel (Widget w, char *name, int *row, int *column)
+#else
+XawTableSearchLabel (w, name, row, column)
+ Widget w;
+ char *name;
+ int *row, *column;
+#endif
+{
+ int row_start = *row;
+ int column_start = *column;
+ XrmQuark templ = XrmStringToQuark (name);
+
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start, row_start, column_start, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start+1, ROWS(w)-1, 0, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ 0, row_start-1, 0, COLUMNS(w)-1,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ if (XawTableWalk(w, (XawTableProc)MatchLabel,
+ row_start, row_start, 0, column_start,
+ XawTABLE_RIGHT_DOWN,
+ row, column, (XtPointer)&templ)) {
+ return (True);
+ }
+ return (False);
+
+}
+
+/**************************************************************
+ *
+ *
+ *
+ * ROW routines
+ *
+ *
+ *
+ **************************************************************/
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTablePrependRow (Widget w)
+#else
+XawTablePrependRow(w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "prependRow", "XawTablePrependRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_before(STUFF(tw), sizeof(XawTableCellRec));
+ ROWS(tw)++;
+
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, 0, 0, COLUMNS(tw)-1);
+
+ if (XawTableIsEditManaged(w))
+ MoveEditCell (tw, ++(tw->table.edit_row), tw->table.edit_column);
+
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableAppendRow (Widget w)
+#else
+XawTableAppendRow (w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL)
+ {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "appendRow", "XawTableAppendRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), ROWS(tw)-1, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_after(get_cell(STUFF(tw), ROWS(tw) - 1, 0),
+ sizeof(XawTableCellRec));
+
+ ROWS(tw)++;
+
+ WalkForCells(w, (XawTableProc)InitCell,
+ ROWS(tw)-1, ROWS(tw)-1, 0, COLUMNS(tw)-1);
+
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), ROWS(tw)-1, 0);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = ROWS(tw)-1;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableInsertRow (Widget w, int row)
+#else
+XawTableInsertRow (w, row)
+ Widget w;
+ int row;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertRow", "XawTableInsertRow","XawToolkitError",
+ "An attempt to add a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (row != InRange(row, 0, ROWS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertRow", "XawTableInsertRow","XawToolkitError",
+ "Incorrect attempt to insert a row in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ row_insert_before(get_cell((XtPointer)STUFF(tw), row, 0),
+ sizeof(XawTableCellRec));
+
+ ROWS(tw)++;
+
+ if (row == 0)
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, row, row, 0, COLUMNS(tw)-1);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XawTableIsEditManaged(w) && row <= tw->table.edit_row){
+ tw->table.no_redraw++;
+ MoveEditCell (tw, ++(tw->table.edit_row), tw->table.edit_column);
+ tw->table.no_redraw--;
+ }
+
+ UpdateTable(tw);
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ADD_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddRow, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableDeleteRow (Widget w, int row)
+#else
+XawTableDeleteRow (w, row)
+ Widget w;
+ int row;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteRow", "XawTableDeleteRow","XawToolkitError",
+ "An attempt to delete a row in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (row != InRange(row, 0, ROWS(tw)-1)) {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", ROWS(tw)-1);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteRow", "XawTableDeleteRow","XawToolkitError",
+ "Incorrect value of row (%s, max is %s) in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_ALLOW_DELETE_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteRow, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNdeleteRow))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), row, 0);
+
+ callback_str.reason = XawTABLE_DELETE_ROW;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNdeleteRow, (XtPointer)&callback_str);
+ }
+
+ /* if selections owner locates here, then disown selections */
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ {
+ Boolean have_find;
+ int i, j;
+
+ have_find = go_table((XtPointer)w, CompareCells, STUFF(tw),
+ row, row, 0, COLUMNS(tw)-1,
+ XawTABLE_RIGHT_DOWN, &i, &j,
+ (XtPointer)tw->table.cell_own);
+ if (have_find) {
+ for (; 0 < tw->table.num_selections;)
+ XtDisownSelection (w,
+ tw->table.selections[--(tw->table.num_selections)],
+ XtLastTimestampProcessed(XtDisplay(w)));
+
+ tw->table.cell_own = (XawTableCell)NULL;
+ }
+ }
+
+ if (row == 0)
+ STUFF(tw) = (XawTableCell)get_cell(STUFF(tw), 1, 0);
+
+ if (--ROWS(tw) == 0)
+ STUFF(tw) = (XawTableCell)NULL;
+
+ WalkForCells(w, (XawTableProc)DeleteCell, row, row, 0, COLUMNS(tw)-1);
+
+ row_delete(cell);
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ if (row < tw->table.edit_row){
+ MoveEditCell (tw, --(tw->table.edit_row), tw->table.edit_column);
+ }
+ else if (row == tw->table.edit_row){
+ UNMANAGE_EDIT(tw);
+ tw->table.edit_row = InRange (tw->table.edit_row, 0, ROWS(tw)-1);
+ XawTableSetEdit (w, tw->table.edit_row, tw->table.edit_column);
+ }
+ tw->table.no_redraw--;
+ }
+
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ return ACCEPT;
+}
+
+
+
+/**************************************************************
+ *
+ *
+ *
+ * COLUMN routines
+ *
+ *
+ *
+ **************************************************************/
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTablePrependColumn (Widget w, int width)
+#else
+XawTablePrependColumn (w, width)
+ Widget w;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int j;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "prependColumn", "XawTablePrependColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_before(STUFF(tw), sizeof(XawTableCellRec));
+ COLUMNS(tw)++;
+
+ STUFF(tw) = (XawTableCell)get_table(STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, ROWS(tw)-1, 0, 0);
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ for(j = COLUMNS(tw)-2; j >= 0; j--)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j+1]), (char*)&(COLUMN_DATA(tw)[j]),
+ sizeof(XawTableColumnRec));
+
+ COLUMN_DATA(tw)[0].flag |= _CL_width;
+ COLUMN_DATA(tw)[0].width = width;
+
+
+ if (XawTableIsEditManaged(w))
+ MoveEditCell (tw, tw->table.edit_row, ++(tw->table.edit_column));
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = STUFF(tw);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableAppendColumn (Widget w, int width)
+#else
+XawTableAppendColumn (w, width)
+ Widget w;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int j;
+ XawTableCell cell;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "addingColumn", "XawTableAppendColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, COLUMNS(tw)-1);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_after(get_cell(STUFF(tw), 0, COLUMNS(tw)-1),
+ sizeof(XawTableCellRec));
+
+ COLUMNS(tw)++;
+
+ WalkForCells(w, (XawTableProc)InitCell,
+ 0, ROWS(tw)-1, COLUMNS(tw)-1, COLUMNS(tw)-1);
+
+
+
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ COLUMN_DATA(tw)[COLUMNS(tw)-1].flag |= _CL_width;
+ COLUMN_DATA(tw)[COLUMNS(tw)-1].width = width;
+
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, COLUMNS(tw)-1);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = COLUMNS(tw)-1;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableInsertColumn (Widget w, int column, int width)
+#else
+XawTableInsertColumn(w, column, width)
+ Widget w;
+ int column;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int j;
+ XawTableCallbackStruct callback_str;
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertColumn", "XawTableInsertColumn","XawToolkitError",
+ "An attempt to add a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (column != InRange(column, 0, COLUMNS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "insertColumn", "XawTableInsertColumn","XawToolkitError",
+ "It detected incorrect value of column in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ALLOW_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowAddColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ column_insert_before (get_cell ((XtPointer)STUFF(tw), 0, column),
+ sizeof(XawTableCellRec));
+ COLUMNS(tw)++;
+
+ if (column == 0)
+ STUFF(tw) = (XawTableCell) get_table (STUFF(tw));
+
+ WalkForCells(w, (XawTableProc)InitCell, 0, ROWS(tw)-1, column, column);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ /*
+ * insert new item in `column_data' list
+ */
+
+ if (tw->table.column_data)
+ {
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+ else
+ {
+ tw->table.column_data = CALLOC(COLUMNS(tw), XawTableColumnRec);
+ for(j = 0; j < COLUMNS(tw); j++)
+ COLUMN_DATA(tw)[j].flag = 0;
+ }
+
+ for(j = COLUMNS(tw)-2; j >= column; j--)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j+1]), (char*)&(COLUMN_DATA(tw)[j]),
+ sizeof(XawTableColumnRec));
+
+ COLUMN_DATA(tw)[column].flag |= _CL_width;
+ COLUMN_DATA(tw)[column].width = width;
+
+ /*
+ * move the edit cell
+ */
+
+ if (XawTableIsEditManaged(w) && column <= tw->table.edit_column){
+ tw->table.no_redraw++;
+ MoveEditCell (tw, tw->table.edit_row, ++(tw->table.edit_column));
+ tw->table.no_redraw--;
+ }
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNaddColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ADD_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNaddColumn, (XtPointer)&callback_str);
+ }
+
+ return ACCEPT;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableDeleteColumn (Widget w, int column)
+#else
+XawTableDeleteColumn(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int j;
+ XawTableCallbackStruct callback_str;
+
+
+ if (STUFF(tw) == NULL) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteColumn", "XawTableDeleteColumn","XawToolkitError",
+ "An attempt to delete a column in empty table in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ if (column != InRange(column, 0, COLUMNS(tw)-1)) {
+ String subs[1];
+ Cardinal num_subs = 1;
+ subs[0] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "deleteColumn", "XawTableDeleteColumn","XawToolkitError",
+ "It detected incorrect value of column in TableWidget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ /* request for allowance */
+
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_ALLOW_DELETE_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = 0;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNallowDeleteColumn, callback_str);
+
+ if (callback_str.do_it != True)
+ return REJECT;
+
+
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ if (XtCallbackHasSome == XtHasCallbacks(w, XtNdeleteColumn))
+ {
+ cell = (XawTableCell)get_cell(STUFF(tw), 0, column);
+
+ callback_str.reason = XawTABLE_DELETE_COLUMN;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ XtCallCallbacks (w, XtNdeleteColumn, (XtPointer)&callback_str);
+ }
+
+ /* if selections owner locates here, then disown selections */
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ {
+ Boolean have_find;
+ int i, j;
+
+ have_find = go_table((XtPointer)w, CompareCells, STUFF(tw),
+ 0, ROWS(tw)-1, column, column,
+ XawTABLE_RIGHT_DOWN, &i, &j,
+ (XtPointer)tw->table.cell_own);
+ if (have_find) {
+ for (; 0 < tw->table.num_selections;)
+ XtDisownSelection (w,
+ tw->table.selections[--(tw->table.num_selections)],
+ XtLastTimestampProcessed(XtDisplay(w)));
+
+ tw->table.cell_own = (XawTableCell)NULL;
+ }
+ }
+
+ if (column == 0)
+ STUFF(tw) = (XawTableCell)get_cell(STUFF(tw), 0, 1);
+
+ if (--COLUMNS(tw) == 0)
+ STUFF(tw) = (XawTableCell)NULL;
+
+
+ WalkForCells(w, (XawTableProc)DeleteCell, 0, ROWS(tw)-1, column, column);
+
+ column_delete(cell);
+
+ /*
+ * shrink column data list
+ */
+
+ if (COLUMNS(tw) == 0) {
+ XtFree((XtPointer)tw->table.column_data);
+ tw->table.column_data = NULL;
+ }
+ else
+ {
+ for(j = column; j < COLUMNS(tw); j++)
+ (void)memcpy((char*)&(COLUMN_DATA(tw)[j]),(char*)&(COLUMN_DATA(tw)[j+1]),
+ sizeof(XawTableColumnRec));
+
+ tw->table.column_data = (XawTableColumn)
+ XtRealloc((XtPointer)tw->table.column_data,
+ (Cardinal)(COLUMNS(tw) * sizeof(XawTableColumnRec)));
+ }
+
+
+ /*
+ * shift the edit cell
+ */
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ if (column < tw->table.edit_column){
+ MoveEditCell (tw, tw->table.edit_row, --(tw->table.edit_column));
+ }
+ else if (column == tw->table.edit_column){
+ UNMANAGE_EDIT(tw);
+ tw->table.edit_column = InRange (tw->table.edit_column,0,COLUMNS(tw)-1);
+ XawTableSetEdit (w, tw->table.edit_row, tw->table.edit_column);
+ }
+ tw->table.no_redraw--;
+ }
+
+ /* Let's look the table which we have made now */
+ UpdateTable(tw);
+
+#ifdef EBUG_XRAW_MALLOC
+ CHECK_TABLE(tw);
+#endif
+
+ return ACCEPT;
+}
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+XawTableIsEditManaged (Widget w)
+#else
+XawTableIsEditManaged (w)
+ Widget w;
+#endif
+{
+ return XtIsManaged(((XawTableWidget)w)->table.edit);
+}
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetLabel (Widget w, int row, int column, char *raw_label)
+#else
+XawTableSetLabel(w, row, column, raw_label)
+ Widget w;
+ int row;
+ int column;
+ char *raw_label;
+#endif
+{
+ register XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ char* label = NULL;
+ XawTableCellRec new;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange(row, 0, ROWS(tw)-1)) ||
+ (column != InRange(column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetLabel", "XawTableSetLabel","XawToolkitError",
+"XawTableSetLabel\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (raw_label == (char*)NULL)
+ label = DummyString();
+ else
+ label = CopyOnlyPrintable(raw_label);
+
+ if (streq(label,CELL(label))) {
+ XtFree(label); /* XtMalloc in CopyOnlyPrintable */
+ return ACCEPT;
+ }
+
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.label = label;
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it != True) {
+ XtFree(label);
+ return REJECT;
+ }
+
+
+ if (CELL(label))
+ XtFree(CELL(label));
+
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ SetLabelWidth (tw, row, column);
+ Reposition (tw, cell, row, column);
+
+ if (IsEditInRowColumn (tw, row, column))
+ {
+ XtVaSetValues (EDIT(w), "string", CELL(label), NULL);
+ }
+ else if (XtIsRealized (w) && w->core.visible && !tw->table.no_redraw)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ XClearArea (XtDisplay(w), XtWindow(w), x, y, width, height, FALSE);
+ (void) PaintCell (w, row, column, (XtPointer)cell, (XtPointer)NULL);
+ }
+ return ACCEPT;
+}
+
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellColours (Widget w, int row, int column,
+ Pixel fore, Pixel back)
+#else
+XawTableSetCellColours (w, row, column, fore, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel fore;
+ Pixel back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellColours","XawToolkitError",
+"XawTableSetCellColours\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return REJECT;
+ }
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && fore == CELL(fore) && back == CELL(back))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.back = back;
+ new.fore = fore;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, fore, back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible &&
+ !tw->table.no_redraw && !tw->table.no_refigure) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, fore, back);
+ ReleaseShadowGC(w, back);
+ return REJECT;
+ }
+}
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellDefaultColours (Widget w, int row, int column)
+#else
+XawTableSetCellDefaultColours (w, row, column)
+ Widget w;
+ int row;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellDefaultColours","XawToolkitError",
+"XawTableSetCellDefaultColours\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (!CELL(special_colour))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = False;
+ new.fore = tw->table.foreground;
+ new.back = tw->core.background_pixel;
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ return REJECT;
+ }
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellBackground (Widget w, int row, int column, Pixel back)
+#else
+XawTableSetCellBackground (w, row, column, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellBackground","XawToolkitError",
+"XawTableSetCellBackground\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && back == CELL(back))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.back = back;
+
+ if (!CELL(special_colour))
+ new.fore = tw->table.foreground;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, new.fore, back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, new.fore, back);
+ ReleaseShadowGC(w, back);
+ return REJECT;
+ }
+
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableSetCellForeground (Widget w, int row, int column, Pixel fore)
+#else
+XawTableSetCellForeground (w, row, column, fore)
+ Widget w;
+ int row;
+ int column;
+ Pixel fore;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ XawTableCellRec new;
+ NormalReverseGC* normal;
+ ShadowGC* shadow;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange (row, 0, ROWS(tw)-1)) ||
+ (column != InRange (column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetCellColours", "XawTableSetCellBackground","XawToolkitError",
+"XawTableSetCellBackground\n\
+Incorrect value of row or column (%s,%s) in Table widget '%s'",
+ subs, &num_subs);
+ return REJECT;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(special_colour) && fore == CELL(fore))
+ return ACCEPT;
+
+ /*
+ * prepare new cell stuff from old one
+ */
+ (void)memcpy((char*)&new, (char*)cell, sizeof(XawTableCellRec));
+ new.special_colour = True;
+ new.fore = fore;
+
+ if (!CELL(special_colour))
+ new.back = tw->core.background_pixel;
+
+ /* normal and reverse GC's */
+ normal = GetNormalGC(w, fore, new.back, tw->table.font->fid);
+
+ new.normal = normal->normal;
+ new.reverse = normal->reverse;
+
+
+ /* shadow GC's */
+ shadow = GetShadowGC(w, new.back);
+
+ new.top = shadow->top;
+ new.bottom = shadow->bottom;
+
+
+ callback_str.reason = XawTABLE_CHANGED_CELL;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = &new;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedCell, callback_str);
+
+ if (callback_str.do_it)
+ {
+ int x = GetX(tw,column);
+ int y = GetY(tw,row);
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,column);
+ unsigned int height = (unsigned int) tw->table.row_height;
+
+ if (XtIsRealized(w) && w->core.visible && !tw->table.no_redraw) {
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+ PaintLabel (w, row, column, x, y, &new);
+ PaintShadow (w, row, column, x, y, &new);
+ XFlush(XtDisplay(w));
+ }
+
+ if (CELL(special_colour)) {
+ ReleaseNormalGC(w, CELL(fore), CELL(back));
+ ReleaseShadowGC(w, CELL(back));
+ }
+ (void)memcpy((char*)cell, (char*)&new, sizeof(XawTableCellRec));
+
+ return ACCEPT;
+ }
+ else
+ {
+ ReleaseNormalGC(w, fore, new.back);
+ ReleaseShadowGC(w, new.back);
+ return REJECT;
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetCellColours (Widget w, int row, int column,
+ Pixel *fore, Pixel *back)
+#else
+XawTableGetCellColours (w, row, column, fore, back)
+ Widget w;
+ int row;
+ int column;
+ Pixel *fore;
+ Pixel *back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+
+ if (cell && cell->special_colour) {
+ *fore = cell->fore;
+ *back = cell->back;
+ }
+ else {
+ *fore = tw->table.foreground;
+ *back = tw->core.background_pixel;
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableGetCellColoursByCell (Widget w, XawTableCell cell,
+ Pixel *fore, Pixel *back)
+#else
+XawTableGetCellColoursByCell (w, cell, fore, back)
+ Widget w;
+ XawTableCell cell;
+ Pixel *fore;
+ Pixel *back;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (cell && cell->special_colour) {
+ *fore = cell->fore;
+ *back = cell->back;
+ }
+ else {
+ *fore = tw->table.foreground;
+ *back = tw->core.background_pixel;
+ }
+}
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Defaults #*/
+/*# #*/
+/*#########################################################################*/
+
+#ifdef notdef
+/* ARGSUSED */
+static Boolean PaintCellWithClear(p, i, j, call_data, client_data)
+ XtPointer p;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data; /* unused */
+{
+ Widget w = (Widget) p;
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell = (XawTableCell) call_data;
+ unsigned int width = (unsigned int) COLUMN_WIDTH(tw,j);
+ unsigned int height = (unsigned int) tw->table.row_height;
+ Position x;
+ Position y;
+
+
+ x = GetX(tw,j);
+ y = GetY(tw,i);
+
+ XClearArea (XtDisplay(w), XtWindow(w),
+ x + tw->table.label_shadow_thickness,
+ y + tw->table.label_shadow_thickness,
+ width, height, FALSE);
+
+ PaintLabel (w, i, j, x, y, cell);
+ PaintShadow (w, i, j, x, y, cell);
+
+ XFlush(XtDisplay(w));
+ return False;
+}
+#endif
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetColumnJustify (Widget w, int column, XtJustify justify)
+#else
+XawTableSetColumnJustify (w, column, justify)
+ Widget w;
+ int column;
+ XtJustify justify;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int i, j;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return;
+
+ COLUMN_DATA(tw)[column].flag |= _CL_justify;
+ COLUMN_DATA(tw)[column].justify = justify;
+
+ for(i = 0; i < ROWS(tw); i++)
+ Reposition(tw, NULL, i, column);
+
+ if (XtIsRealized(w) && w->core.visible &&
+ !tw->table.no_redraw && !tw->table.no_refigure)
+ {
+ (void)go_table((XtPointer)w, PaintCell, STUFF(tw),
+ 0, ROWS(tw)-1, column, column,
+ XawTABLE_DOWN_RIGHT,
+ &i, &j, (XtPointer)NULL);
+ XFlush(XtDisplay(w));
+ }
+}
+
+
+XtJustify
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnJustify (Widget w, int column)
+#else
+XawTableGetColumnJustify (w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return XtJustifyCenter;
+
+ if (COLUMN_DATA(tw)[column].flag & _CL_justify)
+ return COLUMN_DATA(tw)[column].justify;
+
+ return XtJustifyCenter;
+}
+
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetColumnWidth (Widget w, int column, int width)
+#else
+XawTableSetColumnWidth(w, column, width)
+ Widget w;
+ int column;
+ int width;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCallbackStruct callback_str;
+ register int row;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return;
+
+ if ((COLUMN_DATA(tw)[column].flag & _CL_width) &&
+ COLUMN_DATA(tw)[column].width == width)
+ return;
+
+ COLUMN_DATA(tw)[column].flag |= _CL_width;
+ COLUMN_DATA(tw)[column].width = width;
+
+ for(row = 0; row < ROWS(tw); row++)
+ Reposition(tw, NULL, row, column);
+
+ UpdateTable(tw);
+
+ callback_str.reason = XawTABLE_CHANGED_COLUMN_WIDTH;
+ callback_str.event = (XEvent*)NULL;
+ callback_str.old_cell = (XawTableCell)NULL;
+ callback_str.new_cell = (XawTableCell)NULL;
+ callback_str.row = 0;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNchangedColumnWidth, callback_str);
+}
+
+
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnWidth (Widget w, int column)
+#else
+XawTableGetColumnWidth(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ return tw->table.column_default_width;
+
+ if ((COLUMN_DATA(tw)[column].flag & _CL_width))
+ return COLUMN_DATA(tw)[column].width;
+
+ return tw->table.column_default_width;
+}
+
+int
+#ifdef Xraw_NEED_PROTO
+XawTableGetColumnPixelWidth (Widget w, int column)
+#else
+XawTableGetColumnPixelWidth(w, column)
+ Widget w;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ int width;
+
+ if (column != InRange (column, 0, COLUMNS(tw)-1))
+ width = tw->table.column_default_width;
+ else if ((COLUMN_DATA(tw)[column].flag & _CL_width))
+ width = COLUMN_DATA(tw)[column].width;
+ else
+ width = tw->table.column_default_width;
+
+ if (tw->table.literal) {
+ width = width * tw->table.literal_width + 2 * tw->table.internal_width;
+ }
+
+ return width;
+}
+
+char *
+#ifdef Xraw_NEED_PROTO
+XawTableGetLabelByPosition (Widget w, int i, int j)
+#else
+ XawTableGetLabelByPosition(w,i,j)
+ Widget w;
+ int i,j;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (i != InRange(i, 0, ROWS(tw)-1)) ||
+ (j != InRange(j, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", i);
+ sprintf(subs[1], "%5d", j);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "GetLabelByPosition", "XawTableGetLabelByPosition","XawToolkitError",
+"XawTableGetLabelByPosition\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return NULL;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), i, j);
+ return GET_CELL_LABEL;
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableUnsetEdit (Widget w)
+#else
+ XawTableUnsetEdit(w)
+ Widget w;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ char* label;
+ XawTableCell cell;
+
+ if (XawTableIsEditManaged(w))
+ {
+ tw->table.no_redraw++;
+ UNMANAGE_EDIT(tw);
+ tw->table.no_redraw--;
+
+ XtVaGetValues(EDIT(w), "string", &label, NULL);
+
+ label = CopyOnlyPrintable(label);
+
+ cell = (XawTableCell)
+ get_cell(STUFF(tw),tw->table.edit_row, tw->table.edit_column);
+
+ if (!streq(label,CELL(label)))
+ XawTableSetLabel(w, tw->table.edit_row, tw->table.edit_column, label);
+
+ XtFree(label); /* XtMalloc in CopyOnlyPrintable */
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawTableSetEdit (Widget w, int row, int column)
+#else
+ XawTableSetEdit(w, row, column)
+ Widget w;
+ int row;
+ int column;
+#endif
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+
+ if (IsEditInRowColumn(tw, row, column) || STUFF(tw) == NULL)
+ return;
+
+ if ((ROWS(tw) < 1) || (COLUMNS(tw) < 1) ||
+ (row != InRange(row, 0, ROWS(tw)-1)) ||
+ (column != InRange(column, 0, COLUMNS(tw)-1)))
+ {
+ String subs[3];
+ Cardinal num_subs = 3;
+ sprintf(subs[0], "%5d", row);
+ sprintf(subs[1], "%5d", column);
+ subs[2] = w->core.name;
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ "SetEdit", "XawTableSetEdit","XawToolkitError",
+"XawTableSetEdit\nIncorrect value of rows or columns (%s,%s) in TableWidget '%s' ",
+ subs, &num_subs);
+ return;
+ }
+
+ XawTableUnsetEdit(w);
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (CELL(label) == NULL)
+ XtVaSetValues(EDIT(tw), "string", Dummy, NULL);
+ else
+ XtVaSetValues(EDIT(tw), "string", CELL(label), NULL);
+
+ tw->table.edit_row = row;
+ tw->table.edit_column = column;
+
+ MoveEditCell (tw, tw->table.edit_row, tw->table.edit_column);
+
+ MANAGE_EDIT(tw);
+}
+
+/******************************************************************
+ *
+ * Actions
+ *
+ ******************************************************************/
+
+static void HighlightCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int row, column;
+ Position x,y;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ if (*num_params == 2)
+ {
+ row = atoi(params[0]);
+ column = atoi(params[1]);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ ExtractPosition(event, &x, &y , &tm);
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+ }
+ else
+ {
+ return;
+ }
+
+ cell = (XawTableCell) get_cell (STUFF(tw), row, column);
+
+ if (CELL(highlight))
+ return ;
+
+ CELL(highlight) = True;
+
+ x = GetX(tw,column);
+ y = GetY(tw,row);
+
+ PaintLabel(w, row, column, x, y, cell);
+ XFlush(XtDisplay(w));
+}
+
+/* ARGSUSED */
+static void UnhighlightCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ XawTableCell cell;
+ int row, column;
+ Position x,y;
+ Time tm;
+ unsigned int width;
+ unsigned int height;
+
+ if (!tw->table.editable)
+ return;
+
+ if (*num_params == 2)
+ {
+ row = atoi(params[0]);
+ column = atoi(params[1]);
+ }
+ else if (event != (XEvent*)NULL)
+ {
+ ExtractPosition(event, &x, &y , &tm);
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+ }
+ else
+ {
+ return;
+ }
+
+ cell = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ if (!CELL(highlight))
+ return ;
+
+ CELL(highlight) = False;
+
+ width = (unsigned int) COLUMN_WIDTH(tw, column) +
+ 2 * tw->table.label_shadow_thickness;
+ height = (unsigned int) tw->table.row_height +
+ 2 * tw->table.label_shadow_thickness;
+
+ XClearArea(XtDisplay(w), XtWindow(w),
+ (int)GetX(tw,column),
+ (int)GetY(tw,row),
+ width, height, FALSE);
+
+ PaintLabel(w, row, column, x, y, cell);
+
+ XFlush(XtDisplay(w));
+
+}
+
+/* ARGSUSED */
+static void WhatCell(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ XawTableCallbackStruct callback_str;
+ XawTableCell cell;
+ Time tm;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y , &tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ cell = (XawTableCell) get_cell (STUFF(tw), row, column);
+
+ callback_str.reason = XawTABLE_WHAT_CELL;
+ callback_str.event = event;
+ callback_str.old_cell = cell;
+ callback_str.new_cell = cell;
+ callback_str.row = row;
+ callback_str.column = column;
+ callback_str.do_it = True;
+
+ DO_CALLBACK(w, XtNwhatCell, callback_str);
+}
+
+/* ARGSUSED */
+static void KeyReturn(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ Widget tw;
+ KeySym ksSymbol;
+
+ ksSymbol = XtGetActionKeysym(event, (Modifiers*)NULL);
+
+ if (ksSymbol == XK_Return || ksSymbol == XK_Linefeed)
+ {
+ XtVaGetValues(w, XtNuserData, &tw, NULL);
+ XawTableUnsetEdit(tw);
+ }
+
+}
+
+static Atom FetchAtom(w, name)
+ Widget w;
+ String name;
+{
+ Atom a;
+ XrmValue source, dest;
+
+ source.size = strlen(name)+1;
+ source.addr = name;
+ dest.size = sizeof(Atom);
+ dest.addr = (XtPointer) &a;
+
+ (void) XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
+ return a;
+}
+
+/* ARGSUSED */
+static Boolean DeliverSelection(w, selection, target,
+ type, value, length, format)
+ Widget w;
+ Atom *selection, *target, *type;
+ XtPointer *value;
+ unsigned long *length;
+ int *format;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ static Atom targets = 0;
+
+ if (targets == 0) {
+ targets = FetchAtom(w, "TARGETS");
+ }
+
+ if (*target == targets) {
+ *type = XA_ATOM;
+ *value = (XtPointer) CALLOC(1, Atom);
+ *(Atom *) *value = XA_STRING;
+ *length = 1;
+ *format = 32;
+ return TRUE;
+ }
+
+ if (*target == XA_STRING) {
+ *type = XA_STRING;
+ *value = (XtPointer) XtNewString(tw->table.cell_own->label);
+ *length = tw->table.cell_own->label_len;
+ *format = 8;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* ARGSUSED */
+static void LoseSelection(w, selection)
+ Widget w;
+ Atom *selection;
+{
+ XawTableWidget tw = (XawTableWidget) w;
+ XawTableCell cell;
+ int row, column;
+ int x,y;
+ unsigned int width, height;
+
+ cell = tw->table.cell_own;
+ tw->table.cell_own = (XawTableCell)NULL;
+
+ if (!CELL(highlight))
+ return ;
+
+ get_cell_positions(cell, &row, &column);
+
+ CELL(highlight) = False;
+
+ x = GetX(tw,column) + tw->table.label_shadow_thickness;
+ y = GetY(tw,row) + tw->table.label_shadow_thickness;
+ width = (unsigned int) COLUMN_WIDTH(tw, column);
+ height = (unsigned int) tw->table.row_height;
+
+ XClearArea(XtDisplay(w), XtWindow(w), x, y, width, height, FALSE);
+ (void)PaintCell(w, row, column, (XtPointer)cell, (XtPointer)NULL);
+
+ XFlush(XtDisplay(w));
+}
+
+static int GetCutBufferNumber();
+
+static void StoreBuffer(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* selections in precedence order */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x, y;
+ int row, column;
+ int i, buffer;
+ Time tm;
+ Atom selection;
+
+ if (!tw->table.editable)
+ return;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y ,&tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ if (tw->table.cell_own != (XawTableCell)NULL)
+ LoseSelection(w, (Atom*)NULL);
+
+ tw->table.cell_own = (XawTableCell)get_cell(STUFF(tw), row, column);
+
+ for(i=0; i<(int)*num_params; i++) {
+ selection = FetchAtom(w, *(String *)(params+i));
+
+ buffer = GetCutBufferNumber(selection);
+
+ if (buffer >= 0) {
+ if (buffer == 0) {
+
+#define Create(buffer) \
+ XChangeProperty(XtDisplay(w), DefaultRootWindow(XtDisplay(w)),\
+ buffer,XA_STRING, 8,PropModeAppend, NULL, 0)
+
+ Create(XA_CUT_BUFFER0);
+ Create(XA_CUT_BUFFER1);
+ Create(XA_CUT_BUFFER2);
+ Create(XA_CUT_BUFFER3);
+ Create(XA_CUT_BUFFER4);
+ Create(XA_CUT_BUFFER5);
+ Create(XA_CUT_BUFFER6);
+ Create(XA_CUT_BUFFER7);
+#undef Create
+
+ XRotateBuffers(XtDisplay(w), 1);
+ }
+
+ XStoreBuffer(XtDisplay(w), tw->table.cell_own->label,
+ (int)MIN(tw->table.cell_own->label_len, MAXCUT), buffer);
+
+ } else {
+ tw->table.selections[tw->table.num_selections++] = selection;
+
+ XtOwnSelection (w, selection, tm,
+ DeliverSelection, LoseSelection,
+ (XtSelectionDoneProc) NULL);
+ }
+ }
+}
+
+
+/* ARGSUSED */
+static void CallEdit(w,event,params,num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ ExtractPosition(event, &x, &y , &tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ XawTableSetEdit(w, row, column);
+}
+
+
+
+typedef struct {
+ Widget w;
+ Atom *selections;
+ Time time;
+ int row;
+ int column;
+ int count;
+ int num;
+}RowColumn;
+
+static void GetProc();
+
+static void GetSelection (rc)
+ RowColumn *rc;
+{
+ Atom selection;
+ int buffer;
+ int nbytes;
+ char *label;
+
+ selection = *(rc->selections + rc->num);
+
+ if (rc->num < rc->count){
+
+ buffer = GetCutBufferNumber(selection);
+
+ if (buffer >= 0) {
+ label = XFetchBuffer(XtDisplay(rc->w), &nbytes, buffer);
+ XawTableSetLabel(rc->w, rc->row, rc->column, label);
+ XtFree((XtPointer)rc->selections);
+ XtFree((XtPointer)rc);
+ }else {
+ XtGetSelectionValue(rc->w, selection, XA_STRING, GetProc,
+ (XtPointer)rc, rc->time);
+ rc->num++;
+ }
+ }
+}
+
+/* ARGSUSED */
+static void GetProc(w, client_data, selection,
+ type, value, length, format)
+ Widget w;
+ XtPointer client_data;
+ Atom *selection;
+ Atom *type;
+ XtPointer value;
+ unsigned long *length;
+ int *format;
+{
+ RowColumn *rc = (RowColumn*)client_data;
+
+ if ((*type == XA_STRING) && (value != NULL)) {
+ XawTableSetLabel(w, rc->row, rc->column, (char*)value);
+ XtFree((XtPointer)value);
+ XtFree((XtPointer)client_data);
+ }else {
+ GetSelection(rc);
+ }
+
+}
+
+static void InsertSelection(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* selections in precedence order */
+ Cardinal *num_params;
+{
+ XawTableWidget tw = (XawTableWidget)w;
+ Position x,y;
+ int row, column;
+ RowColumn *rc;
+ Time tm;
+
+ if (!tw->table.editable)
+ return;
+
+ if (event->type != ButtonPress && event->type != ButtonRelease)
+ return;
+
+ ExtractPosition(event, &x, &y ,&tm);
+
+ if (ExtractCell(tw, x, y, &row, &column))
+ return ;
+
+ if (*num_params > 0) {
+
+ rc = XtNew(RowColumn);
+
+ rc->time = tm;
+ rc->w = w;
+ rc->row = row;
+ rc->column = column;
+ rc->count = (int)*num_params;
+ rc->num = 0;
+
+ if (*num_params > (Cardinal)0) {
+ rc->selections = CALLOC(*num_params, Atom);
+ XmuInternStrings(XtDisplay(w), params, *num_params, rc->selections);
+ } else {
+ rc->selections = XtNew(Atom);
+ *rc->selections = FetchAtom(w, "PRIMARY");
+ }
+ GetSelection(rc);
+ }
+}
+
+
+static int GetCutBufferNumber(atom)
+ register Atom atom;
+{
+ if (atom == XA_CUT_BUFFER0) return(0);
+ if (atom == XA_CUT_BUFFER1) return(1);
+ if (atom == XA_CUT_BUFFER2) return(2);
+ if (atom == XA_CUT_BUFFER3) return(3);
+ if (atom == XA_CUT_BUFFER4) return(4);
+ if (atom == XA_CUT_BUFFER5) return(5);
+ if (atom == XA_CUT_BUFFER6) return(6);
+ if (atom == XA_CUT_BUFFER7) return(7);
+ return(-1);
+}
+
+
+/* ARGSUSED */
+static void DoingNothing(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ /* doing nothing */
+}
+
diff --git a/vendor/x11iraf/obm/ObmW/zz/Table.h b/vendor/x11iraf/obm/ObmW/zz/Table.h
new file mode 100644
index 00000000..4c7ab5cf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Table.h
@@ -0,0 +1,539 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _XawTable_h
+#define _XawTable_h
+
+#include <X11/Xmu/Converters.h>
+
+#include <X11/Xraw/Simple.h>
+#include <X11/Xraw/XawInit.h>
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resources #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XawTextEncoding8bit
+#define XawTextEncoding8bit 0
+#endif
+#ifndef XawTextEncodingChar2b
+#define XawTextEncodingChar2b 1
+#endif
+
+#ifndef XtNliteral
+#define XtNliteral "literal"
+#endif
+
+#ifndef XtNrows
+#define XtNrows "rows"
+#endif
+
+#ifndef XtNcolumns
+#define XtNcolumns "columns"
+#endif
+
+
+#ifndef XtNmaskNumber
+#define XtNmaskNumber "maskNumber"
+#endif
+
+#ifndef XtNrowOriented
+#define XtNrowOriented "rowOriented"
+#endif
+
+#ifndef XtNeditForeground
+#define XtNeditForeground "editForeground"
+#endif
+
+#ifndef XtNeditBackground
+#define XtNeditBackground "editBackground"
+#endif
+
+#ifndef XtNcolumnForeground
+#define XtNcolumnForeground "columnForeground"
+#endif
+
+#ifndef XtNrowForeground
+#define XtNrowForeground "rowForeground"
+#endif
+
+#ifndef XtNvetricalScroll
+#define XtNvetricalScroll "vetricalScroll"
+#endif
+
+#ifndef XtNhorizontalScroll
+#define XtNhorizontalScroll "horizontalScroll"
+#endif
+
+#ifndef XtNcolumnsWidth
+#define XtNcolumnsWidth "columnsWidth"
+#endif
+
+#ifndef XtNrowHeight
+#define XtNrowHeight "rowHeight"
+#endif
+
+#ifndef XtNdefaultWidth
+#define XtNdefaultWidth "defaultWidth"
+#endif
+
+#ifndef XtNeditable
+#define XtNeditable "editable"
+#endif
+
+#ifndef XtNliteralWidth
+#define XtNliteralWidth "literalWidth"
+#endif
+
+#ifndef XtNtableMargin
+#define XtNtableMargin "tableMargin"
+#endif
+
+#ifndef XtNrowMargin
+#define XtNrowMargin "rowMargin"
+#endif
+
+#ifndef XtNcolumnMargin
+#define XtNcolumnMargin "columnMargin"
+#endif
+
+#ifndef XtNlabelShadowWidth
+#define XtNlabelShadowWidth "labelShadowWidth"
+#endif
+
+#ifndef XtNencoding
+#define XtNencoding "encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Classes #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtCLiteral
+#define XtCLiteral "Literal"
+#endif
+
+#ifndef XtCColumns
+#define XtCColumns "Columns"
+#endif
+
+#ifndef XtCMaskNumber
+#define XtCMaskNumber "MaskNumber"
+#endif
+
+#ifndef XtCScroll
+#define XtCScroll "Scroll"
+#endif
+
+#ifndef XtCColumnsWidth
+#define XtCColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowHeight
+#define XtCRowHeight "RowHeight"
+#endif
+
+#ifndef XtCDefaultWidth
+#define XtCDefaultWidth "DefaultWidth"
+#endif
+
+#ifndef XtCEditable
+#define XtCEditable "Editable"
+#endif
+
+#ifndef XtCLiteralWidth
+#define XtCLiteralWidth "LiteralWidth"
+#endif
+
+#ifndef XtCRows
+#define XtCRows "Rows"
+#endif
+
+#ifndef XtCTableMargin
+#define XtCTableMargin "TableMargin"
+#endif
+
+#ifndef XtCRowMargin
+#define XtCRowMargin "RowMargin"
+#endif
+
+#ifndef XtCColumnMargin
+#define XtCColumnMargin "ColumnMargin"
+#endif
+
+#ifndef XtCLabelShadowWidth
+#define XtCLabelShadowWidth "LabelShadowWidth"
+#endif
+
+#ifndef XtCEncoding
+#define XtCEncoding "Encoding"
+#endif
+
+
+
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# New Resource Types #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtRColumnsWidth
+#define XtRColumnsWidth "ColumnsWidth"
+#endif
+
+#ifndef XtCRowOriented
+#define XtCRowOriented "RowOriented"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Allowance Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNallowAddColumn
+#define XtNallowAddColumn "allowAddColumn"
+#endif
+
+#ifndef XtNallowAddRow
+#define XtNallowAddRow "allowAddRow"
+#endif
+
+#ifndef XtNallowDeleteColumn
+#define XtNallowDeleteColumn "allowDeleteColumn"
+#endif
+
+#ifndef XtNallowDeleteRow
+#define XtNallowDeleteRow "allowDeleteRow"
+#endif
+
+#ifndef XtNallowDeleteTable
+#define XtNallowDeleteTable "allowDeleteTable"
+#endif
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Information Callbacks #*/
+/*# #*/
+/*#########################################################################*/
+#ifndef XtNaddColumn
+#define XtNaddColumn "addColumn"
+#endif
+
+#ifndef XtNaddRow
+#define XtNaddRow "addRow"
+#endif
+
+#ifndef XtNchangedCell
+#define XtNchangedCell "changedCell"
+#endif
+
+#ifndef XtNchangedColumnWidth
+#define XtNchangedColumnWidth "changedColumnWidth"
+#endif
+
+#ifndef XtNchangedRowHeight
+#define XtNchangedRowHeight "changedRowHeight"
+#endif
+
+#ifndef XtNcreateTable
+#define XtNcreateTable "createTable"
+#endif
+
+#ifndef XtNdeleteColumn
+#define XtNdeleteColumn "deleteColumn"
+#endif
+
+#ifndef XtNdeleteRow
+#define XtNdeleteRow "deleteRow"
+#endif
+
+#ifndef XtNdeleteTable
+#define XtNdeleteTable "deleteTable"
+#endif
+
+#ifndef XtNwhatCell
+#define XtNwhatCell "whatCell"
+#endif
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# XawTableCell & XawTableColumn #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct _XawTableCellRec *XawTableCell; /* opaque to outside */
+
+typedef struct _XawTableColumnRec *XawTableColumn; /* opaque to outside */
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routine and Direction Types #*/
+/*# #*/
+/*#########################################################################*/
+typedef Boolean (*XawTableProc) Xraw_PROTO((Widget,
+ int,
+ int,
+ XawTableCell,
+ XtPointer));
+enum XawTableBypassDirection{
+ XawTABLE_RIGHT_DOWN,
+ XawTABLE_DOWN_RIGHT
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Reasons #*/
+/*# #*/
+/*#########################################################################*/
+enum XawTableReasons{
+ XawTABLE_ALLOW_ADD_COLUMN = Xraw_TABLE,
+ XawTABLE_ALLOW_ADD_ROW,
+ XawTABLE_ALLOW_CREATE_TABLE,
+ XawTABLE_ALLOW_DELETE_COLUMN,
+ XawTABLE_ALLOW_DELETE_ROW,
+ XawTABLE_ALLOW_DELETE_TABLE,
+
+ XawTABLE_ADD_COLUMN,
+ XawTABLE_ADD_ROW,
+ XawTABLE_CHANGED_CELL,
+ XawTABLE_CHANGED_COLUMN_WIDTH,
+ XawTABLE_CHANGED_ROW_HEIGHT,
+ XawTABLE_CREATE_TABLE,
+ XawTABLE_DELETE_COLUMN,
+ XawTABLE_DELETE_ROW,
+ XawTABLE_DELETE_TABLE,
+ XawTABLE_WHAT_CELL
+};
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Callback Structure #*/
+/*# #*/
+/*#########################################################################*/
+typedef struct {
+ int reason;
+ XEvent *event;
+ XawTableCell old_cell;
+ XawTableCell new_cell;
+ int row;
+ int column;
+ Boolean do_it;
+}XawTableCallbackStruct;
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Layout Control Routine #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableDoLayout Xraw_PROTO((Widget w,
+ Boolean do_layout));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Stuff Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetNewSize Xraw_PROTO((Widget w,
+ int rows,
+ int columns));
+
+extern void XawTableGetSize Xraw_PROTO((Widget w,
+ int *rows,
+ int *columns));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Row Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependRow Xraw_PROTO((Widget w));
+
+extern int XawTableAppendRow Xraw_PROTO((Widget w));
+
+extern int XawTableInsertRow Xraw_PROTO((Widget w, int row));
+
+extern int XawTableDeleteRow Xraw_PROTO((Widget w, int row));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTablePrependColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableAppendColumn Xraw_PROTO((Widget w, int width));
+
+extern int XawTableInsertColumn Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableDeleteColumn Xraw_PROTO((Widget w, int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Label Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern char *XawTableGetLabelByCell Xraw_PROTO((XawTableCell cell));
+
+extern char *XawTableGetLabelByPosition Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetLabel Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ char *label));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Bypass Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableWalk Xraw_PROTO((Widget w,
+ XawTableProc proc,
+ int b_row,
+ int e_row,
+ int b_column,
+ int e_column,
+ int direction,
+ int *row, int *column,
+ XtPointer client_data));
+
+extern Boolean XawTableSearchLabel Xraw_PROTO((Widget w,
+ char *name,
+ int *row,
+ int *column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Edit Cell Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern Boolean XawTableIsEditManaged Xraw_PROTO((Widget w));
+
+extern void XawTableGetEditPosition Xraw_PROTO((Widget w,
+ int *row,
+ int *column));
+
+extern void XawTableUnsetEdit Xraw_PROTO((Widget w));
+
+extern void XawTableSetEdit Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Set Colour Routines #*/
+/*# #*/
+/*#########################################################################*/
+extern int XawTableSetCellBackground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel background));
+
+extern int XawTableSetCellForeground Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground));
+
+extern int XawTableSetCellDefaultColours Xraw_PROTO((Widget w,
+ int row,
+ int column));
+
+extern int XawTableSetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel foreground,
+ Pixel background));
+
+
+extern void XawTableGetCellColours Xraw_PROTO((Widget w,
+ int row,
+ int column,
+ Pixel *foreground,
+ Pixel *background));
+
+extern void XawTableGetCellColoursByCell Xraw_PROTO((Widget w,
+ XawTableCell cell,
+ Pixel *foreground,
+ Pixel *background));
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Column Deta #*/
+/*# #*/
+/*#########################################################################*/
+extern void XawTableSetColumnJustify Xraw_PROTO((Widget w,
+ int column,
+ XtJustify justify));
+
+extern XtJustify XawTableGetColumnJustify Xraw_PROTO((Widget w,
+ int column));
+
+extern void XawTableSetColumnWidth Xraw_PROTO((Widget w,
+ int column,
+ int width));
+
+extern int XawTableGetColumnWidth Xraw_PROTO((Widget w,
+ int column));
+
+extern int XawTableGetColumnPixelWidth Xraw_PROTO((Widget w,
+ int column));
+
+
+
+/*#########################################################################*/
+/*# #*/
+/*# Widget Class Pointer #*/
+/*# #*/
+/*#########################################################################*/
+extern WidgetClass tableWidgetClass;
+
+typedef struct _TableClassRec *XawTableWidgetClass;
+typedef struct _TableRec *XawTableWidget;
+
+
+#endif /* _XawTable_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/vendor/x11iraf/obm/ObmW/zz/Table3d.c b/vendor/x11iraf/obm/ObmW/zz/Table3d.c
new file mode 100644
index 00000000..085b2cac
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Table3d.c
@@ -0,0 +1,924 @@
+#include <X11/Xraw/3d.h>
+#include <X11/Xraw/color.h>
+
+#define WHITE WhitePixelOfScreen
+#define BLACK BlackPixelOfScreen
+#define SWITCH(a,b) (top_or_bottom == TOP ? a : b)
+
+#define DEPTH_SCREEN(w) DefaultDepthOfScreen(XtScreen(w))
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define TOP_VALUE_RATIO (1.3)
+#define BOT_VALUE_RATIO (0.6)
+#define ARM_VALUE_RATIO (0.85)
+
+#define Top_Cash (1<<0L)
+#define Bot_Cash (1<<1L)
+#define Arm_Cash (1<<2L)
+
+typedef struct _ColorCashRec {
+ struct _ColorCashRec* nxt;
+ XColor col;
+ RGB rgb[1];
+ HSV hsv[1];
+ RGB top[1];
+ RGB bot[1];
+ RGB arm[1];
+ unsigned int set;
+}ColorCashRec, *ColorCash;
+
+static ColorCashRec* color_cash = NULL;
+static void GetTopShadow();
+
+
+static void GetTopShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Top_Cash)
+ {
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= TOP_VALUE_RATIO;
+ cash->hsv[0].v = MIN(cash->hsv[0].v, 1.0);
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->top);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+
+ cash->set |= Top_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= TOP_VALUE_RATIO;
+ cash->hsv[0].v = MIN(cash->hsv[0].v, 1.0);
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->top);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->top[0].r;
+ to->green = cash->top[0].g;
+ to->blue = cash->top[0].b;
+
+ cash->set = Top_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+static void GetBotShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Bot_Cash)
+ {
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= BOT_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->bot);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+
+ cash->set |= Bot_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= BOT_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->bot);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->bot[0].r;
+ to->green = cash->bot[0].g;
+ to->blue = cash->bot[0].b;
+
+ cash->set = Bot_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+static void GetArmShadow(trom ,to)
+ XColor* trom;
+ XColor* to;
+{
+ ColorCashRec* cash;
+ float save;
+
+ for (cash = color_cash; cash != NULL; cash = cash->nxt)
+ {
+ if (cash->col.red == trom->red &&
+ cash->col.green == trom->green &&
+ cash->col.blue == trom->blue)
+ {
+ if (cash->set & Arm_Cash)
+ {
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+ }
+ else
+ {
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= ARM_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->arm);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+
+ cash->set |= Arm_Cash;
+ }
+
+ return;
+ }
+ }
+
+ cash = XtNew (ColorCashRec);
+
+ cash->col.red = cash->rgb[0].r = trom->red;
+ cash->col.green = cash->rgb[0].g = trom->green;
+ cash->col.blue = cash->rgb[0].b = trom->blue;
+
+ RGBToHSV((RGB*)cash->rgb, (HSV*)cash->hsv);
+
+ save = cash->hsv[0].v;
+ cash->hsv[0].v *= ARM_VALUE_RATIO;
+
+ HSVToRGB((HSV*)cash->hsv, (RGB*)cash->arm);
+
+ cash->hsv[0].v = save;
+
+ to->red = cash->arm[0].r;
+ to->green = cash->arm[0].g;
+ to->blue = cash->arm[0].b;
+
+ cash->set = Arm_Cash;
+
+ cash->nxt = color_cash;
+ color_cash = cash;
+}
+
+unsigned int shadowpm_width = 8;
+unsigned int shadowpm_height= 8;
+
+static char shadow_bits[] = {
+ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
+
+static char mtshadowpm_bits[] = {
+ 0x92, 0x24, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
+
+static char mbshadowpm_bits[] = {
+ 0x6d, 0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d, 0xdb};
+
+
+GC
+#ifdef Xraw_NEED_PROTO
+AllocGCFromPixmap (Widget w, Pixmap pixmap)
+#else
+AllocGCFromPixmap(w, pixmap)
+ Widget w;
+ Pixmap pixmap;
+#endif
+{
+ XGCValues values;
+
+ if (pixmap != None) {
+ values.tile = pixmap;
+ values.fill_style = FillTiled;
+ return XtGetGC(w, (XtGCMask)(GCTile | GCFillStyle), &values);
+ }
+
+ return XtGetGC(w, (XtGCMask)0, (XGCValues *)NULL);
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+AllocGCFromPixel (Widget w, Pixel fore)
+#else
+AllocGCFromPixel(w, fore)
+ Widget w;
+ Pixel fore;
+#endif
+{
+ XGCValues values;
+
+ values.foreground = fore;
+ return XtGetGC(w, GCForeground, &values);
+}
+
+static Pixmap Depth_1_ShadowPixmap (w, top_or_bottom)
+ Widget w;
+ int top_or_bottom;
+{
+ Screen *scn = XtScreen (w);
+
+ if (DEPTH_SCREEN(w) == 1)
+ return XCreatePixmapFromBitmapData (XtDisplay (w),
+ RootWindowOfScreen (scn),
+ shadow_bits,
+ shadowpm_width,
+ shadowpm_height,
+ SWITCH(BLACK (scn), WHITE (scn)),
+ SWITCH(WHITE (scn), BLACK (scn)),
+ 1);
+ else
+ return None;
+}
+
+static Pixmap Depth_NOT_1_ShadowPixmap (w, colour, top_or_bottom)
+ Widget w;
+ Pixel colour;
+ int top_or_bottom;
+{
+ Display *dpy = XtDisplay (w);
+ Screen *scn = XtScreen (w);
+ unsigned long fore;
+ unsigned long back;
+ char *pm_data;
+ int depth = DEPTH_SCREEN(w);
+
+ if (depth == 1)
+ return None;
+
+ if (colour == WHITE (scn) || colour == BLACK (scn)) {
+ fore = WHITE (scn);
+ back = BLACK (scn);
+ pm_data = SWITCH(mtshadowpm_bits, mbshadowpm_bits);
+ } else {
+ fore = colour;
+ back = SWITCH (WHITE (scn), BLACK (scn));
+ pm_data = shadow_bits;
+ }
+
+ return XCreatePixmapFromBitmapData (dpy,
+ RootWindowOfScreen (scn),
+ pm_data,
+ shadowpm_width,
+ shadowpm_height,
+ fore,
+ back,
+ depth);
+}
+
+Pixmap
+#ifdef Xraw_NEED_PROTO
+CreateShadowPixmap (Widget w, Pixel colour, int top_or_bottom)
+#else
+CreateShadowPixmap (w, colour, top_or_bottom)
+ Widget w;
+ Pixel colour;
+ int top_or_bottom;
+#endif
+{
+ if (DEPTH_SCREEN(w) == 1)
+ return Depth_1_ShadowPixmap (w, top_or_bottom);
+ else
+ return Depth_NOT_1_ShadowPixmap (w, colour, top_or_bottom);
+}
+
+#define _MIN(x,y) (unsigned short) ((x) < (y)) ? (x) : (y)
+#define _MAX(x,y) (unsigned short) ((x) < (y)) ? (y) : (x)
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+AllocShadowPixel (
+ Widget w,
+ Pixel base,
+ int brightness,
+ Pixel *result)
+#else
+AllocShadowPixel (w, base, brightness, result)
+ Widget w;
+ Pixel base;
+ int brightness;
+ Pixel *result; /* RETURN */
+#endif
+{
+ XColor set;
+ XColor get;
+ double mult;
+ Colormap cmap= ((CoreWidget)w)->core.colormap;
+ unsigned short red;
+ unsigned short green;
+ unsigned short blue;
+
+ get.pixel = base;
+ XQueryColor (XtDisplay (w), cmap, &get);
+ mult = (double)(100 + brightness) / ((double) 100.0);
+
+ red = mult * (double)get.red;
+ green = mult * (double)get.green;
+ blue = mult * (double)get.blue;
+
+ set.red = _MAX(0,_MIN (65535, red));
+ set.green = _MAX(0,_MIN (65535, green));
+ set.blue = _MAX(0,_MIN (65535, blue));
+
+#define EQ(field) (set.field == get.field)
+ if (EQ(red) && EQ(green) && EQ(blue))
+#undef EQ
+ return False;
+
+ if (XAllocColor (XtDisplay (w), cmap, &set) != 0) {
+ *result = set.pixel;
+ return True;
+ } else
+ return False;
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeGC (Widget w,
+ Pixel base,
+ int brightness,
+ Boolean pseudo,
+ int top_or_bottom)
+#else
+MakeGC(w, base, brightness, pseudo, top_or_bottom)
+ Widget w;
+ Pixel base;
+ int brightness;
+ Boolean pseudo;
+ int top_or_bottom;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (pseudo) {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ } else {
+ if (AllocShadowPixel(w, base, brightness, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ }
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, top_or_bottom);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeTopShadowGC (Widget w, Pixel base)
+#else
+MakeTopShadowGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (TopShadowColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, TOP);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, TOP);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeBottomShadowGC (Widget w, Pixel base)
+#else
+MakeBottomShadowGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (BottomShadowColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+GC
+#ifdef Xraw_NEED_PROTO
+MakeArmedGC (Widget w, Pixel base)
+#else
+MakeArmedGC(w, base)
+ Widget w;
+ Pixel base;
+#endif
+{
+ Pixel fore;
+ Pixmap tile;
+
+ if (DEPTH_SCREEN(w) > 1) {
+ if (ArmedColor(w, base, &fore)) {
+ return AllocGCFromPixel(w, fore);
+ } else {
+ tile = Depth_NOT_1_ShadowPixmap (w, base, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+ } else {
+ tile = Depth_1_ShadowPixmap (w, BOTTOM);
+ return AllocGCFromPixmap(w, tile);
+ }
+}
+
+void
+#ifdef Xraw_NEED_PROTO
+XawDrawFrame (Widget gw,
+ Position x,
+ Position y,
+ Dimension w,
+ Dimension h,
+ XawFrameType frame_type,
+ Dimension t,
+ GC lightgc,
+ GC darkgc)
+#else
+XawDrawFrame (gw, x, y, w, h, frame_type, t, lightgc, darkgc)
+ Widget gw;
+ Position x;
+ Position y;
+ Dimension w;
+ Dimension h;
+ XawFrameType frame_type;
+ Dimension t;
+ GC lightgc;
+ GC darkgc;
+#endif
+{
+ XPoint top_polygon[6];
+ XPoint bottom_polygon[6];
+ XPoint points[3];
+
+
+ if (t == 0 || w == 0 || h == 0)
+ return;
+
+ if( lightgc == (GC)NULL ){
+ XtWarning("XawDrawFrame: lightgc is NULL in XawDrawFrame.");
+ return;
+ }
+
+ if( darkgc == (GC)NULL ){
+ XtWarning("XawDrawFrame: darkgc is NULL in XawDrawFrame.");
+ return;
+ }
+
+ if (!XtIsRealized(gw)) {
+ XtWarning("XawDrawFrame: widget is not realized!!!");
+ return;
+ }
+
+#define topPolygon(i,xx,yy) \
+ top_polygon[i].x = (short) (xx); \
+ top_polygon[i].y = (short) (yy)
+
+#define bottomPolygon(i,xx,yy) \
+ bottom_polygon[i].x = (short) (xx); \
+ bottom_polygon[i].y = (short) (yy)
+
+
+ if (frame_type == XawTACK && t <= 2)
+ frame_type = XawLEDGED;
+
+ switch (frame_type) {
+
+ case XawRAISED :
+ case XawSUNKEN :
+
+ topPolygon (0,x ,y ); bottomPolygon (0,x+w ,y+h );
+ topPolygon (1,x+w ,y ); bottomPolygon (1,x ,y+h );
+ topPolygon (2,x+w-t,y+t ); bottomPolygon (2,x+t ,y+h-t);
+ topPolygon (3,x+t ,y+t ); bottomPolygon (3,x+w-t,y+h-t);
+ topPolygon (4,x+t ,y+h-t); bottomPolygon (4,x+w-t,y+t );
+ topPolygon (5,x ,y+h ); bottomPolygon (5,x+w ,y );
+
+ if (frame_type == XawSUNKEN)
+ {
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+ }
+ else if (frame_type == XawRAISED)
+ {
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+ }
+
+ break;
+
+ case XawTACK :
+
+ t -= 2;
+
+ topPolygon (0,x ,y ); bottomPolygon (0,x+w ,y+h );
+ topPolygon (1,x+w ,y ); bottomPolygon (1,x ,y+h );
+ topPolygon (2,x+w-t,y+t ); bottomPolygon (2,x+t ,y+h-t);
+ topPolygon (3,x+t ,y+t ); bottomPolygon (3,x+w-t,y+h-t);
+ topPolygon (4,x+t ,y+h-t); bottomPolygon (4,x+w-t,y+t );
+ topPolygon (5,x ,y+h ); bottomPolygon (5,x+w ,y );
+
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ top_polygon, 6, Nonconvex, CoordModeOrigin);
+ XFillPolygon(XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ bottom_polygon, 6, Nonconvex, CoordModeOrigin);
+
+ points[0].x = x + t + 1; points[0].y = y + h - t - 2;
+ points[1].x = x + t + 1; points[1].y = y + t + 1;
+ points[2].x = x + w - t - 2; points[2].y = y + t + 1;
+
+ XDrawLines (XtDisplayOfObject(gw), XtWindowOfObject(gw), darkgc,
+ points, 3, CoordModeOrigin);
+
+ /* points[0].x = x + t + 1; points[0].y = y + h -t - 1; */
+ points[1].x = x + w - t - 2; points[1].y = y + h - t - 2;
+ /* points[2].x = x + w - t - 1; points[2].y = y + t + 1; */
+
+ XDrawLines (XtDisplayOfObject(gw), XtWindowOfObject(gw), lightgc,
+ points, 3, CoordModeOrigin);
+
+ break;
+
+ case XawLEDGED :
+
+ XawDrawFrame(gw, x, y, w, h, XawRAISED, t/2, lightgc, darkgc);
+ XawDrawFrame(gw, (Position)(x + t/2), (Position)(y + t/2),
+ (Dimension)(w - 2 * (t/2)), (Dimension)(h - 2 * (t/2)),
+ XawSUNKEN, t/2, lightgc, darkgc);
+ break;
+
+ case XawCHISELED :
+
+ XawDrawFrame(gw, x, y, w, h, XawSUNKEN, t/2, lightgc, darkgc);
+ XawDrawFrame(gw, (Position)(x + t/2),(Position)(y + t/2),
+ (Dimension)(w - 2 * (t/2)), (Dimension)(h - 2 * (t/2)),
+ XawRAISED, t/2, lightgc, darkgc);
+ break;
+
+ default :
+ break;
+
+ }
+
+#undef topPolygon
+#undef bottomPolygon
+}
+
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+BottomShadowColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+BottomShadowColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetBotShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+TopShadowColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+TopShadowColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetTopShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+ArmedColor( Widget widget,
+ Pixel base,
+ Pixel *result)
+#else
+ArmedColor(widget, base, result)
+ Widget widget;
+ Pixel base;
+ Pixel *result;
+#endif
+{
+ Colormap colormap;
+ XColor color;
+
+ if (XtIsWidget(widget))
+ colormap = widget->core.colormap;
+ else
+ colormap = (XtParent(widget))->core.colormap;
+
+ color.pixel = base;
+
+ XQueryColor(XtDisplay(widget), colormap, &color);
+
+ GetArmShadow(&color, &color);
+
+ if (XAllocColor (XtDisplay(widget), colormap, &color) != 0)
+ {
+ *result = color.pixel;
+ return True;
+ }
+ else
+ {
+ HSV hsv;
+ RGB rgb;
+
+ rgb.r = color.red;
+ rgb.g = color.green;
+ rgb.b = color.blue;
+
+ RGBToHSV ((RGB*)&rgb, (HSV*)&hsv);
+
+ if (hsv.v > 0.5)
+ *result = WhitePixelOfScreen(XtScreen (widget));
+ else
+ *result = BlackPixelOfScreen(XtScreen (widget));
+ return True;
+ }
+
+}
+
+
+
+#undef assign_max
+#undef assign_min
+
+
+void
+#ifdef Xraw_NEED_PROTO
+DrawRhombus (
+ Widget w,
+ short x,
+ short y,
+ short g,
+ short t,
+ GC top_shadow_GC,
+ GC foreground_gc,
+ GC bottom_shadow_GC,
+ Boolean state )
+#else
+DrawRhombus(w, x, y, g, t,
+ top_shadow_GC, foreground_gc, bottom_shadow_GC, state)
+ Widget w;
+ short x;
+ short y;
+ short g;
+ short t;
+ GC top_shadow_GC;
+ GC foreground_gc;
+ GC bottom_shadow_GC;
+ Boolean state;
+#endif
+{
+ XPoint top_shade[6];
+ XPoint bot_shade[6];
+ XPoint center[4];
+
+#define topPolygon(i,a,b) top_shade[i].x = a; top_shade[i].y = b
+#define bottomPolygon(i,a,b) bot_shade[i].x = a; bot_shade[i].y = b
+#define centerPolygon(i,a,b) center[i].x = a; center[i].y = b
+
+ topPolygon(0, x-g , y ); bottomPolygon(0, x-g , y );
+ topPolygon(1, x-g+t, y ); bottomPolygon(1, x-g+t, y );
+ topPolygon(2, x , y-g+t); bottomPolygon(2, x , y+g-t);
+ topPolygon(3, x+g-t, y ); bottomPolygon(3, x+g-t, y );
+ topPolygon(4, x+g , y ); bottomPolygon(4, x+g , y );
+ topPolygon(5, x , y-g ); bottomPolygon(5, x , y+g );
+
+ if (state)
+ {
+ if (foreground_gc)
+ {
+ centerPolygon(0, x-g+t, y );
+ centerPolygon(1, x , y-g+t);
+ centerPolygon(2, x+g-t, y );
+ centerPolygon(3, x , y+g-t);
+
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), foreground_gc,
+ center, XtNumber(center),
+ Convex, CoordModeOrigin);
+ }
+
+ if (bottom_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), bottom_shadow_GC,
+ top_shade, XtNumber(top_shade), Nonconvex, CoordModeOrigin);
+
+ if (top_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), top_shadow_GC,
+ bot_shade, XtNumber(bot_shade), Nonconvex, CoordModeOrigin);
+ }else{
+
+ if (top_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), top_shadow_GC,
+ top_shade, XtNumber(top_shade),
+ Nonconvex, CoordModeOrigin);
+
+ if (bottom_shadow_GC)
+ XFillPolygon(XtDisplayOfObject(w), XtWindowOfObject(w), bottom_shadow_GC,
+ bot_shade, XtNumber(bot_shade),
+ Nonconvex, CoordModeOrigin);
+ }
+
+#undef topPolygon
+#undef bottomPolygon
+#undef centerPolygon
+
+}
+
+Boolean
+#ifdef Xraw_NEED_PROTO
+FetchPixel (Widget w, String name, Pixel* pixel)
+#else
+FetchPixel(w, name, pixel)
+ Widget w;
+ String name;
+ Pixel* pixel;
+#endif
+{
+ XrmValue source, dest;
+
+ source.size = strlen(name)+1;
+ source.addr = name;
+ dest.size = sizeof(Pixel);
+ dest.addr = (caddr_t) pixel;
+
+ return XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest);
+}
diff --git a/vendor/x11iraf/obm/ObmW/zz/Table3d.h b/vendor/x11iraf/obm/ObmW/zz/Table3d.h
new file mode 100644
index 00000000..8d09dddf
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/Table3d.h
@@ -0,0 +1,145 @@
+#ifndef _3d_h_
+#define _3d_h_
+
+#include <stdio.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xraw/XawInit.h>
+
+typedef enum {
+ XawRAISED = Xraw_3d,
+ XawSUNKEN,
+ XawCHISELED,
+ XawLEDGED,
+ XawTACK
+} XawFrameType;
+
+#define TOP (1)
+#define BOTTOM (2)
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern Boolean ArmedColor Xraw_PROTO((Widget /* self */,
+ Pixel /* base */,
+ Pixel* /* result */));
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC AllocGCFromPixmap Xraw_PROTO((Widget , Pixmap ));
+
+
+extern GC AllocGCFromPixel Xraw_PROTO((Widget , Pixel ));
+
+
+extern Pixmap CreateShadowPixmap Xraw_PROTO((Widget ,
+ Pixel ,
+ int ));
+
+
+extern Boolean AllocShadowPixel Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Pixel * ));
+
+
+extern GC MakeGC Xraw_PROTO((Widget ,
+ Pixel ,
+ int ,
+ Boolean ,
+ int ));
+
+
+extern GC MakeTopShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeBottomShadowGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern GC MakeArmedGC Xraw_PROTO((Widget , Pixel ));
+
+
+extern void XawDrawFrame Xraw_PROTO((Widget ,
+ Position ,
+ Position ,
+ Dimension ,
+ Dimension ,
+ XawFrameType ,
+ Dimension ,
+ GC ,
+ GC ));
+
+
+extern void RGBtoHLS Xraw_PROTO((double ,
+ double ,
+ double ,
+ double * ,
+ double * ,
+ double * ));
+
+extern void HLStoRGB Xraw_PROTO((double * ,
+ double * ,
+ double * ,
+ double ,
+ double ,
+ double ));
+
+extern Boolean BottomShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean TopShadowColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern Boolean ArmedColor Xraw_PROTO((Widget ,
+ Pixel ,
+ Pixel * ));
+
+
+extern void DrawRhombus Xraw_PROTO((Widget ,
+ short ,
+ short ,
+ short ,
+ short ,
+ GC ,
+ GC ,
+ GC ,
+ Boolean ));
+
+extern Boolean FetchPixel Xraw_PROTO((Widget ,
+ String name ,
+ Pixel* ));
+
+#endif /* _3d_h_ */
+
+
+
+
diff --git a/vendor/x11iraf/obm/ObmW/zz/TableP.h b/vendor/x11iraf/obm/ObmW/zz/TableP.h
new file mode 100644
index 00000000..7daa38f8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/TableP.h
@@ -0,0 +1,166 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is desined for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advises, new components and patches of the existing programs.
+Commercial usage is also possible with participation of it's author.
+
+*************************************************************************/
+
+#ifndef _XawTableP_h
+#define _XawTableP_h
+
+/***********************************************************************
+ *
+ * Table Widget Private Data
+ *
+ ***********************************************************************/
+
+
+#include <X11/Xraw/ContainerP.h>
+#include <X11/Xraw/Table.h>
+#include <X11/Xraw/table.h>
+
+/* New fields for the Table widget class record */
+
+typedef struct {int foo;} TableClassPart;
+
+/* Full class record declaration */
+typedef struct _TableClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ConstraintClassPart constraint_class;
+ ContainerClassPart container_class;
+ TableClassPart table_class;
+} TableClassRec;
+
+#define MAX_ROWS 50
+
+typedef struct _NormalReverseGC {
+ int used;
+ Pixel fore;
+ Pixel back;
+ GC normal;
+ GC reverse;
+}NormalReverseGC;
+
+typedef struct _ShadowGC {
+ int used;
+ Pixel back;
+ GC top;
+ GC bottom;
+}ShadowGC;
+
+
+
+/* New fields for the Table widget record */
+typedef struct {
+ /* ------------------------ resources -----------------------*/
+ Pixel row_fore;
+ Pixel column_fore;
+ Pixel edit_fore;
+ Pixel edit_back;
+ Boolean row_oriented;
+ Boolean editable;
+ Boolean literal;
+
+ int mask_number;
+ int columns;
+ int rows;
+ Dimension tab_margin;
+ Dimension row_margin;
+ Dimension col_margin;
+ Dimension internal_width;
+ Dimension internal_height;
+ Dimension label_shadow_thickness;
+ unsigned char encoding;
+
+ /* Default Values */
+ Pixel foreground;
+ XtJustify justify;
+ XFontStruct *font;
+ int width;
+
+ /* Allowance CallbackList */
+ XtCallbackList allow_add_row;
+ XtCallbackList allow_add_column;
+ XtCallbackList allow_delete_column;
+ XtCallbackList allow_delete_row;
+ XtCallbackList allow_delete_table;
+
+ /* Information CallbackList */
+ XtCallbackList add_row;
+ XtCallbackList add_column;
+ XtCallbackList changed_cell;
+ XtCallbackList create_table;
+ XtCallbackList delete_column;
+ XtCallbackList delete_row;
+ XtCallbackList delete_table;
+ XtCallbackList what_cell;
+ XtCallbackList changed_column_width;
+ XtCallbackList changed_row_height;
+
+ Widget v_scroll;
+ Widget h_scroll;
+
+ int row_height;
+ int column_default_width;
+ int literal_width;
+
+ /* ------------------------ private state -----------------------*/
+
+ int no_refigure; /* no re-layout while > 0 */
+ int no_redraw; /* no re-draw while > 0 */
+ Boolean was_resized;
+
+
+ XawTableColumn column_data;
+
+ Dimension prefer_width;
+ Dimension prefer_height;
+ Widget edit;
+ int edit_row;
+ int edit_column;
+ XawTableCell cell_own;
+ XawTableCell table_stuff;
+
+ GC row_gc; /* Intrinsics sharedable GC */
+ GC column_gc; /* Intrinsics sharedable GC */
+
+ GC normal; /* Table sharedable GC */
+ GC reverse; /* Table sharedable GC */
+ GC top;
+ GC bottom;
+
+ GC edit_top;
+ GC edit_bottom;
+
+ NormalReverseGC *normal_hash_table;
+ ShadowGC *shadow_hash_table;
+ int mask_hash_table;
+
+ Atom selections[30];
+ int num_selections;
+} TablePart;
+
+/****************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************/
+
+typedef struct _TableRec {
+ CorePart core;
+ CompositePart composite;
+ ConstraintPart constraint;
+ ContainerPart container;
+ TablePart table;
+} TableRec;
+
+extern TableClassRec tableClassRec;
+
+#endif /* _XawTableP_h */
diff --git a/vendor/x11iraf/obm/ObmW/zz/TableUtil.c b/vendor/x11iraf/obm/ObmW/zz/TableUtil.c
new file mode 100644
index 00000000..ec2582be
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/TableUtil.c
@@ -0,0 +1,918 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#include <X11/Xraw/table.h>
+
+#ifdef EBUG_XRAW_MALLOC
+#include <dbmalloc/malloc.h>
+#endif
+
+/************************************************************************
+ *
+ * TABLE IS A GRID OF POINTER BINDED NODES
+ *
+ ************************************************************************/
+
+#define null (XawTableNode)NULL
+#define FREE(t) if((t) != null)XtFree((char*)(t))
+
+static void vert_tab_node_insert(f,s,p)
+ register XawTableNode f; /* insert after */
+ register XawTableNode s; /* insert before */
+ register XawTableNode p; /* to be inserted */
+{
+ if (f != null) f->b = p;
+ if (s != null) s->t = p;
+ if (p != null) {p->t = f; p->b = s;}
+}
+
+static void horiz_tab_node_insert(f,s,p)
+ register XawTableNode f; /* insert after */
+ register XawTableNode s; /* insert before */
+ register XawTableNode p; /* to be inserted */
+{
+ if (f != null) f->r = p;
+ if (s != null) s->l = p;
+ if (p != null) {p->l = f; p->r = s;}
+}
+
+static void vert_tab_node_reject(p)
+ register XawTableNode p;
+{
+ if (p == null) return;
+
+ if (p->t != null) p->t->b = p->b;
+ if (p->b != null) p->b->t = p->t;
+}
+
+static void horiz_tab_node_reject(p)
+ register XawTableNode p;
+{
+ if (p == null) return;
+
+ if (p->r != null) p->r->l = p->l;
+ if (p->l != null) p->l->r = p->r;
+}
+
+/* ARGSUSED */
+static XawTableProc del_cell (w, i, j, call_data, client_data)
+ XtPointer w;
+ int i;
+ int j;
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ XtFree((char*)call_data);
+ return False;
+}
+
+/*
+** Function name : row_delete
+**
+** Description : delete row which the node belongs to
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+row_delete (XtPointer f)
+#else
+row_delete(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return;
+
+ /* Go to left edge */
+ for(; p->l != null; p=p->l )
+ /*EMPTY*/;
+
+ /* Go to right with dettaching cell */
+ for(; p->r != null; p=p->r){
+ vert_tab_node_reject(p->l);
+ FREE(p->l);
+ }
+
+ /* Detach last but one cell in the row */
+ if (p->l != null){
+ vert_tab_node_reject(p->l);
+ FREE(p->l);
+ }
+
+ /* Detach very last cell in the row */
+ vert_tab_node_reject(p);
+ FREE(p);
+}
+
+/*
+** Function name : column_delete
+**
+** Description : delete column which the node belongs to
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+column_delete (XtPointer f)
+#else
+column_delete(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return;
+
+ /* Go up to the edge */
+ for(; p->t != null; p=p->t )
+ /*EMPTY*/;
+
+ /* Go down with dettaching cell */
+ for(; p->b != null; p=p->b){
+ horiz_tab_node_reject(p->t);
+ FREE(p->t);
+ }
+
+ /* Detach bottom but one cell in the column */
+ if (p->t != null){
+ horiz_tab_node_reject(p->t);
+ FREE(p->t);
+ }
+
+ /* Detach very bottom cell in the column */
+ horiz_tab_node_reject(p);
+ FREE(p);
+}
+
+
+
+/*
+** Function name : row_insert_after
+**
+** Description : insert row down to the row which the node belongs to
+** Input : poiter to the node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+row_insert_after (XtPointer d, int node_size)
+#else
+row_insert_after(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode left;
+
+ if (f == null)
+ return False;
+
+ /* go left till row edge */
+ for(; f->l != null; f=f->l )
+ /*EMPTY*/;
+
+ /* save very left node */
+ left = f;
+
+ /* go right and attach new cells via vertical ponters */
+ for(; f->r != null; f=f->r){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->b);
+ FREE(left->b);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f, f->b, p);
+ }
+
+ /* attach vertically very right cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->b);
+ FREE(left->b);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f, f->b, p);
+
+ /* if only one column */
+ if ( f->l == null ) {
+ f->b->l = f->b->r = null;
+ return True;
+ }
+
+ /* attach horizontally very right cell */
+ horiz_tab_node_insert(f->l->b,null,f->b);
+
+ /* bind via horizontal ponters */
+ for(f=f->l; f->l != null; f=f->l )
+ horiz_tab_node_insert(f->l->b,f->r->b,f->b);
+
+ /* attach horizontally very left cell */
+ horiz_tab_node_insert(null,f->r->b,f->b);
+
+ return True;
+}
+
+/*
+** Function name : row_insert_before
+**
+** Description : the same as previous, but only on top from row
+** Input : pointer to the node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+row_insert_before (XtPointer d, int node_size)
+#else
+row_insert_before(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode left;
+
+ if (f == null)
+ return False;
+
+ /* go left till row edge */
+ for(; f->l != null; f=f->l )
+ /*EMPTY*/;
+
+ /* save very left node */
+ left = f;
+
+ /* go right and attach new cells via vertical ponters */
+ for(; f->r != null; f=f->r){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->t);
+ FREE(left->t);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f->t, f, p);
+ }
+
+ /* attach vertically very right cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; left != f; left = left->r){
+ vert_tab_node_reject(left->t);
+ FREE(left->t);
+ }
+ return False;
+ }
+ vert_tab_node_insert(f->t, f, p);
+
+ /* if only one column */
+ if ( f->l == null ) {
+ f->t->l = f->t->r = null;
+ return True;
+ }
+
+ /* attach horizontally very right cell */
+ horiz_tab_node_insert(f->l->t,null,f->t);
+
+ /* bind via horizontal ponters */
+ for(f=f->l; f->l != null; f=f->l )
+ horiz_tab_node_insert(f->l->t,f->r->t,f->t);
+
+ /* attach horizontally very left cell */
+ horiz_tab_node_insert(null,f->r->t,f->t);
+
+ return True;
+}
+
+/*
+** Function name : column_insert_after
+**
+** Description : insert column right to the column which the node belongs to
+** Input : pointer to the node, size of node
+** Output : True if successful
+[<*/
+
+Boolean
+#if NeedFunctionPrototypes
+column_insert_after (XtPointer d, int node_size)
+#else
+column_insert_after(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode) d;
+ register XawTableNode p;
+ XawTableNode top;
+
+ if (f == null)
+ return False;
+
+ /* go top till column edge */
+ for(; f->t != null; f=f->t )
+ /*EMPTY*/;
+
+ /* save very top node */
+ top = f;
+
+ /* go down and attach new cells via horizontal ponters */
+ for(; f->b != null; f=f->b){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->r);
+ FREE(top->r);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f, f->r, p);
+ }
+
+ /* attach horizontally very down cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->r);
+ FREE(top->r);
+ }
+ return False;
+ }
+
+ horiz_tab_node_insert(f, f->r, p);
+
+ /* if only one row */
+ if ( f->t == null ) {
+ f->r->t = f->r->b = null;
+ return True;
+ }
+
+ /* attach vertically very down cell */
+ vert_tab_node_insert(f->t->r,null,f->r);
+
+ /* bind via vertical ponters */
+ for(f=f->t; f->t != null; f=f->t )
+ vert_tab_node_insert(f->t->r,f->b->r,f->r);
+
+ /* attach vertically very top cell */
+ vert_tab_node_insert(null,f->b->r,f->r);
+
+ return True;
+}
+
+/*
+** Function name : column_insert_before
+**
+** Description : the same as previous, but only to left from column
+** Input : pointer to node, size of node
+** Output : True if successful
+*/
+
+Boolean
+#if NeedFunctionPrototypes
+column_insert_before (XtPointer d, int node_size)
+#else
+column_insert_before(d, node_size)
+ XtPointer d;
+ int node_size;
+#endif
+{
+ register XawTableNode f = (XawTableNode)d;
+ register XawTableNode p;
+ XawTableNode top;
+
+ if (f == null)
+ return False;
+
+ /* go top till column top */
+ for(; f->t != null; f=f->t )
+ /*EMPTY*/;
+
+ /* save very top node */
+ top = f;
+
+ /* go down and attach new cells via horizontal ponters */
+ for(; f->b != null; f=f->b){
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->l);
+ FREE(top->l);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f->l, f, p);
+ }
+
+ /* attach horizontally very down cell */
+ if( (p = (XawTableNode) XtMalloc (node_size)) == null){
+ for(; top != f; top = top->b){
+ horiz_tab_node_reject(top->l);
+ FREE(top->l);
+ }
+ return False;
+ }
+ horiz_tab_node_insert(f->l, f, p);
+
+ /* if only one row */
+ if ( f->t == null ) {
+ f->l->t = f->l->b = null;
+ return True;
+ }
+
+ /* attach vertically very down cell */
+ vert_tab_node_insert(f->t->l, null, f->l);
+
+ /* bind via vertical ponters */
+ for(f=f->t; f->t != null; f=f->t )
+ vert_tab_node_insert(f->t->l, f->b->l, f->l);
+
+ /* attach vertically very top cell */
+ vert_tab_node_insert(null, f->b->l, f->l);
+
+ return True;
+}
+
+/*
+** Function name : get_table
+**
+** Description : spot the node (0,0) in the table
+** Input : pointer to any node in table
+** Output : pointer to the node (0,0)
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+get_table (XtPointer f)
+#else
+get_table(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return (XtPointer)NULL;
+
+ for(; p->t != null; p=p->t)
+ /*EMPTY*/;
+
+ for(; p->l != null; p=p->l)
+ /*EMPTY*/;
+
+ return (XtPointer)p;
+}
+
+/*
+** Function name : get_cell
+**
+** Description : spot the node (i,j) regarding to given node
+** Input : pointer to the node, column, row (may be negative)
+** Output : pointer to the node or NULL
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+get_cell (XtPointer f, register int i, register int j)
+#else
+get_cell (f, i, j)
+ XtPointer f;
+ register int i;
+ register int j;
+#endif
+{
+ register XawTableNode p = (XawTableNode) f;
+
+ if (p == null)
+ return (XtPointer)NULL;
+
+ if (i > 0) {
+ for(; i>0; i--)
+ if (p != null) p = p->b;
+ else return (XtPointer)NULL;
+ } else {
+ for(; i<0; i++)
+ if (p != null) p = p->t;
+ else return (XtPointer)NULL;
+ }
+
+ if (j > 0) {
+ for(; j>0; j--)
+ if (p != null) p = p->r;
+ else return (XtPointer)NULL;
+ } else {
+ for(; j<0; j++)
+ if (p != null) p = p->l;
+ else return (XtPointer)NULL;
+ }
+
+ return (XtPointer)p;
+}
+
+#if 0
+static Boolean go_row(w, proc, p, begin_column, end_column, i, j, client_data)
+ XtPointer w;
+ XawTableProc proc;
+ XawTableNode p; /* p == get_cell(table, ... , begin_column) */
+ int begin_column;
+ int end_column;
+ int *i; /* returned */
+ int *j; /* returned */
+ XtPointer client_data;
+{
+ for ((*j) = begin_column; ((*j) <= end_column) && (p != null); (*j)++)
+ {
+ XawTableProc sp = p;
+ p = p->r;
+
+ if (proc(w, *i, *j, (XtPointer)sp, client_data))
+ return True;
+ }
+
+ return False;
+}
+#endif
+
+/*
+** Function name : go_table
+**
+** Description : invoke given rutine for every node in given region
+** Input : rutine, begin/end rows, begin/end columns...
+** Output : True if given rutine returned True for a node,
+** numbers of row and column for that node
+ */
+
+Boolean
+#if NeedFunctionPrototypes
+go_table (
+ XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *i, /* returned */
+ register int *j, /* returned */
+ XtPointer client_data)
+#else
+go_table(w, proc, table, begin_row, end_row, begin_column, end_column,
+ direction, i, j, client_data)
+ XtPointer w;
+ XawTableProc proc;
+ XtPointer table;
+ int begin_row;
+ int end_row;
+ int begin_column;
+ int end_column;
+ int direction;
+ register int *i; /* returned */
+ register int *j; /* returned */
+ XtPointer client_data;
+#endif
+{
+ register XawTableNode p;
+ register XawTableNode n;
+
+ table = get_table(table);
+
+ switch (direction) {
+ case XawTABLE_DOWN_RIGHT :
+ p = (XawTableNode)get_cell(table, begin_row, begin_column);
+
+ for (*j = begin_column; *j <= end_column && p != null; (*j)++)
+ {
+ register XawTableNode sp = p; /* protect against deallocated node !! */
+ p = p->r;
+
+ for (*i = begin_row, n = sp; *i <= end_row && n != null; (*i)++)
+ {
+ register XawTableNode sn = n; /* protect against deallocated node !! */
+ n = n->b;
+
+ if (proc(w, *i, *j, (XtPointer)sn, client_data))
+ return True;
+ }
+ }
+ break;
+ case XawTABLE_RIGHT_DOWN :
+ default :
+ p = (XawTableNode)get_cell(table, begin_row, begin_column);
+
+ for (*i = begin_row; *i <= end_row && p != null; (*i)++)
+ {
+ register XawTableNode sp = p; /* protect against deallocated node !! */
+ p = p->b;
+
+ for (*j = begin_column, n = sp; *j <= end_column && n != null; (*j)++)
+ {
+ register XawTableNode sn = n; /* protect against deallocated node !! */
+ n = n->r;
+
+ if (proc(w, *i, *j, (XtPointer)sn, client_data))
+ return True;
+ }
+ }
+ break;
+ }
+ return False;
+}
+
+/*
+** Function name : get_table_size
+**
+** Description : define dimention on the table
+** Input : pointer to any node in the table
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+get_table_size (XtPointer f,
+ register int *i, /* returned */
+ register int *j) /* returned */
+#else
+get_table_size(f,i,j)
+ XtPointer f;
+ register int *i; /* returned */
+ register int *j; /* returned */
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ if (p == null){
+ *i = 0;
+ *j = 0;
+ }
+
+ p = (XawTableNode)get_table(f);
+
+ for (*i = 1; p->b != null; p = p->b, (*i)++)
+ /*EMPTY*/;
+
+ for (*j = 1; p->r != null; p = p->r, (*j)++)
+ /*EMPTY*/;
+}
+
+/*
+** Function name : delete_table
+**
+** Description : destroy table
+** Input : pointer to any node in the table
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+delete_table (XtPointer f)
+#else
+delete_table(f)
+ XtPointer f;
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ int i,j;
+ int end_row, end_column;
+
+ if (p == null)
+ return;
+
+ p = (XawTableNode)get_table(f);
+ get_table_size((XtPointer)p, (int*)&end_row, (int*)&end_column);
+ (void)go_table(NULL, (XawTableProc)del_cell, (XtPointer)p,
+ 0, (int)(end_row-1), 0, (int)(end_column-1),
+ XawTABLE_RIGHT_DOWN,
+ (int*)&i, (int*)&j, NULL);
+}
+
+/*
+** Function name : get_cell_positions
+**
+** Description : define number of row & column for node
+** Input : pointer to the node
+** Output : void
+*/
+
+void
+#if NeedFunctionPrototypes
+get_cell_positions (XtPointer f,
+ register int *i, /* returned */
+ register int *j) /* returned */
+#else
+get_cell_positions(f, i, j)
+ XtPointer f;
+ register int *i; /* returned */
+ register int *j; /* returned */
+#endif
+{
+ register XawTableNode p = (XawTableNode)f;
+ if ( p == null )
+ return;
+
+ if ( i != (int*)NULL ) {
+ for (*i = 0; p->t != null; p = p->t, (*i)++)
+ /*EMPTY*/;
+ }
+
+ if ( j != (int*)NULL ) {
+ for (*j = 0; p->l != null; p = p->l, (*j)++)
+ /*EMPTY*/;
+ }
+}
+
+/*
+** Function name : create_table
+**
+** Description : create the table
+** Input : row & column dimestions, size of node
+** Output : pointer to the node (0,0)
+*/
+
+XtPointer
+#if NeedFunctionPrototypes
+create_table ( int rows, int columns, int node_size)
+#else
+create_table(rows, columns, node_size)
+ int rows;
+ int columns;
+ int node_size;
+#endif
+{
+ register XawTableNode *area;
+ register XawTableNode p;
+ register int i,j;
+ XawTableNode table;
+
+ if (rows == 0 || columns == 0)
+ return (XtPointer)NULL;
+ else{
+ register XawTableNode *s;
+
+ /* allocate temporary two-dimension array to make first node's binding */
+ if ( (s = area = (XawTableNode*)
+ XtCalloc ((unsigned)(rows * columns), sizeof(XawTableNode))) == NULL)
+ return (XtPointer)NULL;
+
+ /* allocate nodes */
+ for (i = 0, j = rows*columns; i < j; i++)
+ if((*s++ = (XawTableNode) XtMalloc (node_size)) == NULL){
+ int h;
+ for (h = 0, s = area; h < i; h++)
+ XtFree((char*)*s++);
+
+ XtFree((char*)area);
+ return (XtPointer)NULL;
+ }
+ }
+
+#define a(i,j) (XawTableNode)*(area + (i)*columns + (j))
+
+ /* initialize the boundary nodes */
+ for (i = 0; i < rows; i++) {
+ p = a(i,0); p->l = null;
+ p = a(i,columns-1); p->r = null;
+ }
+ for (j = 0; j < columns; j++) {
+ p = a(0,j); p->t = null;
+ p = a(rows-1,j); p->b = null;
+ }
+
+#undef a
+#define a(i,j) (( (i)>=0 && (i)<rows ) && ( (j)>=0 && (j)<columns ) ? \
+ (XawTableNode)*(area + (i)*columns + (j)) : null)
+
+ /* make internode's binding */
+ for (i = 0; i < rows; i++) {
+ for (j = i % 2; j < columns; j += 2) {
+ horiz_tab_node_insert(a(i,j-1), a(i,j+1), a(i,j));
+ vert_tab_node_insert (a(i-1,j), a(i+1,j), a(i,j));
+ }
+ }
+
+#undef a
+
+ table = *area;
+ XtFree((char*)area);
+ return (XtPointer)table;
+}
+
+
+#ifdef EBUG_XRAW_MALLOC
+/* ARGSUSED */
+static Boolean check_cell (w, row, column, call_data, client_data)
+ XtPointer w; /* unused */
+ int row;
+ int column;
+ XtPointer call_data;
+ XtPointer client_data;
+{
+ register XawTableNode p = (XawTableNode)call_data;
+ int real_row, real_column;
+ char *halt = NULL;;
+
+ get_cell_positions(p, &real_row, &real_column);
+
+ if (real_row != row){
+ XtWarning("check_table: wrong initial table row size");
+ *halt = '\0';
+ }
+
+ if (real_column != column){
+ XtWarning("check_table: wrong initial table column size");
+ *halt = '\0';
+ }
+
+ if (p->l != null)
+ if (p->l->r != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->r != null)
+ if (p->r->l != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->t != null)
+ if (p->t->b != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+ if (p->b != null)
+ if (p->b->t != p) {
+ XtWarning("check_table: wrong cell");
+ *halt = '\0';
+ }
+
+ return False;
+}
+
+
+
+void
+#if NeedFunctionPrototypes
+_check_table (XtPointer f, int rows, int columns)
+#else
+_check_table (f, rows, columns)
+ XtPointer f;
+ int rows;
+ int columns;
+#endif
+{
+ register XawTableNode table = (XawTableNode)f;
+ int real_rows, real_columns;
+ register int i,j;
+ char *halt = NULL;
+
+ if (f == NULL && (rows == 0 || columns == 0))
+ return;
+
+ if (table != get_table(f)){
+ XtWarning("check_table: wrong initial table cell");
+ *halt = '\0';
+ }
+
+ get_table_size (f, &real_rows, &real_columns);
+
+ if (real_rows != rows){
+ XtWarning("check_table: wrong initial table row size");
+ *halt = '\0';
+ }
+
+ if (real_columns != columns){
+ XtWarning("check_table: wrong initial table column size");
+ *halt = '\0';
+ }
+
+
+ (void) go_table (NULL, check_cell, table,
+ 0, rows-1, 0, columns-1,
+ XawTABLE_RIGHT_DOWN,
+ &real_rows, &real_columns, (XtPointer)NULL);
+
+}
+#endif /* EBUG_XRAW_MALLOC */
+
+#undef null
+#undef FREE
+
diff --git a/vendor/x11iraf/obm/ObmW/zz/TableUtil.h b/vendor/x11iraf/obm/ObmW/zz/TableUtil.h
new file mode 100644
index 00000000..a8262f75
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/TableUtil.h
@@ -0,0 +1,94 @@
+/***********************************************************************
+
+ Table widget
+ Copyright by Vladimir T. Romanovski
+ All rights reserved.
+
+This library is designed for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advice, new components and patches of the existing programs.
+Commercial usage is also possible with participation of the author.
+
+ romsky@hp1.oea.ihep.su (Russia)
+ romsky@munin.ucsf.edu (USA)
+
+*************************************************************************/
+
+#ifndef _table_h_
+#define _table_h_
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xraw/Table.h>
+
+#if __STDC__ || defined(__cplusplus)
+#define F_PROTO(s) s
+#else
+#define F_PROTO(s) ()
+#endif
+
+typedef struct _XawTableNodeRec { /* Node of table grid */
+ struct _XawTableNodeRec *l;
+ struct _XawTableNodeRec *r;
+ struct _XawTableNodeRec *t;
+ struct _XawTableNodeRec *b;
+}XawTableNodeRec, *XawTableNode;
+
+
+extern XtPointer create_table F_PROTO((int rows,
+ int columns,
+ int node_size));
+
+extern Boolean row_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean row_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern Boolean column_insert_after F_PROTO((XtPointer d,
+ int node_size));
+
+extern Boolean column_insert_before F_PROTO((XtPointer f,
+ int node_size));
+
+extern XtPointer get_table F_PROTO((XtPointer f));
+
+extern XtPointer get_cell F_PROTO((XtPointer p,
+ int i,
+ int j));
+
+extern void get_table_size F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void get_cell_positions F_PROTO((XtPointer p,
+ int *i,
+ int *j));
+
+extern void row_delete F_PROTO((XtPointer p));
+
+extern void column_delete F_PROTO((XtPointer p));
+
+extern void delete_table F_PROTO((XtPointer p));
+
+extern Boolean go_table F_PROTO((XtPointer w,
+ XawTableProc proc,
+ XtPointer table,
+ int begin_row,
+ int end_row,
+ int begin_column,
+ int end_column,
+ int direction,
+ register int *row,
+ register int *column,
+ XtPointer client_data));
+
+#ifdef EBUG_XRAW_MALLOC
+extern void _check_table F_PROTO((XtPointer table,
+ int rows,
+ int columns));
+#endif
+
+#undef F_PROTO
+
+#endif /* _table_h_ */
diff --git a/vendor/x11iraf/obm/ObmW/zz/XrawInit.h b/vendor/x11iraf/obm/ObmW/zz/XrawInit.h
new file mode 100644
index 00000000..cf6bcbc8
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/zz/XrawInit.h
@@ -0,0 +1,60 @@
+/* $XConsortium: XawInit.h,v 1.4 91/07/22 19:05:25 converse Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _XawInit_
+#define _XawInit_
+
+#if !(defined(__STDC__) && __STDC__) && !defined(__cplusplus) && !defined(c_plusplus) && !defined(FUNCPROTO) && !defined(XTFUNCPROTO) && !defined(XAWFUNCPROTO) && !(defined(NeedFunctionPrototypes) && NeedFunctionPrototypes)
+#define Xraw_NO_PROTO
+#else
+#define Xraw_NEED_PROTO
+#endif /* __STDC__ */
+
+
+#ifdef Xraw_NEED_PROTO
+#define Xraw_PROTO(args) args
+#else
+#define Xraw_PROTO(args) ()
+#endif
+
+#define Xraw_VERSION 1
+#define Xraw_REVISION 2
+
+#define Xraw_3d 1
+#define Xraw_SCROLLBAR 20
+#define Xraw_TABLE 40
+#define Xraw_SEPARATOR 60
+#define Xraw_FRAME 80
+
+#define streq(a,b) (XrmStringToQuark(a) == XrmStringToQuark(b))
+
+#define FULL_WIDTH(w) ((w)->core.width + ((w)->core.border_width << 1))
+#define FULL_HEIGHT(w) ((w)->core.height + ((w)->core.border_width << 1))
+#define WNULL (Widget)NULL
+
+/* called from ClassInit procs */
+extern void XawInitializeWidgetSet Xraw_PROTO((void));
+
+#if defined(XtSpecificationRelease) && XtSpecificationRelease < 5
+#define XPointer XtPointer
+#endif
+
+#endif /* _XawInit_ */
diff --git a/vendor/x11iraf/obm/README b/vendor/x11iraf/obm/README
new file mode 100644
index 00000000..e97a5880
--- /dev/null
+++ b/vendor/x11iraf/obm/README
@@ -0,0 +1,9 @@
+OBM -- Object Manager library. This library implements a window system
+toolkit as an interpreted window-object language, allowing application GUIs
+to be defined and executed at runtime without compiling any code, and with
+minimal dependence upon the underlying window system toolkit library.
+The object manager is used in X11 client applications such as the IRAF widget
+server, which is basically just the object manager packaged as a server that
+remote client applications can connect to to download and execute a GUI.
+
+See obm.c for an overview of the library.
diff --git a/vendor/x11iraf/obm/Tcl/Imakefile b/vendor/x11iraf/obm/Tcl/Imakefile
new file mode 100644
index 00000000..dca178ec
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/Imakefile
@@ -0,0 +1,224 @@
+XCOMM Imakefile for maintaining Tcl in the Object Manager library.
+XCOMM 05-Sep-93, Doug Tody NOAO/IRAF.
+XCOMM 28-Aug-96, Mike Fitzpatrick NOAO/IRAF. (Revised)
+
+X11IRAFDIR = ../../
+#include <../../X11IRAF.tmpl>
+
+XCOMM ------------------ BEGIN TCL DEFINITIONS ----------------------
+
+ TCL_LIBRARY = /usr/local/lib/tcl
+ SRC_DIR = .
+
+
+#if defined(MacIIArchitecture)
+XCOMM - The following are for Macintosh A/UX
+ GCC_FLAGS = -w -Wunused -traditional
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_STDLIB_H=1 -DNO_STRING_H=1 \
+ -DNEED_MATHERR=1
+ COMPAT_OBJS = strerror.o strtoul.o tclMtherr.o
+#else
+
+#if defined(PpcDarwinArchitecture) || defined (TenonServer)
+XCOMM - The following are for OS X on a PowerPC
+#if ((OSMajorVersion == 10) && (OSMinorVersion < 4))
+ CPP_FLAGS = -traditional-cpp
+#else
+ CPP_FLAGS =
+#endif
+ GCC_FLAGS = -DNOSTDHDRS -DSYSV -DANSI -D_BSD_SOURCE -W \
+ $(CPP_FLAGS) -fstrength-reduce -fpcc-struct-return
+ AC_FLAGS = $(CPP_FLAGS) -DHAVE_UNISTD_H=1
+ CFLAGS += $(CPP_FLAGS) -I. $(AC_FLAGS) $(GCC_FLAGS)
+ COMPAT_OBJS =
+#else
+
+#if defined(SunArchitecture) && (OSMajorVersion <= 4)
+XCOMM - The following are for SunOS
+ GCC_FLAGS =
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_FLOAT_H=1 -DNO_STDLIB_H=1 \
+ -DNO_STRING_H=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = strerror.o strtoul.o tclMtherr.o
+#else
+
+#if defined(SunArchitecture) && !defined (i386Architecture)
+XCOMM - The following are for SunSoft/Solaris
+# Hack to compile under SunPRO V4 on Solaris
+ CCOPTIONS = -Xs
+ EXTRA_LDOPTIONS = -xildoff
+ GCC_FLAGS =
+ AC_FLAGS = -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 \
+ -DNO_UNION_WAIT=1 -DNEED_MATHERR=1 -DUSE_STDARG
+ COMPAT_OBJS = tclMtherr.o
+#else
+
+#if defined(SunArchitecture) && defined (i386Architecture)
+XCOMM - The following are for Solaris x86
+ CCOPTIONS =
+ EXTRA_LDOPTIONS =
+ GCC_FLAGS =
+ AC_FLAGS = -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 \
+ -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+#else
+
+#if defined(FreeBSDArchitecture)
+XCOMM - The following are for FreeBSD
+ GCC_FLAGS = -DNOSTDHDRS -DSYSV -DANSI -D_BSD_SOURCE -W \
+ -fstrength-reduce -fpcc-struct-return
+ AC_FLAGS = -DHAVE_UNISTD_H=1
+ CFLAGS += -I. $(AC_FLAGS) $(GCC_FLAGS)
+ COMPAT_OBJS =
+#else
+
+#if defined(LinuxArchitecture)
+XCOMM - The following are for Linux
+ GCC_FLAGS = -DNOSTDHDRS -DSYSV -DANSI -D_BSD_SOURCE -W \
+ -fstrength-reduce -fpcc-struct-return
+ AC_FLAGS = -DHAVE_UNISTD_H=1
+ COMPAT_OBJS =
+#else
+
+#if defined(HPArchitecture)
+XCOMM - The following are for HP-UX
+ GCC_FLAGS =
+ AC_FLAGS = -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 \
+ -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+#else
+
+#if defined(OSF1Architecture)
+XCOMM - The following are for OSF/1 on Alpha
+ GCC_FLAGS =
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+
+#else
+
+#if defined(RsArchitecture)
+XCOMM - The following are for AIX on Rs/6000
+ GCC_FLAGS =
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+
+#else
+#if defined(cygwinArchitecture)
+
+ GCC_FLAGS = -DUSE_STDARG
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_UNION_WAIT=1 -DNO_STDLIB_H=1
+ COMPAT_OBJS =
+#else
+
+ GCC_FLAGS =
+ AC_FLAGS =
+ COMPAT_OBJS =
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+
+# Platform flags.
+#if ((GccMajorVersion == 3) && (GccMinorVersion >= 1))
+ PL_FLAGS = -DUSE_STDARG
+#else
+#if ((GccMajorVersion == 4))
+ PL_FLAGS = -DUSE_STDARG
+ CPP_FLAGS = -traditional-cpp
+#else
+ PL_FLAGS =
+#endif
+#endif
+
+
+ DEPENDFLAGS = -I.. -I${SRC_DIR} ${AC_FLAGS} ${PL_FLAGS}
+ CCOPTIONS = -I.. -I${SRC_DIR} ${AC_FLAGS} ${PL_FLAGS} ${GCC_FLAGS} \
+ -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
+
+UNIX_OBJS = \
+ panic.o tclEnv.o tclGlob.o tclMain.o tclUnixAZ.o \
+ tclUnixStr.o tclUnixUtil.o
+
+GENERIC_OBJS = \
+ regexp.o tclAsync.o tclBasic.o tclCkalloc.o \
+ tclCmdAH.o tclCmdIL.o tclCmdMZ.o tclExpr.o tclGet.o \
+ tclHash.o tclHistory.o tclLink.o tclParse.o tclProc.o \
+ tclUtil.o tclVar.o
+
+TCL_OBJS = ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS}
+
+XCOMM -------------------- END TCL DEFINITIONS ----------------------
+
+
+HEADERS = patchlevel.h tclRegexp.h tcl.h tclInt.h tclUnix.h
+
+SRCS = panic.c regexp.c tclAppInit.c tclAsync.c tclBasic.c \
+ tclCkalloc.c tclCmdAH.c tclCmdIL.c tclCmdMZ.c tclEnv.c \
+ tclExpr.c tclGet.c tclGlob.c tclHash.c tclHistory.c \
+ tclLink.c tclMain.c tclMtherr.c tclParse.c tclProc.c \
+ tclTest.c tclUnixAZ.c tclUnixStr.c tclUnixUtil.c tclUtil.c \
+ tclVar.c
+
+OBJS = ${TCL_OBJS}
+
+SubdirLibraryRule($(OBJS))
+
+XCOMM ------------------ BEGIN TCL DEFINITIONS ----------------------
+getcwd.o: $(SRC_DIR)/compat/getcwd.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/getcwd.c
+
+opendir.o: $(SRC_DIR)/compat/opendir.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/opendir.c
+
+strerror.o: $(SRC_DIR)/compat/strerror.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strerror.c
+
+strstr.o: $(SRC_DIR)/compat/strstr.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strstr.c
+
+strtod.o: $(SRC_DIR)/compat/strtod.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtod.c
+
+strtol.o: $(SRC_DIR)/compat/strtol.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtol.c
+
+strtoul.o: $(SRC_DIR)/compat/strtoul.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtoul.c
+
+tmpnam.o: $(SRC_DIR)/compat/tmpnam.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/tmpnam.c
+
+waitpid.o: $(SRC_DIR)/compat/waitpid.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/waitpid.c
+XCOMM -------------------- END TCL DEFINITIONS ----------------------
+
+
+NormalLintTarget($(SRCS))
+LintLibraryTarget(ar,$(SRCS))
+
+includes::
+ MakeDir(X11irafIncDir/Tcl)
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/Tcl/$$i; \
+ $(CP) -p ObmDir/Tcl/$$i X11irafIncDir/Tcl/$$i; \
+ done)
+
+#if InstallIncludes
+install::
+ @(set -x; for i in $(HEADERS); do \
+ $(RM) X11irafIncDir/Tcl/$$i; \
+ done)
+ for i in $(HEADERS); do \
+ (set -x; $(CP) -p $$i X11irafIncDir/Tcl/); \
+ done
+#endif
+
+DependTarget()
+
diff --git a/vendor/x11iraf/obm/Tcl/Imakefile.ORIG b/vendor/x11iraf/obm/Tcl/Imakefile.ORIG
new file mode 100644
index 00000000..83444b6d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/Imakefile.ORIG
@@ -0,0 +1,163 @@
+XCOMM Imakefile for maintaining Tcl in the Object Manager library.
+XCOMM 05-Sep-93, Doug Tody NOAO/IRAF.
+
+#include <Library.tmpl>
+
+XCOMM ------------------ BEGIN TCL DEFINITIONS ----------------------
+ exec_prefix = /usr/local
+ prefix = /usr/local
+
+ TCL_LIBRARY = $(prefix)/lib/tcl
+ LIB_DIR = $(exec_prefix)/lib
+ BIN_DIR = $(exec_prefix)/bin
+ SRC_DIR = .
+ INCLUDE_DIR = $(prefix)/include
+
+#if defined(MacIIArchitecture)
+XCOMM - The following are for Macintosh A/UX
+ GCC_FLAGS = -w -Wunused -traditional
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_STDLIB_H=1 -DNO_STRING_H=1 \
+ -DNEED_MATHERR=1
+ COMPAT_OBJS = strerror.o strtoul.o tclMtherr.o
+
+#else
+#if defined(SunArchitecture) && (OSMajorVersion <= 4)
+XCOMM - The following are for SunOS
+ GCC_FLAGS =
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_FLOAT_H=1 -DNO_STDLIB_H=1 \
+ -DNO_STRING_H=1 -DNEED_MATHERR=1
+
+ COMPAT_OBJS = \
+ strerror.o strtoul.o tclMtherr.o
+
+#else
+#if defined(SunArchitecture)
+XCOMM - The following are for SunSoft/Solaris
+ GCC_FLAGS =
+ AC_FLAGS = -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 \
+ -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+
+#else
+#if defined(LinuxArchitecture)
+ GCC_FLAGS = -DNOSTDHDRS -DSYSV -DANSI -D_BSD_SOURCE -W \
+ -Wunused -Wcomment -fstrength-reduce -fpcc-struct-return
+ AC_FLAGS = -DHAVE_UNISTD_H=1
+ COMPAT_OBJS =
+
+#else
+#if defined(HPArchitecture)
+XCOMM - The following are for HP-UX
+ GCC_FLAGS =
+ AC_FLAGS = -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 \
+ -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+
+#else
+#if defined(OSF1)
+ GCC_FLAGS =
+ AC_FLAGS = -DHAVE_UNISTD_H=1 -DNO_UNION_WAIT=1 -DNEED_MATHERR=1
+ COMPAT_OBJS = tclMtherr.o
+#else
+ GCC_FLAGS =
+ AC_FLAGS =
+ COMPAT_OBJS =
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ DEPENDFLAGS = -I.. -I${SRC_DIR} ${AC_FLAGS}
+ CCOPTIONS = -I.. -I${SRC_DIR} ${AC_FLAGS} ${GCC_FLAGS} \
+ -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
+
+UNIX_OBJS = \
+ panic.o tclEnv.o tclGlob.o tclMain.o tclUnixAZ.o \
+ tclUnixStr.o tclUnixUtil.o
+
+GENERIC_OBJS = \
+ regexp.o tclAsync.o tclBasic.o tclCkalloc.o \
+ tclCmdAH.o tclCmdIL.o tclCmdMZ.o tclExpr.o tclGet.o \
+ tclHash.o tclHistory.o tclLink.o tclParse.o tclProc.o \
+ tclUtil.o tclVar.o
+
+TCL_OBJS = \
+ ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS}
+XCOMM -------------------- END TCL DEFINITIONS ----------------------
+
+HEADERS = \
+ patchlevel.h \
+ tclRegexp.h \
+ tcl.h \
+ tclInt.h \
+ tclUnix.h
+
+SRCS = \
+ panic.c \
+ regexp.c \
+ tclAppInit.c \
+ tclAsync.c \
+ tclBasic.c \
+ tclCkalloc.c \
+ tclCmdAH.c \
+ tclCmdIL.c \
+ tclCmdMZ.c \
+ tclEnv.c \
+ tclExpr.c \
+ tclGet.c \
+ tclGlob.c \
+ tclHash.c \
+ tclHistory.c \
+ tclLink.c \
+ tclMain.c \
+ tclMtherr.c \
+ tclParse.c \
+ tclProc.c \
+ tclTest.c \
+ tclUnixAZ.c \
+ tclUnixStr.c \
+ tclUnixUtil.c \
+ tclUtil.c \
+ tclVar.c
+
+OBJS = \
+ ${TCL_OBJS}
+
+SubdirLibraryRule($(OBJS))
+
+XCOMM ------------------ BEGIN TCL DEFINITIONS ----------------------
+getcwd.o: $(SRC_DIR)/compat/getcwd.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/getcwd.c
+
+opendir.o: $(SRC_DIR)/compat/opendir.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/opendir.c
+
+strerror.o: $(SRC_DIR)/compat/strerror.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strerror.c
+
+strstr.o: $(SRC_DIR)/compat/strstr.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strstr.c
+
+strtod.o: $(SRC_DIR)/compat/strtod.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtod.c
+
+strtol.o: $(SRC_DIR)/compat/strtol.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtol.c
+
+strtoul.o: $(SRC_DIR)/compat/strtoul.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtoul.c
+
+tmpnam.o: $(SRC_DIR)/compat/tmpnam.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/tmpnam.c
+
+waitpid.o: $(SRC_DIR)/compat/waitpid.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/waitpid.c
+XCOMM -------------------- END TCL DEFINITIONS ----------------------
+
+
+NormalLintTarget($(SRCS))
+LintLibraryTarget(ar,$(SRCS))
+
+DependTarget()
diff --git a/vendor/x11iraf/obm/Tcl/Makefile b/vendor/x11iraf/obm/Tcl/Makefile
new file mode 100644
index 00000000..4182d6a0
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/Makefile
@@ -0,0 +1,1136 @@
+# Makefile generated by imake - do not edit!
+# $Xorg: imake.c,v 1.6 2001/02/09 02:03:15 xorgcvs Exp $
+
+# ----------------------------------------------------------------------
+# Makefile generated from "Imake.tmpl" and </tmp/IIf.t1R7HV>
+# $Xorg: Imake.tmpl,v 1.4 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# $XFree86: xc/config/cf/Imake.tmpl,v 3.138 2002/12/10 03:20:41 dawes Exp $
+# ----------------------------------------------------------------------
+
+all::
+
+.SUFFIXES: .i
+
+# $Xorg: Imake.cf,v 1.4 2000/08/17 19:41:45 cpqbld Exp $
+
+# $XFree86: xc/config/cf/Imake.cf,v 3.80 2003/01/15 02:52:12 dawes Exp $
+
+# Keep cpp from replacing path elements containing i486/i586/i686
+
+# -----------------------------------------------------------------------
+# site-specific configuration parameters that need to come before
+# the platform-specific parameters - edit site.def to change
+
+# site: $TOG: site.sample /main/r64_final/1 1998/02/05 16:28:49 kaleb $
+
+# site: $XFree86: xc/config/cf/site.def,v 3.24 2000/06/25 20:17:29 dawes Exp $
+
+# $XFree86: xc/config/cf/xf86site.def,v 3.181 2002/02/22 21:32:33 dawes Exp $
+
+# ----------------------------------------------------------------------
+# platform-specific configuration parameters - edit linux.cf to change
+
+# platform: $Xorg: linux.cf,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+
+# platform: $XFree86: xc/config/cf/linux.cf,v 3.201tsi Exp $
+
+# operating system: Linux 2.4.29-4aslsmp i686 [ELF] (2.4.29)
+# libc: (6.3.2)
+# binutils: (213)
+
+# $Xorg: lnxLib.rules,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+# $XFree86: xc/config/cf/lnxLib.rules,v 3.43 2002/04/04 14:05:33 eich Exp $
+
+# $XFree86: xc/config/cf/xfree86.cf,v 3.439.2.1 2003/03/13 04:10:40 tsi Exp $
+
+# $Xorg: xfree86.cf,v 1.4 2000/08/17 19:41:49 cpqbld Exp $
+
+VENDORMANNAME = XFree86
+VENDORMANVERSION = `echo 4 3 0 | sed -e 's/ /./g' -e 's/^/Version\\\ /'`
+
+AFB_DEFS = -DUSE_AFB
+
+DRIVERSDKDIR = $(USRLIBDIR)/Server
+DRIVERSDKMODULEDIR = $(USRLIBDIR)/Server/modules
+DRIVERSDKINCLUDEDIR = $(USRLIBDIR)/Server/include
+
+ XF86SRC = $(SERVERSRC)/hw/xfree86
+ XF86COMSRC = $(XF86SRC)/common
+ XF86PARSERSRC = $(XF86SRC)/parser
+ XF86OSSRC = $(XF86SRC)/os-support
+ XF86DRIVERSRC = $(XF86SRC)/drivers
+ DRIVERSRC = $(XF86DRIVERSRC)
+
+ XFREE86DOCDIR = $(DOCDIR)
+ XFREE86PSDOCDIR = $(DOCPSDIR)
+ XFREE86HTMLDOCDIR = $(DOCHTMLDIR)
+XFREE86JAPANESEDOCDIR = $(DOCDIR)/Japanese
+
+# $Xorg: xf86.rules,v 1.3 2000/08/17 19:41:48 cpqbld Exp $
+
+# $XFree86: xc/config/cf/xf86.rules,v 3.33 2001/01/17 16:38:51 dawes Exp $
+
+# ----------------------------------------------------------------------
+# site-specific configuration parameters that go after
+# the platform-specific parameters - edit site.def to change
+
+# site: $TOG: site.sample /main/r64_final/1 1998/02/05 16:28:49 kaleb $
+
+# site: $XFree86: xc/config/cf/site.def,v 3.24 2000/06/25 20:17:29 dawes Exp $
+
+# ---------------------------------------------------------------------
+# Imake rules for building libraries, programs, scripts, and data files
+# rules: $Xorg: Imake.rules,v 1.3 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# rules: $XFree86: xc/config/cf/Imake.rules,v 3.112 2002/11/14 21:01:13 tsi Exp $
+
+ _NULLCMD_ = @ echo -n
+
+GLIDE2INCDIR = /usr/include/glide
+
+GLIDE3INCDIR = /usr/include/glide3
+
+GLIDE3LIBNAME = glide3
+
+TKLIBNAME =
+
+TKLIBDIR =
+
+TCLLIBNAME =
+
+TCLIBDIR =
+
+ PATHSEP = /
+ SHELL = /bin/sh -e
+
+ TOP = ../..
+ CURRENT_DIR = obm/Tcl
+
+ IMAKE = imake
+ DEPEND = gccmakedep
+ MKDIRHIER = mkdir -p
+ REVPATH = revpath
+ EXPORTLISTGEN =
+ RMAN = rman
+ RMANBASENAME = rman
+ RMANOPTIONS = -f HTML
+ CONFIGSRC = $(TOP)/config
+ IMAKESRC = $(CONFIGSRC)/imake
+ DEPENDSRC = $(CONFIGSRC)/util
+
+ INCROOT = /usr/X11R6/include
+ USRLIBDIR = /usr/X11R6/lib
+ VARDIR = /var
+ VARLIBDIR = $(VARDIR)/lib
+ SYSTEMUSRLIBDIR = /usr/lib
+ SYSTEMUSRINCDIR = /usr/include
+ SHLIBDIR = /usr/X11R6/lib
+ LINTLIBDIR = $(USRLIBDIR)/lint
+ MANPATH = /usr/X11R6/man
+ MANSOURCEPATH = $(MANPATH)/man
+ MANDIR = $(MANSOURCEPATH)1
+ LIBMANDIR = $(MANSOURCEPATH)3
+ FILEMANDIR = $(MANSOURCEPATH)5
+ MISCMANDIR = $(MANSOURCEPATH)7
+ DRIVERMANDIR = $(MANSOURCEPATH)4
+ ICONDIR = /usr/share/icons
+ XCURSORPATH = "~/.icons:/usr/share/icons:/usr/share/pixmaps"
+ LOGDIRECTORY = $(VARDIR)/log
+
+ VARRUNDIR = $(VARDIR)/run
+
+ VARDBDIR = $(VARDIR)/lib
+
+ AR = ar clq
+
+# Nice try but useless: make will inherit BOOTSTRAPCFLAGS
+# from top Makefile
+ BOOTSTRAPCFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -pipe
+
+ CC = gcc -m32
+ AS = gcc -m32 -c -x assembler
+
+.SUFFIXES: .cc
+
+ CXX = c++ -m32
+
+ CXXFILT = c++filt
+ CXXLIB =
+ CXXDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+CXXDEPENDINCLUDES =
+ CXXEXTRA_DEFINES =
+CXXEXTRA_INCLUDES =
+ CXXSTD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(CXXPROJECT_DEFINES)
+ CXXOPTIONS =
+ CXXINCLUDES = $(INCLUDES) $(TOP_INCLUDES) $(CXXEXTRA_INCLUDES)
+ CXXDEFINES = $(CXXINCLUDES) $(CXXSTD_DEFINES) $(THREADS_CXXDEFINES) $(DEFINES) $(CXXEXTRA_DEFINES)
+ CXXFLAGS = $(CXXDEBUGFLAGS) $(CXXOPTIONS) $(THREADS_CXXFLAGS) $(CXXDEFINES)
+
+ COMPRESS = compress
+ GZIPCMD = gzip
+
+ CPP = /usr/bin/cpp $(STD_CPP_DEFINES)
+ RAWCPP = /usr/bin/cpp -undef $(STD_CPP_OPTIONS)
+ PREPROCESSCMD = gcc -m32 -E $(STD_CPP_DEFINES)
+
+ INSTALL = install
+ INSTALLFLAGS = -c
+
+ LD = gcc -m32 -nostdlib
+
+ LEX = flex -l
+ M4 = m4
+ M4FLAGS =
+ LEXLIB = -lfl
+ YACC = bison -y
+ CCYACC = bison -y
+
+ LINT = lint
+
+ LINTLIBFLAG = -C
+ LINTOPTS = -axz
+ LN = ln -s
+ MAKE = make
+ MV = mv -f
+ CP = cp
+
+ RANLIB = ranlib
+
+ RANLIBINSTFLAGS =
+
+ RM = rm -f
+ PERL = perl
+ PERLOPTS =
+ MANSUFFIX = 1x
+ LIBMANSUFFIX = 3x
+ FILEMANSUFFIX = 5x
+ MISCMANSUFFIX = 7x
+ DRIVERMANSUFFIX = 4x
+ MANSRCSUFFIX = man
+ MANNEWSUFFIX = _man
+ MANDEFS = -D__apploaddir__=$(XAPPLOADDIR) -D__filemansuffix__=$(FILEMANSUFFIX) -D__libmansuffix__=$(LIBMANSUFFIX) -D__miscmansuffix__=$(MISCMANSUFFIX) -D__drivermansuffix__=$(DRIVERMANSUFFIX) -D__projectroot__=$(PROJECTROOT) $(XORGMANDEFS) $(VENDORMANDEFS)
+
+ COMPRESSMANCMD = gzip -n
+
+ TROFF = groff -Tps
+ NROFF = nroff
+ MSMACROS = -ms
+ MANMACROS = -man
+ TBL = tbl
+ EQN = eqn
+ NEQN = neqn
+ COL = col
+ COLFLAGS = -b
+
+ MODCC = gcc -m32
+
+ MODCPP = /usr/bin/cpp
+ MODCFLAGS = $(CFLAGS)
+ MODAS = gcc -m32 -c -x assembler
+ MODASFLAGS =
+
+ MODLD = gcc -m32 -nostdlib
+
+ MODLDFLAGS =
+MODLDCOMBINEFLAGS = -r
+ MODAR = ar clq
+
+ MODRANLIB = ranlib
+
+ STD_INCLUDES =
+ STD_CPP_OPTIONS = -traditional
+ STD_CPP_DEFINES = -traditional -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+ STD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+ EXTRA_LOAD_FLAGS =
+ EXTRA_LDOPTIONS =
+ EXTRA_LIBRARIES =
+ TAGS = ctags
+
+ PARALLELMFLAGS =
+
+ SHAREDCODEDEF =
+ SHLIBDEF =
+
+ SHLIBLDFLAGS = -shared $(SHLIBGLOBALSFLAGS)
+
+ PICFLAGS = -fPIC
+
+ CXXPICFLAGS = -fPIC
+
+ PROTO_DEFINES = -DFUNCPROTO=15 -DNARROWPROTO
+
+ INSTPGMFLAGS =
+
+ INSTBINFLAGS = -m 0755
+ INSTUIDFLAGS = -m 4711
+ INSTLIBFLAGS = -m 0644
+ INSTINCFLAGS = -m 0444
+ INSTMANFLAGS = -m 0444
+ INSTDATFLAGS = -m 0444
+ INSTKMEMFLAGS = -m 4711
+
+ PROJECTROOT = /usr/X11R6
+
+ CDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+ CCOPTIONS =
+
+ ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(INSTALLED_INCLUDES) $(STD_INCLUDES)
+ ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(THREADS_DEFINES) $(MODULE_DEFINES) $(DEFINES) $(EXTRA_DEFINES)
+ CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(THREADS_CFLAGS) $(MODULE_CFLAGS) $(ALLDEFINES)
+ LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) $(DEPEND_DEFINES)
+ LDPRELIB = -L$(USRLIBDIR) $(INSTALLED_LIBS)
+ LDPOSTLIB =
+ LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_LDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIBS)
+ CXXLDOPTIONS = $(CXXDEBUGFLAGS) $(CXXOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_CXXLDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIBS)
+
+ LDLIBS = $(LDPOSTLIBS) $(THREADS_LIBS) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
+
+ CCLINK = $(CC)
+
+ CXXLINK = $(CXX)
+
+ LDSTRIPFLAGS = -x
+ LDCOMBINEFLAGS = -r
+ DEPENDFLAGS =
+ DEPEND_DEFINES =
+
+# Not sure this belongs here
+ TKLIBDIR =
+ TKINCDIR =
+ TKLIBNAME =
+ TKLIBRARY = -L$(TKLIBDIR) -l$(TKLIBNAME)
+ TCLLIBDIR =
+ TCLINCDIR =
+ TCLLIBNAME =
+ TCLLIBRARY = -L$(TCLLIBDIR) -l$(TCLLIBNAME)
+
+ MACROFILE = linux.cf
+ RM_CMD = $(RM)
+
+ IMAKE_DEFINES =
+ IMAKE_WARNINGS = -Wundef
+
+ IRULESRC = $(CONFIGDIR)
+ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) $(IMAKE_WARNINGS)
+
+ ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/X11.tmpl $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) $(IRULESRC)/xfree86.cf $(IRULESRC)/xf86.rules $(IRULESRC)/xf86site.def $(IRULESRC)/host.def $(EXTRA_ICONFIGFILES)
+
+# $Xorg: X11.rules,v 1.4 2000/08/17 19:41:46 cpqbld Exp $
+
+# $XFree86: xc/config/cf/X11.rules,v 1.5 2000/11/06 19:24:00 dawes Exp $
+
+# ----------------------------------------------------------------------
+# X Window System Build Parameters and Rules
+# $Xorg: X11.tmpl,v 1.6 2000/08/17 19:41:46 cpqbld Exp $
+#
+#
+#
+#
+# $XFree86: xc/config/cf/X11.tmpl,v 1.196.2.2 2003/09/17 05:58:15 herrb Exp $
+
+XORGRELSTRING = Release 6.6
+XORGMANNAME = X Version 11
+
+VENDORMANNAME = XFree86
+VENDORMANVERSION = `echo 4 3 0 | sed -e 's/ /./g' -e 's/^/Version\\\ /'`
+
+STICKY_DEFINES = -DHAS_STICKY_DIR_BIT
+
+FCHOWN_DEFINES = -DHAS_FCHOWN
+
+# -----------------------------------------------------------------------
+# X Window System make variables; these need to be coordinated with rules
+
+ XTOP = $(TOP)
+ BINDIR = /usr/X11R6/bin
+ BUILDINCROOT = $(TOP)/exports
+ BUILDINCDIR = $(BUILDINCROOT)/include
+ BUILDINCTOP = ../..
+ BUILDLIBDIR = $(TOP)/exports/lib
+ BUILDLIBTOP = ../..
+ BUILDBINDIR = $(TOP)/exports/bin
+ BUILDBINTOP = ../..
+ BUILDMODULEDIR = $(BUILDLIBDIR)/modules
+ BUILDMODULETOP = $(BUILDLIBTOP)/..
+ XBUILDINCROOT = $(XTOP)/exports
+ XBUILDINCDIR = $(XBUILDINCROOT)/include/X11
+ XBUILDINCTOP = ../../..
+ XBUILDBINDIR = $(XBUILDINCROOT)/bin
+ INCDIR = $(INCROOT)
+ ADMDIR = /var/log
+ LIBDIR = /usr/X11R6/lib/X11
+ LIBEXECDIR = /usr/X11R6/libexec
+ MODULEDIR = $(USRLIBDIR)/modules
+ TOP_X_INCLUDES =
+
+ ETCX11DIR = /etc/X11
+
+ CONFDIR = $(ETCX11DIR)
+
+ DOCDIR = $(LIBDIR)/doc
+ DOCHTMLDIR = $(DOCDIR)/html
+ DOCPSDIR = $(DOCDIR)/PostScript
+ FONTDIR = $(LIBDIR)/fonts
+ ENCODINGSDIR = $(FONTDIR)/encodings
+ XINITDIR = /etc/X11/xinit
+ XDMDIR = /etc/X11/xdm
+ XDMVARDIR = $(VARLIBDIR)/xdm
+ TWMDIR = $(LIBDIR)/twm
+ XSMDIR = $(LIBDIR)/xsm
+ NLSDIR = $(LIBDIR)/nls
+ XLOCALEDIR = $(LIBDIR)/locale
+ PEXAPIDIR = $(LIBDIR)/PEX
+ LBXPROXYDIR = /etc/X11/lbxproxy
+ PROXYMANAGERDIR = /etc/X11/proxymngr
+ XPRINTDIR = /etc/X11/xserver
+ XAPPLOADDIR = $(LIBDIR)/app-defaults
+ FONTCFLAGS = -t
+
+ INSTAPPFLAGS = $(INSTDATFLAGS)
+
+ RGB = $(BINDIR)/rgb
+ FONTC = $(BINDIR)/bdftopcf
+ MKFONTDIR = $(BINDIR)/mkfontdir
+ MKHTMLINDEX = $(BINDIR)/mkhtmlindex
+ UCS2ANY = $(BINDIR)/ucs2any
+ BDFTRUNCATE = $(BINDIR)/bdftruncate
+ UCSMAPPREFIX = $(FONTDIR)/util/map-
+ XCURSORGEN = $(BINDIR)/xcursorgen
+
+ HTMLINDEXCMD = HtmlIndexCmd
+
+ DOCUTILSRC = $(XTOP)/doc/util
+ CLIENTSRC = $(TOP)/clients
+ DEMOSRC = $(TOP)/demos
+ XDOCMACROS = $(DOCUTILSRC)/macros.t
+ XIDXMACROS = $(DOCUTILSRC)/indexmacros.t
+ PROGRAMSRC = $(TOP)/programs
+ LIBSRC = $(XTOP)/lib
+ FONTSRC = $(XTOP)/fonts
+ ENCODINGSSRC = $(FONTSRC)/encodings
+ INCLUDESRC = $(BUILDINCROOT)/include
+ XINCLUDESRC = $(INCLUDESRC)/X11
+ SERVERSRC = $(XTOP)/programs/Xserver
+ CONTRIBSRC = $(XTOP)/../contrib
+ UNSUPPORTEDSRC = $(XTOP)/unsupported
+ DOCSRC = $(XTOP)/doc
+ RGBSRC = $(XTOP)/programs/rgb
+ BDFTOPCFSRC = $(PROGRAMSRC)/bdftopcf
+ MKFONTDIRSRC = $(PROGRAMSRC)/mkfontdir
+ FONTSERVERSRC = $(PROGRAMSRC)/xfs
+ FONTINCSRC = $(XTOP)/include/fonts
+ EXTINCSRC = $(XTOP)/include/extensions
+ FTSOURCEDIR = $(TOP)/extras/FreeType
+ XTTSOURCEDIR = $(TOP)/extras/X-TrueType
+ MESASRCDIR = $(TOP)/extras/Mesa
+ OGLSAMPLESRCDIR = $(TOP)/extras/ogl-sample
+ PSWRAPSRC = $(XTOP)/config/pswrap
+ TRANSCOMMSRC = $(LIBSRC)/xtrans
+ TRANS_INCLUDES = -I$(TRANSCOMMSRC)
+ CONNECTION_FLAGS = -DUNIXCONN -DTCPCONN $(STICKY_DEFINES) $(FCHOWN_DEFINES)
+
+ XORGMANDEFS = -D__xorgversion__='"$(XORGRELSTRING)" "$(XORGMANNAME)"'
+ VENDORMANDEFS = -D__vendorversion__="\"Version $(VENDORMANVERSION)\" $(VENDORMANNAME)"
+
+ XENVLIBDIR = $(USRLIBDIR)
+ CLIENTENVSETUP = LD_LIBRARY_PATH=$(XENVLIBDIR)
+
+# $Xorg: lnxLib.tmpl,v 1.3 2000/08/17 19:41:47 cpqbld Exp $
+# $XFree86: xc/config/cf/lnxLib.tmpl,v 3.13 2001/01/17 16:22:32 dawes Exp $
+
+ XLIBSRC = $(LIBSRC)/X11
+
+SOXLIBREV = 6.2
+DEPXONLYLIB =
+XONLYLIB = -lX11
+
+LINTXONLY = $(LINTLIBDIR)/llib-lX11.ln
+
+ XLIBONLY = $(XONLYLIB)
+
+ XEXTLIBSRC = $(LIBSRC)/Xext
+
+SOXEXTREV = 6.4
+DEPEXTENSIONLIB =
+EXTENSIONLIB = -lXext
+
+LINTEXTENSION = $(LINTLIBDIR)/llib-lXext.ln
+
+LINTEXTENSIONLIB = $(LINTEXTENSION)
+ DEPXLIB = $(DEPEXTENSIONLIB) $(DEPXONLYLIB)
+ XLIB = $(EXTENSIONLIB) $(XONLYLIB)
+ LINTXLIB = $(LINTXONLYLIB)
+
+ XSSLIBSRC = $(LIBSRC)/Xss
+
+DEPXSSLIB = $(USRLIBDIR)/libXss.a
+XSSLIB = -lXss
+
+LINTXSS = $(LINTLIBDIR)/llib-lXss.ln
+
+ XXF86MISCLIBSRC = $(LIBSRC)/Xxf86misc
+
+DEPXXF86MISCLIB = $(USRLIBDIR)/libXxf86misc.a
+XXF86MISCLIB = -lXxf86misc
+
+LINTXXF86MISC = $(LINTLIBDIR)/llib-lXxf86misc.ln
+
+ XXF86VMLIBSRC = $(LIBSRC)/Xxf86vm
+
+DEPXXF86VMLIB = $(USRLIBDIR)/libXxf86vm.a
+XXF86VMLIB = -lXxf86vm
+
+LINTXXF86VM = $(LINTLIBDIR)/llib-lXxf86vm.ln
+
+ XXF86DGALIBSRC = $(LIBSRC)/Xxf86dga
+
+DEPXXF86DGALIB = $(USRLIBDIR)/libXxf86dga.a
+XXF86DGALIB = -lXxf86dga
+
+LINTXXF86DGA = $(LINTLIBDIR)/llib-lXxf86dga.ln
+
+ XXF86RUSHLIBSRC = $(LIBSRC)/Xxf86rush
+
+DEPXXF86RUSHLIB = $(USRLIBDIR)/libXxf86rush.a
+XXF86RUSHLIB = -lXxf86rush
+
+LINTXXF86RUSH = $(LINTLIBDIR)/llib-lXxf86rush.ln
+
+ XVLIBSRC = $(LIBSRC)/Xv
+
+SOXVREV = 1.0
+DEPXVLIB =
+XVLIB = -lXv
+
+LINTXV = $(LINTLIBDIR)/llib-lXv.ln
+
+ XVMCLIBSRC = $(LIBSRC)/XvMC
+
+DEPXVMCLIB = $(USRLIBDIR)/libXvMC.a
+XVMCLIB = -lXvMC
+
+LINTXVMC = $(LINTLIBDIR)/llib-lXvMC.ln
+
+ XINERAMALIBSRC = $(LIBSRC)/Xinerama
+
+DEPXINERAMALIB = $(USRLIBDIR)/libXinerama.a
+XINERAMALIB = -lXinerama
+
+LINTXINERAMA = $(LINTLIBDIR)/llib-lXinerama.ln
+
+ XRESLIBSRC = $(LIBSRC)/XRes
+
+DEPXRESLIB = $(USRLIBDIR)/libXRes.a
+XRESLIB = -lXRes
+
+LINTXRES = $(LINTLIBDIR)/llib-lXRes.ln
+
+ DPSLIBSRC = $(LIBSRC)/dps
+
+SODPSREV = 1.0
+DEPDPSLIB =
+DPSLIB = -ldps
+
+LINTDPS = $(LINTLIBDIR)/llib-ldps.ln
+
+ DPSTKLIBSRC = $(LIBSRC)/dpstk
+
+SODPSTKREV = 1.0
+DEPDPSTKLIB =
+DPSTKLIB = -ldpstk
+
+LINTDPSTK = $(LINTLIBDIR)/llib-ldpstk.ln
+
+ PSRESLIBSRC = $(LIBSRC)/psres
+
+SOPSRESREV = 1.0
+DEPPSRESLIB =
+PSRESLIB = -lpsres
+
+LINTPSRES = $(LINTLIBDIR)/llib-lpsres.ln
+
+ GLULIBSRC = $(LIBSRC)/GLU
+
+SOGLUREV = 1.3
+DEPGLULIB =
+GLULIB = -lGLU
+
+LINTGLU = $(LINTLIBDIR)/llib-lGLU.ln
+
+ GLXLIBSRC = $(LIBSRC)/GL
+
+SOGLREV = 1.2
+DEPGLXLIB =
+GLXLIB = -lGL
+
+LINTGLX = $(LINTLIBDIR)/llib-lGL.ln
+
+ GLWIDGETSRC = $(LIBSRC)/GLw
+
+DEPGLWLIB = $(USRLIBDIR)/libGLw.a
+GLWLIB = -lGLw
+
+LINTGLW = $(LINTLIBDIR)/llib-lGLw.ln
+
+ XRENDERLIBSRC = $(LIBSRC)/Xrender
+
+SOXRENDERREV = 1.2
+DEPXRENDERLIB =
+XRENDERLIB = -lXrender
+
+LINTXRENDER = $(LINTLIBDIR)/llib-lXrender.ln
+
+ XRANDRRLIBSRC = $(LIBSRC)/Xrandr
+
+SOXRANDRREV = 2.0
+DEPXRANDRLIB =
+XRANDRLIB = -lXrandr
+
+LINTXRANDR = $(LINTLIBDIR)/llib-lXrandr.ln
+
+ XCURSORRLIBSRC = $(LIBSRC)/Xcursor
+
+SOXCURSORREV = 1.0
+DEPXCURSORLIB =
+XCURSORLIB = -lXcursor
+
+LINTXCURSOR = $(LINTLIBDIR)/llib-lXcursor.ln
+
+ XFONTCACHELIBSRC = $(LIBSRC)/Xfontcache
+
+DEPXFONTCACHELIB = $(USRLIBDIR)/libXfontcache.a
+XFONTCACHELIB = -lXfontcache
+
+LINTXFONTCACHE = $(LINTLIBDIR)/llib-lXfontcache.ln
+
+ XAUTHSRC = $(LIBSRC)/Xau
+
+DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
+XAUTHLIB = -lXau
+
+LINTXAUTH = $(LINTLIBDIR)/llib-lXau.ln
+
+ XDMCPLIBSRC = $(LIBSRC)/Xdmcp
+
+DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a
+XDMCPLIB = -lXdmcp
+
+LINTXDMCP = $(LINTLIBDIR)/llib-lXdmcp.ln
+
+ XMUSRC = $(LIBSRC)/Xmu
+
+SOXMUREV = 6.2
+DEPXMULIB =
+XMULIB = -lXmu
+
+LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln
+
+ XMUUSRC = $(LIBSRC)/Xmuu
+
+SOXMUUREV = 1.0
+DEPXMUULIB =
+XMUULIB = -lXmuu
+
+LINTXMUU = $(LINTLIBDIR)/llib-lXmuu.ln
+
+ OLDXLIBSRC = $(LIBSRC)/oldX
+
+DEPOLDXLIB = $(USRLIBDIR)/liboldX.a
+OLDXLIB = -loldX
+
+LINTOLDX = $(LINTLIBDIR)/llib-loldX.ln
+
+ XPLIBSRC = $(LIBSRC)/Xp
+
+SOXPREV = 6.2
+DEPXPLIB =
+XPLIB = -lXp
+
+LINTXP = $(LINTLIBDIR)/llib-lXp.ln
+
+ TOOLKITSRC = $(LIBSRC)/Xt
+
+SOXTREV = 6.0
+DEPXTOOLONLYLIB =
+XTOOLONLYLIB = -lXt
+
+LINTXTOOLONLY = $(LINTLIBDIR)/llib-lXt.ln
+
+ DEPXTOOLLIB = $(DEPXTOOLONLYLIB) $(DEPSMLIB) $(DEPICELIB)
+ XTOOLLIB = $(XTOOLONLYLIB) $(SMLIB) $(ICELIB)
+ LINTXTOOLLIB = $(LINTXTOOLONLYLIB)
+
+ XALIBSRC = $(LIBSRC)/Xa
+
+SOXAREV = 1.0
+DEPXALIB =
+XALIB = -lXa
+
+LINTXA = $(LINTLIBDIR)/llib-lXa.ln
+
+ AWIDGETSRC = $(LIBSRC)/Xaw
+
+SOXAWREV = 7.0
+DEPXAWLIB =
+XAWLIB = -lXaw
+
+LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln
+
+ AWIDGET6SRC = $(LIBSRC)/Xaw6
+
+SOXAW6REV = 6.1
+DEPXAW6LIB =
+XAW6LIB = -lXaw
+
+LINTXAW6 = $(LINTLIBDIR)/llib-lXaw.ln
+
+ XILIBSRC = $(LIBSRC)/Xi
+
+SOXINPUTREV = 6.0
+DEPXILIB =
+XILIB = -lXi
+
+LINTXI = $(LINTLIBDIR)/llib-lXi.ln
+
+ XTESTLIBSRC = $(LIBSRC)/Xtst
+
+SOXTESTREV = 6.1
+DEPXTESTLIB =
+XTESTLIB = -lXtst
+
+LINTXTEST = $(LINTLIBDIR)/llib-lXtst.ln
+
+ PEXLIBSRC = $(LIBSRC)/PEX5
+
+SOPEXREV = 6.0
+DEPPEXLIB =
+PEXLIB = -lPEX5
+
+LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln
+
+ XIELIBSRC = $(LIBSRC)/XIE
+
+SOXIEREV = 6.0
+DEPXIELIB =
+XIELIB = -lXIE
+
+LINTXIE = $(LINTLIBDIR)/llib-lXIE.ln
+
+ PHIGSLIBSRC = $(LIBSRC)/PHIGS
+
+DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a
+PHIGSLIB = -lphigs
+
+LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln
+
+DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a
+XBSDLIB = -lXbsd
+
+LINTXBSD = $(LINTLIBDIR)/llib-lXbsd.ln
+
+ ICESRC = $(LIBSRC)/ICE
+
+SOICEREV = 6.3
+DEPICELIB =
+ICELIB = -lICE
+
+LINTICE = $(LINTLIBDIR)/llib-lICE.ln
+
+ SMSRC = $(LIBSRC)/SM
+
+SOSMREV = 6.0
+DEPSMLIB =
+SMLIB = -lSM
+
+LINTSM = $(LINTLIBDIR)/llib-lSM.ln
+
+ XKEYSRC = $(LIBSRC)/Xkey
+
+SOXKEYREV = 6.0
+DEPXKEYLIB =
+XKEYLIB = -lXkey
+
+LINTXKEY = $(LINTLIBDIR)/llib-lXkey.ln
+
+ FSLIBSRC = $(LIBSRC)/FS
+
+DEPFSLIB = $(USRLIBDIR)/libFS.a
+FSLIB = -lFS
+
+LINTFS = $(LINTLIBDIR)/llib-lFS.ln
+
+ FONTLIBSRC = $(LIBSRC)/font
+
+SOFONTREV = 1.4
+DEPFONTLIB =
+FONTLIB = -L$(FREETYPELIBDIR) -L$(FONTLIBSRC) -lXfont
+
+LINTXFONT = $(LINTLIBDIR)/llib-lXfont.ln
+#
+SOFONTREV = 1.4
+DEPXFONTLIB =
+XFONTLIB = -lXfont
+
+LINTXFONT = $(LINTLIBDIR)/llib-lXfont.ln
+
+ FONTSTUBLIBSRC = $(FONTLIBSRC)/stubs
+
+DEPFONTSTUBLIB = $(USRLIBDIR)/libfntstubs.a
+FONTSTUBLIB = -lfntstubs
+
+LINTFONTSTUB = $(LINTLIBDIR)/llib-lfntstubs.ln
+ DEPFONTLIB = $(DEPXFONTLIB) $(DEPFONTSTUBLIB)
+ FONTLIB = $(XFONTLIB) $(FONTSTUBLIB) $(FONTFT2LIB)
+
+ FONTENCLIBSRC = $(LIBSRC)/fontenc
+
+DEPXFONTENCLIB = $(USRLIBDIR)/libfontenc.a
+XFONTENCLIB = -lfontenc
+
+LINTXFONTENC = $(LINTLIBDIR)/llib-lfontenc.ln
+
+ XPMLIBSRC = $(LIBSRC)/Xpm
+
+SOXPMREV = 4.11
+DEPXPMLIB =
+XPMLIB = -lXpm
+
+LINTXPM = $(LINTLIBDIR)/llib-lXpm.ln
+
+FREETYPE2DIR = /usr
+FREETYPE2LIBDIR = /usr/lib
+FREETYPE2INCDIR = /usr/include/freetype2
+
+FREETYPE2LIB = -lfreetype
+
+FREETYPE2INCLUDES = -I$(FREETYPE2INCDIR)
+FREETYPE2DEFINES = -DFREETYPE2
+
+ EXPATLIBSRC = $(LIBSRC)/expat
+
+SOEXPATREV = 1.0
+DEPEXPATLIB =
+EXPATLIB = -lexpat
+
+LINTEXPAT = $(LINTLIBDIR)/llib-lexpat.ln
+
+EXPATDIR = /usr
+EXPATLIBDIR = /usr/lib
+EXPATINCDIR = /usr/include
+
+EXPATINCLUDES =
+
+EXPATLIB = -lexpat
+
+EXPATDEFINES = -DEXPAT
+
+ XFT1LIBSRC = $(LIBSRC)/Xft1
+
+SOXFT1REV = 1.1
+DEPXFT1LIB =
+XFT1LIB = -lXft
+
+LINTXFT1 = $(LINTLIBDIR)/llib-lXft.ln
+
+ XFTLIBSRC = $(LIBSRC)/Xft
+
+SOXFTREV = 2.1
+DEPXFTLIB =
+XFTLIB = -lXft
+
+LINTXFT = $(LINTLIBDIR)/llib-lXft.ln
+
+XFTINCLUDES=$(FONTCONFIGINCLUDES) $(FREETYPE2INCLUDES)
+
+FONTCONFIGDIR = /usr
+FONTCONFIGLIBDIR = /usr/lib
+FONTCONFIGINCDIR = /usr/include
+FONTCONFIGBINDIR = /usr/bin
+
+FONTCONFIGLIB = -lfontconfig
+
+FONTCONFIGINCLUDES =
+
+FCCACHE = $(FONTCONFIGBINDIR)/fc-cache
+
+FONTCONFIGDEFINES = -DFONTCONFIG
+
+LIBPNGINCDIR = /usr/include
+
+LIBPNGINC=
+
+LIBPNGDIR = /usr
+LIBPNGLIBDIR = /usr/lib
+LIBPNGINCDIR = /usr/include
+
+LIBPNGLIB = -lpng
+
+ XKBFILELIBSRC = $(LIBSRC)/xkbfile
+
+DEPXKBFILELIB = $(USRLIBDIR)/libxkbfile.a
+XKBFILELIB = -lxkbfile
+
+LINTXKBFILE = $(LINTLIBDIR)/llib-lxkbfile.ln
+
+ XKBCOMPCMD = $(BINDIR)/xkbcomp
+
+ XKBUILIBSRC = $(LIBSRC)/xkbui
+
+DEPXKBUILIB = $(USRLIBDIR)/libxkbui.a
+XKBUILIB = -lxkbui
+
+LINTXKBUI = $(LINTLIBDIR)/llib-lxkbui.ln
+
+ XTRAPLIBSRC = $(LIBSRC)/XTrap
+
+SOXTRAPREV = 6.4
+DEPXTRAPLIB =
+XTRAPLIB = -lXTrap
+
+LINTXTRAP = $(LINTLIBDIR)/llib-lXTrap.ln
+
+ DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
+
+ DEPLIBS1 = $(DEPLIBS)
+ DEPLIBS2 = $(DEPLIBS)
+ DEPLIBS3 = $(DEPLIBS)
+ DEPLIBS4 = $(DEPLIBS)
+ DEPLIBS5 = $(DEPLIBS)
+ DEPLIBS6 = $(DEPLIBS)
+ DEPLIBS7 = $(DEPLIBS)
+ DEPLIBS8 = $(DEPLIBS)
+ DEPLIBS9 = $(DEPLIBS)
+ DEPLIBS10 = $(DEPLIBS)
+
+XMULIBONLY = -lXmu
+XMULIB = $(XMULIBONLY) $(XTOOLLIB) $(XLIB)
+
+ CONFIGDIR = $(LIBDIR)/config
+
+ USRLIBDIRPATH = $(USRLIBDIR)
+ LDPRELIBS = -L$(USRLIBDIR) $(INSTALLED_LIBS)
+ LDPOSTLIBS =
+ TOP_INCLUDES = -I$(INCROOT) $(TOP_X_INCLUDES)
+ PROJECT_DEFINES =
+
+CXXPROJECT_DEFINES =
+
+# ----------------------------------------------------------------------
+# start of Imakefile
+
+# Imakefile for maintaining Tcl in the Object Manager library.
+# 05-Sep-93, Doug Tody NOAO/IRAF.
+# 28-Aug-96, Mike Fitzpatrick NOAO/IRAF. (Revised)
+
+X11IRAFDIR = ../../
+
+# $Xorg: Library.tmpl,v 1.3 2000/08/17 19:41:46 cpqbld Exp $
+
+# $XFree86: xc/config/cf/Library.tmpl,v 3.20 2002/11/25 14:04:47 eich Exp $
+
+ CC = gcc -m32
+
+ CCOPTIONS =
+STD_DEFINES = -Dlinux -D__i386__ -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE $(PROJECT_DEFINES)
+CDEBUGFLAGS = -O2 -pipe -march=i386 -mcpu=i686 -fno-strict-aliasing -pipe
+CLIBDEBUGFLAGS =
+ CFLAGS = $(CDEBUGFLAGS) $(CLIBDEBUGFLAGS) $(CCOPTIONS) $(THREADS_CFLAGS) $(ALLDEFINES)
+
+LIB_MT_DEFINES = LibraryMTDefines
+
+SOSYMLINK = true
+
+ X11IRAFBINDIR = $(X11IRAFDIR)/bin
+ X11IRAFMANDIR = $(X11IRAFDIR)/man
+ X11IRAFLIBDIR = $(X11IRAFDIR)/lib
+ X11IRAFINCDIR = $(X11IRAFDIR)/include
+
+ XGTERMDIR = $(X11IRAFDIR)/xgterm
+ XIMTOOLDIR = $(X11IRAFDIR)/ximtool
+ XTAPEMONDIR = $(X11IRAFDIR)/xtapemon
+ OBMSHDIR = $(X11IRAFDIR)/obmsh
+ OBMDIR = $(X11IRAFDIR)/obm
+ XPMDIR = $(X11IRAFDIR)/xpm
+ XAW3DDIR = $(X11IRAFDIR)/xaw3d
+ CDLDIR = $(X11IRAFDIR)/cdl
+
+ DEPLIBOBM = $(OBMDIR)/libobm.a
+ LIBOBM = -lobm
+ DEPLIBXPM = $(XPMDIR)/libXpm.a
+ LIBXPM = -lXpm
+ DEPLIBXAW3D = $(XAW3DDIR)/libXaw3d.a
+ LIBXAW3D = -lXaw3d
+ LIBCDL = -lcdl
+
+ X11IRAF_LDFLAGS = -L$(X11IRAFDIR)/lib -L../lib
+ X11IRAF_INCLUDES = -I$(X11IRAFDIR)/include -I../include
+
+ CP = cp -p
+
+# ------------------ BEGIN TCL DEFINITIONS ----------------------
+
+ TCL_LIBRARY = /usr/local/lib/tcl
+ SRC_DIR = .
+
+# - The following are for Linux
+ GCC_FLAGS = -DNOSTDHDRS -DSYSV -DANSI -D_BSD_SOURCE -W -fstrength-reduce -fpcc-struct-return
+
+ AC_FLAGS = -DHAVE_UNISTD_H=1
+ COMPAT_OBJS =
+
+# Platform flags.
+
+ PL_FLAGS = -DUSE_STDARG
+
+ DEPENDFLAGS = -I.. -I${SRC_DIR} ${AC_FLAGS} ${PL_FLAGS}
+ CCOPTIONS = -I.. -I${SRC_DIR} ${AC_FLAGS} ${PL_FLAGS} ${GCC_FLAGS} -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
+
+UNIX_OBJS = panic.o tclEnv.o tclGlob.o tclMain.o tclUnixAZ.o tclUnixStr.o tclUnixUtil.o
+
+GENERIC_OBJS = regexp.o tclAsync.o tclBasic.o tclCkalloc.o tclCmdAH.o tclCmdIL.o tclCmdMZ.o tclExpr.o tclGet.o tclHash.o tclHistory.o tclLink.o tclParse.o tclProc.o tclUtil.o tclVar.o
+
+TCL_OBJS = ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS}
+
+# -------------------- END TCL DEFINITIONS ----------------------
+
+HEADERS = patchlevel.h tclRegexp.h tcl.h tclInt.h tclUnix.h
+
+SRCS = panic.c regexp.c tclAppInit.c tclAsync.c tclBasic.c tclCkalloc.c tclCmdAH.c tclCmdIL.c tclCmdMZ.c tclEnv.c tclExpr.c tclGet.c tclGlob.c tclHash.c tclHistory.c tclLink.c tclMain.c tclMtherr.c tclParse.c tclProc.c tclTest.c tclUnixAZ.c tclUnixStr.c tclUnixUtil.c tclUtil.c tclVar.c
+
+OBJS = ${TCL_OBJS}
+
+all:: DONE
+
+DONE: $(OBJS)
+ $(RM) $@
+ touch $@
+
+cleandir::
+ $(RM) DONE
+
+# ------------------ BEGIN TCL DEFINITIONS ----------------------
+getcwd.o: $(SRC_DIR)/compat/getcwd.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/getcwd.c
+
+opendir.o: $(SRC_DIR)/compat/opendir.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/opendir.c
+
+strerror.o: $(SRC_DIR)/compat/strerror.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strerror.c
+
+strstr.o: $(SRC_DIR)/compat/strstr.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strstr.c
+
+strtod.o: $(SRC_DIR)/compat/strtod.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtod.c
+
+strtol.o: $(SRC_DIR)/compat/strtol.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtol.c
+
+strtoul.o: $(SRC_DIR)/compat/strtoul.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/strtoul.c
+
+tmpnam.o: $(SRC_DIR)/compat/tmpnam.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/tmpnam.c
+
+waitpid.o: $(SRC_DIR)/compat/waitpid.c
+ $(CC) -c $(CCOPTIONS) $(SRC_DIR)/compat/waitpid.c
+# -------------------- END TCL DEFINITIONS ----------------------
+
+lint:
+ $(LINT) $(LINTFLAGS) $(SRCS) $(LINTLIBS)
+lint1:
+ $(LINT) $(LINTFLAGS) $(FILE) $(LINTLIBS)
+
+lintlib:: llib-lar.ln
+
+llib-lar.ln: $(SRCS) $(EXTRALIBRARYDEPS)
+ $(RM) $@
+ $(LINT) $(LINTLIBFLAG)ar $(LINTFLAGS) $(SRCS)
+
+includes::
+ @if [ -d $(X11IRAFDIR)/include/Tcl ]; then \
+ set +x; \
+ else \
+ if [ -h $(X11IRAFDIR)/include/Tcl ]; then \
+ (set -x; rm -f $(X11IRAFDIR)/include/Tcl); \
+ fi; \
+ (set -x; $(MKDIRHIER) $(X11IRAFDIR)/include/Tcl); \
+ fi
+ @(set -x; for i in $(HEADERS); do $(RM) $(X11IRAFDIR)/include/Tcl/$$i; $(CP) -p $(X11IRAFDIR)/obm/Tcl/$$i $(X11IRAFDIR)/include/Tcl/$$i; done)
+
+install::
+ @(set -x; for i in $(HEADERS); do $(RM) $(X11IRAFDIR)/include/Tcl/$$i; done)
+
+ for i in $(HEADERS); do (set -x; $(CP) -p $$i $(X11IRAFDIR)/include/Tcl/); done
+
+depend::
+ $(DEPEND) $(DEPENDFLAGS) -- $(ALLDEFINES) $(DEPEND_DEFINES) -- $(SRCS)
+
+# ----------------------------------------------------------------------
+# common rules for all Makefiles - do not edit
+
+.c.i:
+ $(RM) $@
+ $(CC) -E $(CFLAGS) $(_NOOP_) $*.c > $@
+
+.SUFFIXES: .s
+
+.c.s:
+ $(RM) $@
+ $(CC) -S $(CFLAGS) $(_NOOP_) $*.c
+
+emptyrule::
+
+cleandir::
+ $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"*
+
+Makefile::
+ -@if [ -f Makefile ]; then set -x; \
+ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
+ else exit 0; fi
+ $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
+
+tags::
+ $(TAGS) -w *.[ch]
+ $(TAGS) -xw *.[ch] > TAGS
+
+man_keywords::
+
+html_index::
+
+clean:: cleandir
+
+distclean:: cleandir
+
+# ----------------------------------------------------------------------
+# empty rules for directories that do not have SUBDIRS - do not edit
+
+install::
+ @echo "install in $(CURRENT_DIR) done"
+
+install.man::
+ @echo "install.man in $(CURRENT_DIR) done"
+
+install.sdk::
+ @echo "install.sdk in $(CURRENT_DIR) done"
+
+Makefiles::
+
+includes::
+
+depend::
+
+distclean::
+ $(RM) Makefile Makefile.dep
+
+# ----------------------------------------------------------------------
+# dependencies generated by makedepend
+
diff --git a/vendor/x11iraf/obm/Tcl/README b/vendor/x11iraf/obm/Tcl/README
new file mode 100644
index 00000000..9cb306f5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/README
@@ -0,0 +1,346 @@
+Tcl
+
+by John Ousterhout
+University of California at Berkeley
+ouster@cs.berkeley.edu
+
+1. Introduction
+---------------
+
+This directory contains the sources and documentation for Tcl, an
+embeddable tool command language. The information here corresponds
+to release 7.3.
+
+2. Documentation
+----------------
+
+The best way to get started with Tcl is to read the draft of my
+upcoming book on Tcl and Tk, which can be retrieved using anonymous
+FTP from the directory "ucb/tcl" on ftp.cs.berkeley.edu. Part I of the
+book provides an introduction to writing Tcl scripts and Part III
+describes how to write C code that uses the Tcl C library procedures.
+
+The "doc" subdirectory in this release contains a complete set of manual
+entries for Tcl. Files with extension ".1" are for programs (for
+example, tclsh.1); files with extension ".3" are for C library procedures;
+and files with extension ".n" describe Tcl commands. The file "doc/Tcl.n"
+gives a quick summary of the Tcl language syntax. To print any of the man
+pages, cd to the "doc" directory and invoke your favorite variant of
+troff using the normal -man macros, for example
+
+ ditroff -man Tcl.n
+
+to print Tcl.n. If Tcl has been installed correctly and your "man"
+program supports it, you should be able to access the Tcl manual entries
+using the normal "man" mechanisms, such as
+
+ man Tcl
+
+3. Compiling and installing Tcl
+-------------------------------
+
+This release should compile and run "out of the box" on any UNIX-like
+system that approximates POSIX, BSD, or System V. I know that it runs
+on workstations from Sun, DEC, H-P, IBM, and Silicon Graphics, and on
+PC's running SCO UNIX and Xenix. To compile Tcl, do the following:
+
+ (a) Type "./configure" in this directory. This runs a configuration
+ script created by GNU autoconf, which configures Tcl for your
+ system and creates a Makefile. The configure script allows you
+ to customize the Tcl configuration for your site; for details on
+ how you can do this, see the file "configure.info".
+
+ (b) Type "make". This will create a library archive called "libtcl.a"
+ and an interpreter application called "tclsh" that allows you to type
+ Tcl commands interactively or execute script files.
+
+ (c) If the make fails then you'll have to personalize the Makefile
+ for your site or possibly modify the distribution in other ways.
+ First check the file "porting.notes" to see if there are hints
+ for compiling on your system. If you need to modify Makefile,
+ there are comments at the beginning of it that describe the things
+ you might want to change and how to change them.
+
+ (d) Type "make install" to install Tcl binaries and script files in
+ standard places. You'll need write permission on /usr/local to
+ do this. See the Makefile for details on where things get
+ installed.
+
+ (e) At this point you can play with Tcl by invoking the "tclsh"
+ program and typing Tcl commands. However, if you haven't installed
+ Tcl then you'll first need to set your TCL_LIBRARY variable to
+ hold the full path name of the "library" subdirectory.
+
+If you have trouble compiling Tcl, I'd suggest looking at the file
+"porting.notes". It contains information that people have sent me about
+changes they had to make to compile Tcl in various environments. I make
+no guarantees that this information is accurate, complete, or up-to-date,
+but you may find it useful. If you get Tcl running on a new configuration,
+I'd be happy to receive new information to add to "porting.notes". I'm
+also interested in hearing how to change the configuration setup so that
+Tcl compiles on additional platforms "out of the box".
+
+4. Test suite
+-------------
+
+There is a relatively complete test suite for all of the Tcl core in
+the subdirectory "tests". To use it just type "make test" in this
+directory. You should then see a printout of the test files processed.
+If any errors occur, you'll see a much more substantial printout for
+each error. See the README file in the "tests" directory for more
+information on the test suite.
+
+5. Summary of changes in recent releases
+----------------------------------------
+
+Tcl 7.3 is a minor release that includes only one change relative to
+Tcl 7.1 (it fixes a portability problem that prevented tclMain.c from
+compiling on some machines due to a missing R_OK definition). Tcl 7.3
+should be completely compatible with Tcl 7.1 and Tcl 7.0.
+
+Tcl 7.2 was a mistake; it was withdrawn shortly after it was released.
+
+Tcl 7.1 is a minor release that consists almost entirely of bug fixes.
+The only feature change is to allow no arguments in invocations of "list"
+and "concat". 7.1 should be completely compatible with 7.0.
+
+Tcl 7.0 is a major new release that includes several new features
+and a few incompatible changes. For a complete list of all changes
+to Tcl in chronological order, see the file "changes". Those changes
+likely to cause compatibility problems with existing C code or Tcl
+scripts are specially marked. The most important changes are
+summarized below.
+
+Tcl configuration and installation has improved in several ways:
+
+ 1. GNU autoconf is now used for configuring Tcl prior to compilation.
+
+ 2. The "tclTest" program no longer exists. It has been replaced by
+ "tclsh", which is a true shell-like program based around Tcl (tclTest
+ didn't really work very well as a shell). There's a new program
+ "tcltest" which is the same as "tclsh" except that it includes a
+ few extra Tcl commands for testing purposes.
+
+ 3. A new procedure Tcl_AppInit has been added to separate all of the
+ application-specific initialization from the Tcl main program. This
+ should make it easier to build new Tcl applications that include
+ extra packages.
+
+ 4. There are now separate manual entries for each of the built-in
+ commands. The manual entry "Tcl.n", which used to describe all of
+ the built-ins plus many other things, now contains a terse but
+ complete description of the Tcl language syntax.
+
+Here is a list of all incompatibilities that affect Tcl scripts:
+
+ 1. There have been several changes to backslash processing:
+ - Unknown backslash sequences such as "\*" are now replaced with
+ the following character (such as "*"); Tcl used to treat the
+ backslash as an ordinary character in these cases, so both the
+ backslash and the following character would be passed through.
+ - Backslash-newline now eats up any white space after the newline,
+ replacing the whole sequence with a single space character. Tcl
+ used to just remove the backslash and newline.
+ - The obsolete sequences \Cx, \Mx, \CMx, and \e no longer get
+ special treatment.
+ - The "format" command no longer does backslash processing on
+ its input string.
+ You can invoke the shell command below to locate backslash uses that
+ may potentially behave differently under Tcl 7.0. This command
+ will print all of the lines from the script files "*.tcl" that may
+ not work correctly under Tcl 7.0:
+ egrep '(\\$)|(\\[^][bfnrtv\0-9{}$ ;"])' *.tcl
+ In some cases the command may print lines that are actually OK.
+
+ 2. The "glob" command now returns only the names of files that
+ actually exist, and it only returns names ending in "/" for
+ directories.
+
+ 3. When Tcl prints floating-point numbers (e.g. in the "expr" command)
+ it ensures that the numbers contain a "." or "e" so that they don't
+ look like integers.
+
+ 4. The "regsub" command now overwrites its result variable in all cases.
+ If there is no match, then the source string is copied to the result.
+
+ 5. The "exec", "glob", "regexp", and "regsub" commands now include a
+ "--" switch; if the first non-switch argument starts with a "-" then
+ there must be a "--" switch or the non-switch argument will be treated
+ as a switch.
+
+ 6. The keyword "UNIX" in the variable "errorCode" has been changed to
+ "POSIX".
+
+ 7. The "format" and "scan" commands no longer support capitalized
+ conversion specifiers such as "%D" that aren't supported by ANSI
+ sprintf and sscanf.
+
+Here is a list of all of the incompatibilities that affect C code that
+uses the Tcl library procedures. If you use an ANSI C compiler then
+any potential problems will be detected when you compile your code: if
+your code compiles cleanly then you don't need to worry about anything.
+
+ 1. Tcl_TildeString now takes a dynamic string as an argument, which is
+ used to hold the result.
+
+ 2. tclHash.h has been eliminated; its contents are now in tcl.h.
+
+ 3. The Tcl_History command has been eliminated: the "history" command
+ is now automatically part of the interpreter.
+
+ 4. The Tcl_Fork and Tcl_WaitPids procedures have been deleted (just
+ use fork and waitpid instead).
+
+ 5. The "flags" and "termPtr" arguments to Tcl_Eval have been eliminated,
+ as has the "noSep" argument to Tcl_AppendElement and the TCL_NO_SPACE
+ flag for Tcl_SetVar and Tcl_SetVar2.
+
+ 6. The Tcl_CmdBuf structure has been eliminated, along with the procedures
+ Tcl_CreateCmdBuf, Tcl_DeleteCmdBuf, and Tcl_AssembleCmd. Use dynamic
+ strings instead.
+
+ 7. Tcl_UnsetVar and Tcl_UnsetVar2 now return TCL_OK or TCL_ERROR instead
+ of 0 or -1.
+
+ 8. Tcl_UnixError has been renamed to Tcl_PosixError.
+
+ 9. Tcl no longer redefines the library procedures "setenv", "putenv",
+ and "unsetenv" by default. You have to set up special configuration
+ in the Makefile if you want this.
+
+Below is a sampler of the most important new features in Tcl 7.0. Refer
+to the "changes" file for a complete list.
+
+ 1. The "expr" command supports transcendental and other math functions,
+ plus it allows you to type expressions in multiple arguments. Its
+ numerics have also been improved in several ways (e.g. support for
+ NaN).
+
+ 2. The "format" command now supports XPG3 %n$ conversion specifiers.
+
+ 3. The "exec" command supports many new kinds of redirection such as
+ >> and >&, plus it allows you to leave out the space between operators
+ like < and the file name. For processes put into the background,
+ "exec" returns a list of process ids.
+
+ 4. The "lsearch" command now supports regular expressions and exact
+ matching.
+
+ 5. The "lsort" command has several new switches to control the
+ sorting process (e.g. numerical sort, user-provided sort function,
+ reverse sort, etc.).
+
+ 6. There's a new command "pid" that can be used to return the current
+ process ids or the process ids from an open file that refers to a
+ pipeline.
+
+ 7. There's a new command "switch" that should now be used instead
+ of "case". It supports regular expressions and exact matches, and
+ also uses single patterns instead of pattern lists. "Case" is
+ now deprecated, although it's been retained for compatibility.
+
+ 8. A new dynamic string library has been added to make it easier to
+ build up strings and lists of arbitrary length. See the manual entry
+ "DString.3".
+
+ 9. Variable handling has been improved in several ways: you can
+ now use whole-array traces to create variables on demand, you can
+ delete variables during traces, you can upvar to array elements,
+ and you can retarget an upvar variable to stop through a sequence
+ of variables. Also, there's a new library procedure Tcl_LinkVar
+ that can be used to associate a C variable with a Tcl variable and
+ keep them in sync.
+
+ 10. New library procedures Tcl_SetCommandInfo and Tcl_GetCommandInfo
+ allow you to set and get the clientData and callback procedure for
+ a command.
+
+ 11. Added "-errorinfo" and "-errorcode" options to "return" command;
+ they allow much better error handling.
+
+ 12. Made prompts in tclsh user-settable via "tcl_prompt1" and
+ "tcl_prompt2" variables.
+
+ 13. Added low-level support that is needed to handle signals: see
+ Tcl_AsyncCreate, etc.
+
+6. Tcl newsgroup
+-----------------
+
+There is a network news group "comp.lang.tcl" intended for the exchange
+of information about Tcl, Tk, and related applications. Feel free to use
+the newsgroup both for general information questions and for bug reports.
+I read the newsgroup and will attempt to fix bugs and problems reported
+to it.
+
+7. Tcl contributed archive
+--------------------------
+
+Many people have created exciting packages and applications based on Tcl
+and made them freely available to the Tcl community. An archive of these
+contributions is kept on the machine harbor.ecn.purdue.edu. You can
+access the archive using anonymous FTP; the Tcl contributed archive is
+in the directory "pub/tcl". The archive also contains an FAQ ("frequently
+asked questions") document that provides solutions to problems that
+are commonly encountered by TCL newcomers.
+
+8. Support and bug fixes
+------------------------
+
+I'm very interested in receiving bug reports and suggestions for
+improvements. Bugs usually get fixed quickly (particularly if they
+are serious), but enhancements may take a while and may not happen at
+all unless there is widespread support for them (I'm trying to slow
+the rate at which Tcl turns into a kitchen sink). It's almost impossible
+to make incompatible changes to Tcl at this point.
+
+The Tcl community is too large for me to provide much individual
+support for users. If you need help I suggest that you post questions
+to comp.lang.tcl. I read the newsgroup and will attempt to answer
+esoteric questions for which no-one else is likely to know the answer.
+In addition, Tcl support and training are available commercially from
+NeoSoft. For more information, send e-mail to "info@neosoft.com".
+
+9. Tcl release organization
+---------------------------
+
+Each Tcl release is identified by two numbers separated by a dot, e.g.
+6.7 or 7.0. If a new release contains changes that are likely to break
+existing C code or Tcl scripts then the major release number increments
+and the minor number resets to zero: 6.0, 7.0, etc. If a new release
+contains only bug fixes and compatible changes, then the minor number
+increments without changing the major number, e.g. 7.1, 7.2, etc. If
+you have C code or Tcl scripts that work with release X.Y, then they
+should also work with any release X.Z as long as Z > Y.
+
+Beta releases have an additional suffix of the form bx. For example,
+Tcl 7.0b1 is the first beta release of Tcl version 7.0, Tcl 7.0b2 is
+the second beta release, and so on. A beta release is an initial
+version of a new release, used to fix bugs and bad features before
+declaring the release stable. Each new release will be preceded by
+one or more beta releases. I hope that lots of people will try out
+the beta releases and report problems back to me. I'll make new beta
+releases to fix the problems, until eventually there is a beta release
+that appears to be stable. Once this occurs I'll remove the beta
+suffix so that the last beta release becomes the official release.
+
+If a new release contains incompatibilities (e.g. 7.0) then I can't
+promise to maintain compatibility among its beta releases. For example,
+release 7.0b2 may not be backward compatible with 7.0b1. I'll try
+to minimize incompatibilities between beta releases, but if a major
+problem turns up then I'll fix it even if it introduces an
+incompatibility. Once the official release is made then there won't
+be any more incompatibilities until the next release with a new major
+version number.
+
+10. Compiling on non-UNIX systems
+--------------------------------
+
+The Tcl features that depend on system calls peculiar to UNIX (stat,
+fork, exec, times, etc.) are now separate from the main body of Tcl,
+which only requires a few generic library procedures such as malloc
+and strcpy. Thus it should be relatively easy to compile Tcl for
+non-UNIX machines such as MACs and DOS PC's, although a number of
+UNIX-specific commands will be absent (e.g. exec, time, and glob).
+See the comments at the top of Makefile for information on how to
+compile without the UNIX features.
diff --git a/vendor/x11iraf/obm/Tcl/README.OBM b/vendor/x11iraf/obm/Tcl/README.OBM
new file mode 100644
index 00000000..bf6b891e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/README.OBM
@@ -0,0 +1,17 @@
+README for Tcl configured as part of the IRAF Object Manager Library.
+
+This is the standard Tcl distribution; the only difference is the addition
+of an Imakefile to allow automated building of the Tcl library as part of
+the Object Manager. The Imakefile should be machine independent with one
+exception, the COMPAT_OBJS definition, which lists the compatibility
+routines. The list of objects defined here may have to be modified for
+a different host. One way to do this is to manually run "./configure" in
+this directory to build the standard Tcl Makefile, then transfer the
+COMPAT_OBJS entry therein to the Imakefile.
+
+Tcl does not need to be installed (as in make install) to be used with the
+Object Manager. The contents of the Tcl library are automatically included
+in libObm.a when the library is built. The Tcl include file can be
+referenced as Tcl/tcl.h, with the OBM root directory specified as an -I
+include directory in the application's Imakefile. In most cases the
+application using OBM need not know that Tcl is used internally.
diff --git a/vendor/x11iraf/obm/Tcl/changes b/vendor/x11iraf/obm/Tcl/changes
new file mode 100644
index 00000000..d920add2
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/changes
@@ -0,0 +1,958 @@
+Recent user-visible changes to Tcl:
+
+1. No more [command1] [command2] construct for grouping multiple
+commands on a single command line.
+
+2. Semi-colon now available for grouping commands on a line.
+
+3. For a command to span multiple lines, must now use backslash-return
+at the end of each line but the last.
+
+4. "Var" command has been changed to "set".
+
+5. Double-quotes now available as an argument grouping character.
+
+6. "Return" may be used at top-level.
+
+7. More backslash sequences available now. In particular, backslash-newline
+may be used to join lines in command files.
+
+8. New or modified built-in commands: case, return, for, glob, info,
+print, return, set, source, string, uplevel.
+
+9. After an error, the variable "errorInfo" is filled with a stack
+trace showing what was being executed when the error occurred.
+
+10. Command abbreviations are accepted when parsing commands, but
+are not recommended except for purely-interactive commands.
+
+11. $, set, and expr all complain now if a non-existent variable is
+referenced.
+
+12. History facilities exist now. See Tcl.man and Tcl_RecordAndEval.man.
+
+13. Changed to distinguish between empty variables and those that don't
+exist at all. Interfaces to Tcl_GetVar and Tcl_ParseVar have changed
+(NULL return value is now possible). *** POTENTIAL INCOMPATIBILITY ***
+
+14. Changed meaning of "level" argument to "uplevel" command (1 now means
+"go up one level", not "go to level 1"; "#1" means "go to level 1").
+*** POTENTIAL INCOMPATIBILITY ***
+
+15. 3/19/90 Added "info exists" option to see if variable exists.
+
+16. 3/19/90 Added "noAbbrev" variable to prohibit command abbreviations.
+
+17. 3/19/90 Added extra errorInfo option to "error" command.
+
+18. 3/21/90 Double-quotes now only affect space: command, variable,
+and backslash substitutions still occur inside double-quotes.
+*** POTENTIAL INCOMPATIBILITY ***
+
+19. 3/21/90 Added support for \r.
+
+20. 3/21/90 List, concat, eval, and glob commands all expect at least
+one argument now. *** POTENTIAL INCOMPATIBILITY ***
+
+21. 3/22/90 Added "?:" operators to expressions.
+
+22. 3/25/90 Fixed bug in Tcl_Result that caused memory to get trashed.
+
+------------------- Released version 3.1 ---------------------
+
+23. 3/29/90 Fixed bug that caused "file a.b/c ext" to return ".b/c".
+
+24. 3/29/90 Semi-colon is not treated specially when enclosed in
+double-quotes.
+
+------------------- Released version 3.2 ---------------------
+
+25. 4/16/90 Rewrote "exec" not to use select or signals anymore.
+Should be more Sys-V compatible, and no slower in the normal case.
+
+26. 4/18/90 Rewrote "glob" to eliminate GNU code (there's no GNU code
+left in Tcl, now), and added Tcl_TildeSubst procedure. Added automatic
+tilde-substitution in many commands, including "glob".
+
+------------------- Released version 3.3 ---------------------
+
+27. 7/11/90 Added "Tcl_AppendResult" procedure.
+
+28. 7/20/90 "History" with no options now defaults to "history info"
+rather than to "history redo". Although this is a backward incompatibility,
+it should only be used interactively and thus shouldn't present any
+compatibility problems with scripts.
+
+29. 7/20/90 Added "Tcl_GetInteger", "Tcl_GetDouble", and "Tcl_GetBoolean"
+procedures.
+
+30. 7/22/90 Removed "Tcl_WatchInterp" procedure: doesn't seem to be
+necessary, since the same effect can be achieved with the deletion
+callbacks on individual commands. *** POTENTIAL INCOMPATIBILITY ***
+
+31. 7/23/90 Added variable tracing: Tcl_TraceVar, Tcl_UnTraceVar,
+and Tcl_VarTraceInfo procedures, "trace" command.
+
+32. 8/9/90 Mailed out list of all bug fixes since 3.3 release.
+
+33. 8/29/90 Fixed bugs in Tcl_Merge relating to backslashes and
+semi-colons. Mailed out patch.
+
+34. 9/3/90 Fixed bug in tclBasic.c: quotes weren't quoting ]'s.
+Mailed out patch.
+
+35. 9/19/90 Rewrote exec to always use files both for input and
+output to the process. The old pipe-based version didn't work if
+the exec'ed process forked a child and then exited: Tcl waited
+around for stdout to get closed, which didn't happen until the
+grandchild exited.
+
+36. 11/5/90 ERR_IN_PROGRESS flag wasn't being cleared soon enough
+in Tcl_Eval, allowing error messages from different commands to
+pile up in $errorInfo. Fixed by re-arranging code in Tcl_Eval that
+re-initializes result and ERR_IN_PROGRESS flag. Didn't mail out
+patch: changes too complicated to describe.
+
+37. 12/19/90 Added Tcl_VarEval procedure as a convenience for
+assembling and executing Tcl commands.
+
+38. 1/29/91 Fixed core leak in Tcl_AddErrorInfo. Also changed procedure
+and Tcl_Eval so that first call to Tcl_AddErrorInfo need not come from
+Tcl_Eval.
+
+----------------- Released version 5.0 with Tk ------------------
+
+39. 4/3/91 Removed change bars from manual entries, leaving only those
+that came after version 3.3 was released.
+
+40. 5/17/91 Changed tests to conform to Mary Ann May-Pumphrey's approach.
+
+41. 5/23/91 Massive revision to Tcl parser to simplify the implementation
+of string and floating-point support in expressions. Newlines inside
+[] are now treated as command separators rather than word separators
+(this makes newline treatment consistent throughout Tcl).
+*** POTENTIAL INCOMPATIBILITY ***
+
+42. 5/23/91 Massive rewrite of expression code to support floating-point
+values and simple string comparisons. The C interfaces to expression
+routines have changed (Tcl_Expr is replaced by Tcl_ExprLong, Tcl_ExprDouble,
+etc.), but all old Tcl expression strings should be accepted by the new
+expression code.
+*** POTENTIAL INCOMPATIBILITY ***
+
+43. 5/23/91 Modified tclHistory.c to check for negative "keep" value.
+
+44. 5/23/91 Modified Tcl_Backslash to handle backslash-newline. It now
+returns 0 to indicate that a backslash sequence should be replaced by
+no character at all.
+*** POTENTIAL INCOMPATIBILITY ***
+
+45. 5/29/91 Modified to use ANSI C function prototypes. Must set
+"USE_ANSI" switch when compiling to get prototypes.
+
+46. 5/29/91 Completed test suite by providing tests for all of the
+built-in Tcl commands.
+
+47. 5/29/91 Changed Tcl_Concat to eliminate leading and trailing
+white-space in each of the things it concatenates and to ignore
+elements that are empty or have only white space in them. This
+produces cleaner output from the "concat" command.
+*** POTENTIAL INCOMPATIBILITY ***
+
+48. 5/31/91 Changed "set" command and Tcl_SetVar procedure to return
+new value of variable.
+
+49. 6/1/91 Added "while" and "cd" commands.
+
+50. 6/1/91 Changed "exec" to delete the last character of program
+output if it is a newline. In most cases this makes it easier to
+process program-generated output.
+*** POTENTIAL INCOMPATIBILITY ***
+
+51. 6/1/91 Made sure that pointers are never used after freeing them.
+
+52. 6/1/91 Fixed bug in TclWordEnd where it wasn't dealing with
+[] inside quotes correctly.
+
+53. 6/8/91 Fixed exec.test to accept return values of either 1 or
+255 from "false" command.
+
+54. 7/6/91 Massive overhaul of variable management. Associative
+arrays now available, along with "unset" command (and Tcl_UnsetVar
+procedure). Variable traces have been completely reworked:
+interfaces different both from Tcl and C, and multiple traces may
+exist on same variable. Can no longer redefine existing local
+variable to be global. Calling sequences have changed slightly
+for Tcl_GetVar and Tcl_SetVar ("global" is now "flags"). Tcl_SetVar
+can fail and return a NULL result. New forms of variable-manipulation
+procedures: Tcl_GetVar2, Tcl_SetVar2, etc. Syntax of variable
+$-notation changed to support array indexing.
+*** POTENTIAL INCOMPATIBILITY ***
+
+55. 7/6/91 Added new list-manipulation procedures: Tcl_ScanElement,
+Tcl_ConvertElement, Tcl_AppendElement.
+
+56. 7/12/91 Created new procedure Tcl_EvalFile, which does most of the
+work of the "source" command.
+
+57. 7/20/91 Major reworking of "exec" command to allow pipelines,
+more redirection, background. Added new procedures Tcl_Fork,
+Tcl_WaitPids, Tcl_DetachPids, and Tcl_CreatePipeline. The old
+"< input" notation has been replaced by "<< input" ("<" is for
+redirection from a file). Also handles error returns and abnormal
+terminations (e.g. signals) differently.
+*** POTENTIAL INCOMPATIBILITY ***
+
+58. 7/21/91 Added "append" and "lappend" commands.
+
+59. 7/22/91 Reworked error messages and manual entries to use
+?x? as the notation for an optional argument x, instead of [x]. The
+bracket notation was often confused with the use of brackets for
+command substitution. Also modified error messages to be more
+consistent.
+
+60. 7/23/91 Tcl_DeleteCommand now returns an indication of whether
+or not the command actually existed, and the "rename" command uses
+this information to return an error if an attempt is made to delete
+a non-existent command.
+*** POTENTIAL INCOMPATIBILITY ***
+
+61. 7/25/91 Added new "errorCode" mechanism, along with procedures
+Tcl_SetErrorCode, Tcl_UnixError, and Tcl_ResetResult. Renamed
+Tcl_Return to Tcl_SetResult, but left a #define for Tcl_Return to
+avoid compatibility problems.
+
+62. 7/26/91 Extended "case" command with alternate syntax where all
+patterns and commands are together in a single list argument: makes
+it easier to write multi-line case statements.
+
+63. 7/27/91 Changed "print" command to perform tilde-substitution on
+the file name.
+
+64. 7/27/91 Added "tolower", "toupper", "trim", "trimleft", and "trimright"
+options to "string" command.
+
+65. 7/29/91 Added "atime", "mtime", "size", and "stat" options to "file"
+command.
+
+66. 8/1/91 Added "split" and "join" commands.
+
+67. 8/11/91 Added commands for file I/O, including "open", "close",
+"read", "gets", "puts", "flush", "eof", "seek", and "tell".
+
+68. 8/14/91 Switched to use a hash table for command lookups. Command
+abbreviations no longer have direct support in the Tcl interpreter, but
+it should be possible to simulate them with the auto-load features
+described below. The "noAbbrev" variable is no longer used by Tcl.
+*** POTENTIAL INCOMPATIBILITY ***
+
+68.5 8/15/91 Added support for "unknown" command, which can be used to
+complete abbreviations, auto-load library files, auto-exec shell
+commands, etc.
+
+69. 8/15/91 Added -nocomplain switch to "glob" command.
+
+70. 8/20/91 Added "info library" option and TCL_LIBRARY #define. Also
+added "info script" option.
+
+71. 8/20/91 Changed "file" command to take "option" argument as first
+argument (before file name), for consistency with other Tcl commands.
+*** POTENTIAL INCOMPATIBILITY ***
+
+72. 8/20/91 Changed format of information in $errorInfo variable:
+comments such as
+ ("while" body line 1)
+are now on separate lines from commands being executed.
+*** POTENTIAL INCOMPATIBILITY ***
+
+73. 8/20/91 Changed Tcl_AppendResult so that it (eventually) frees
+large buffers that it allocates.
+
+74. 8/21/91 Added "linsert", "lreplace", "lsearch", and "lsort"
+commands.
+
+75. 8/28/91 Added "incr" and "exit" commands.
+
+76. 8/30/91 Added "regexp" and "regsub" commands.
+
+77. 9/4/91 Changed "dynamic" field in interpreters to "freeProc" (procedure
+address). This allows for alternative storage managers.
+*** POTENTIAL INCOMPATIBILITY ***
+
+78. 9/6/91 Added "index", "length", and "range" options to "string"
+command. Added "lindex", "llength", and "lrange" commands.
+
+79. 9/8/91 Removed "index", "length", "print" and "range" commands.
+"Print" is redundant with "puts", but less general, and the other
+commands are replaced with the new commands described in change 78
+above.
+*** POTENTIAL INCOMPATIBILITY ***
+
+80. 9/8/91 Changed history revision to occur even when history command
+is nested; needed in order to allow "history" to be invoked from
+"unknown" procedure.
+
+81. 9/13/91 Changed "panic" not to use vfprintf (it's uglier and less
+general now, but makes it easier to run Tcl on systems that don't
+have vfprintf). Also changed "strerror" not to redeclare sys_errlist.
+
+82. 9/19/91 Lots of changes to improve portability to different UNIX
+systems, including addition of "config" script to adapt Tcl to the
+configuration of the system it's being compiled on.
+
+83. 9/22/91 Added "pwd" command.
+
+84. 9/22/91 Renamed manual pages so that their filenames are no more
+than 14 characters in length, moved to "doc" subdirectory.
+
+85. 9/24/91 Redid manual entries so they contain the supplemental
+macros that they need; can just print with "troff -man" or "man"
+now.
+
+86. 9/26/91 Created initial version of script library, including
+a version of "unknown" that does auto-loading, auto-execution, and
+abbreviation expansion. This library is used by tclTest
+automatically. See the "library" manual entry for details.
+
+----------------- Released version 6.0, 9/26/91 ------------------
+
+87. 9/30/91 Made "string tolower" and "string toupper" check case
+before converting: on some systems, "tolower" and "toupper" assume
+that character already has particular case.
+
+88. 9/30/91 Fixed bug in Tcl_SetResult: wasn't always setting freeProc
+correctly when called with NULL value. This tended to cause memory
+allocation errors later.
+
+89. 10/3/91 Added "upvar" command.
+
+90. 10/4/91 Changed "format" so that internally it converts %D to %ld,
+%U to %lu, %O to %lo, and %F to %f. This eliminates some compatibility
+problems on some machines without affecting behavior.
+
+91. 10/10/91 Fixed bug in "regsub" that caused core dumps with the -all
+option when the last match wasn't at the end of the string.
+
+92. 10/17/91 Fixed problems with backslash sequences: \r support was
+incomplete and \f and \v weren't supported at all.
+
+93. 10/24/91 Added Tcl_InitHistory procedure.
+
+94. 10/24/91 Changed "regexp" to store "-1 -1" in subMatchVars that
+don't match, rather than returning an error.
+
+95. 10/27/91 Modified "regexp" to return actual strings in matchVar
+and subMatchVars instead of indices. Added "-indices" switch to cause
+indices to be returned.
+*** POTENTIAL INCOMPATIBILITY ***
+
+96. 10/27/91 Fixed bug in "scan" where it used hardwired constants for
+sizes of floats and doubles instead of using "sizeof".
+
+97. 10/31/91 Fixed bug in tclParse.c where parse-related error messages
+weren't being storage-managed correctly, causing spurious free's.
+
+98. 10/31/91 Form feed and vertical tab characters are now considered
+to be space characters by the parser.
+
+99. 10/31/91 Added TCL_LEAVE_ERR_MSG flag to procedures like Tcl_SetVar.
+
+100. 11/7/91 Fixed bug in "case" where "in" argument couldn't be omitted
+if all case branches were embedded in a single list.
+
+101. 11/7/91 Switched to use "pid_t" and "uid_t" and other official
+POSIC types and function prototypes.
+
+----------------- Released version 6.1, 11/7/91 ------------------
+
+102. 12/2/91 Modified Tcl_ScanElement and Tcl_ConvertElement in several
+ways. First, allowed caller to request that only backslashes be used
+(no braces). Second, made Tcl_ConvertElement more aggressive in using
+backslashes for braces and quotes.
+
+103. 12/5/91 Added "type", "lstat", and "readlink" options to "file"
+command, plus added new "type" element to output of "stat" and "lstat"
+options.
+
+104. 12/10/91 Manual entries had first lines that caused "man" program
+to try weird preprocessor. Added blank comment lines to fix problem.
+
+105. 12/16/91 Fixed a few bugs in auto_mkindex proc: wasn't handling
+errors properly, and hadn't been upgraded for new "regexp" syntax.
+
+106. 1/2/92 Fixed bug in "file" command where it didn't properly handle
+a file names containing tildes where the indicated user doesn't exist.
+
+107. 1/2/92 Fixed lots of cases in tclUnixStr.c where two different
+errno symbols (e.g. EWOULDBLOCK and EAGAIN) have the same number; Tcl
+will only use one of them.
+
+108. 1/2/92 Lots of changes to configuration script to handle many more
+systems more gracefully. E.g. should now detect the bogus strtoul that
+comes with AIX and substitute Tcl's own version instead.
+
+----------------- Released version 6.2, 1/10/92 ------------------
+
+109. 1/20/92 Config didn't have code to actually use "uid_t" variable
+to set TCL_UIT_T #define.
+
+110. 2/10/92 Tcl_Eval didn't properly reset "numLevels" variable when
+too-deep recursion occurred.
+
+111. 2/29/92 Added "on" and "off" to keywords accepted by Tcl_GetBoolean.
+
+112. 3/19/92 Config wasn't installing default version of strtod.c for
+systems that don't have one in libc.a.
+
+113. 3/23/92 Fixed bug in tclExpr.c where numbers with leading "."s,
+like 0.75, couldn't be properly substituted into expressions with
+variable or command substitution.
+
+114. 3/25/92 Fixed bug in tclUnixAZ.c where "gets" command wasn't
+checking to make sure that it was able to write the variable OK.
+
+115. 4/16/92 Fixed bug in tclUnixAZ.c where "read" command didn't
+compute file size right for device files.
+
+116. 4/23/92 Fixed but in tclCmdMZ.c where "trace vinfo" was overwriting
+the trace command.
+
+----------------- Released version 6.3, 5/1/92 ------------------
+
+117. 5/1/92 Added Tcl_GlobalEval.
+
+118. 6/1/92 Changed auto-load facility to source files at global level.
+
+119. 6/8/92 Tcl_ParseVar wasn't always setting termPtr after errors, which
+sometimes caused core dumps.
+
+120. 6/21/92 Fixed bug in initialization of regexp pattern cache. This
+bug caused segmentation violations in regexp commands under some conditions.
+
+121. 6/22/92 Changed implementation of "glob" command to eliminate
+trailing slashes on directory names: they confuse some systems. There
+shouldn't be any user-visible changes in functionality except for names
+in error messages not having trailing slashes.
+
+122. 7/2/92 Fixed bug that caused 'string match ** ""' to return 0.
+
+123. 7/2/92 Fixed bug in Tcl_CreateCmdBuf where it wasn't initializing
+the buffer to an empty string.
+
+124. 7/6/92 Fixed bug in "case" command where it used NULL pattern string
+after errors in the "default" clause.
+
+125. 7/25/92 Speeded up auto_load procedure: don't reread all the index
+files unless the path has changed.
+
+126. 8/3/92 Changed tclUnix.h to define MAXPATHLEN from PATH_MAX, not
+_POSIX_PATH_MAX.
+
+----------------- Released version 6.4, 8/7/92 ------------------
+
+127. 8/10/92 Changed tclBasic.c so that comment lines can be continued by
+putting a backslash before the newline.
+
+128. 8/21/92 Modified "unknown" to allow the source-ing of a file for
+an auto-load to trigger other nested auto-loads, as long as there isn't
+any recursion on the same command name.
+
+129. 8/25/92 Modified "format" command to allow " " and "+" flags, and
+allow flags in any order.
+
+130. 9/14/92 Modified Tcl_ParseVar so that it doesn't actually attempt
+to look up the variable if "noEval" mode is in effect in the interpreter
+(it just parses the name). This avoids the errors that used to occur
+in statements like "expr {[info exists foo] && $foo}".
+
+131. 9/14/92 Fixed bug in "uplevel" command where it didn't output the
+correct error message if a level was specified but no command.
+
+132. 9/14/92 Renamed manual entries to have extensions like .3 and .n,
+and added "install" target to Makefile.
+
+133. 9/18/92 Modified "unknown" command to emulate !!, !<num>, and
+^<old>^<new> csh history substitutions.
+
+134. 9/21/92 Made the config script cleverer about figuring out which
+switches to pass to "nm".
+
+135. 9/23/92 Fixed tclVar.c to be sure to copy flags when growing variables.
+Used to forget about traces in progress and make extra recursive calls
+on trace procs.
+
+136. 9/28/92 Fixed bug in auto_reset where it was unsetting variables
+that might not exist.
+
+137. 10/7/92 Changed "parray" library procedure to print any array
+accessible to caller, local or global.
+
+138. 10/15/92 Fixed bug where propagation of new environment variable
+values among interpreters took N! time if there exist N interpreters.
+
+139. 10/16/92 Changed auto_reset procedure so that it also deletes any
+existing procedures that are in the auto_load index (the assumption is
+that they should be re-loaded to get the latest versions).
+
+140. 10/21/92 Fixed bug that caused lists to be incorrectly generated
+for elements that contained backslash-newline sequences.
+
+141. 12/9/92 Added support for TCL_LIBRARY environment variable: use
+it as library location if it's present.
+
+142. 12/9/92 Added "info complete" command, Tcl_CommandComplete procedure.
+
+143. 12/16/92 Changed the Makefile to check to make sure "config" has been
+run (can't run config directly from the Makefile because it modifies the
+Makefile; thus make has to be run again after running config).
+
+----------------- Released version 6.5, 12/17/92 ------------------
+
+144. 12/21/92 Changed config to look in several places for libc file.
+
+145. 12/23/92 Added "elseif" support to if. Also, "then", "else", and
+"elseif" may no longer be abbreviated.
+*** POTENTIAL INCOMPATIBILITY ***
+
+146. 12/28/92 Changed "puts" and "read" to support initial "-nonewline"
+switch instead of additional "nonewline" argument. The old form is
+still supported, but it is discouraged and is no longer documented.
+Also changed "puts" to make the file argument default to stdout: e.g.
+"puts foo" will print foo on standard output.
+
+147. 1/6/93 Fixed bug whereby backslash-newline wasn't working when
+typed interactively, or in "info complete".
+
+148. 1/22/93 Fixed bugs in "lreplace" and "linsert" where close
+quotes were being lost from last element before replacement or
+insertion.
+
+149. 1/29/93 Fixed bug in Tcl_AssembleCmd where it wasn't requiring
+a newline at the end of a line before considering a command to be
+complete. The bug caused some very long lines in script files to
+be processed as multiple separate commands.
+
+150. 1/29/93 Various changes in Makefile to add more configuration
+options, simplify installation, fix bugs (e.g. don't use -f switch
+for cp), etc.
+
+151. 1/29/93 Changed "name1" and "name2" identifiers to "part1" and
+"part2" to avoid name conflicts with stupid C++ implementations that
+use "name1" and "name2" in a reserved way.
+
+152. 2/1/93 Added "putenv" procedure to replace the standard system
+version so that it will work correctly with Tcl's environment handling.
+
+----------------- Released version 6.6, 2/5/93 ------------------
+
+153. 2/10/93 Fixed bugs in config script: missing "endif" in libc loop,
+and tried to use strncasecmp.c instead of strcasecmp.c.
+
+154. 2/10/93 Makefile improvements: added RANLIB variable for easier
+Sys-V configuration, added SHELL variable for SGI systems.
+
+----------------- Released version 6.7, 2/11/93 ------------------
+
+153. 2/6/93 Changes in backslash processing:
+ - \Cx, \Mx, \CMx, \e sequences no longer special
+ - \<newline> also eats up any space after the newline, replacing
+ the whole sequence with a single space character
+ - Hex sequences like \x24 are now supported, along with ANSI C's \a.
+ - "format" no longer does backslash processing on its format string
+ - there is no longer any special meaning to a 0 return value from
+ Tcl_Backslash
+ - unknown backslash sequences, like (e.g. \*), are replaced with
+ the following character (e.g. *), instead of just treating the
+ backslash as an ordinary character.
+*** POTENTIAL INCOMPATIBILITY ***
+
+154. 2/6/93 Updated all copyright notices. The meaning hasn't changed
+at all but the wording does a better job of protecting U.C. from
+liability (according to U.C. lawyers, anyway).
+
+155. 2/6/93 Changed "regsub" so that it overwrites the result variable
+in all cases, even if there is no match.
+*** POTENTIAL INCOMPATIBILITY ***
+
+156. 2/8/93 Added support for XPG3 %n$ conversion specifiers to "format"
+command.
+
+157. 2/17/93 Fixed bug in Tcl_Eval where errors due to infinite
+recursion could result in core dumps.
+
+158. 2/17/93 Improved the auto-load mechanism to deal gracefully (i.e.
+return an error) with a situation where a library file that supposedly
+defines a procedure doesn't actually define it.
+
+159. 2/17/93 Renamed Tcl_UnixError procedure to Tcl_PosixError, and
+changed errorCode variable usage to use POSIX as keyword instead of
+UNIX.
+*** POTENTIAL INCOMPATIBILITY ***
+
+160. 2/19/93 Changes to exec and process control:
+ - Added support for >>, >&, >>&, |&, <@, >@, and >&@ forms of redirection.
+ - When exec puts processes into background, it returns a list of
+ their pids as result.
+ - Added support for <file, >file, etc. (i.e. no space between
+ ">" and file name.
+ - Added -keepnewline option.
+ - Deleted Tcl_Fork and Tcl_WaitPids procedures (just use fork and
+ waitpid instead).
+ - Added waitpid compatibility procedure for systems that don't have
+ it.
+ - Added Tcl_ReapDetachedProcs procedure.
+ - Changed "exec" to return an error if there is stderr output, even
+ if the command returns a 0 exit status (it's always been documented
+ this way, but the implementation wasn't correct).
+ - If a process returns a non-zero exit status but doesn't generate
+ any diagnostic output, then Tcl generates an error message for it.
+*** POTENTIAL INCOMPATIBILITY ***
+
+161. 2/25/93 Fixed two memory-management problems having to do with
+managing the old result during variable trace callbacks.
+
+162. 3/1/93 Added dynamic string library: Tcl_DStringInit, Tcl_DStringAppend,
+Tcl_DStringFree, Tcl_DStringResult, etc.
+
+163. 3/1/93 Modified glob command to only return the names of files that
+exist, and to only return names ending in "/" if the file is a directory.
+*** POTENTIAL INCOMPATIBILITY ***
+
+164. 3/19/93 Modified not to use system calls like "read" directly,
+but instead to use special Tcl procedures that retry automatically
+if interrupted by signals.
+
+165. 4/3/93 Eliminated "noSep" argument to Tcl_AppendElement, plus
+TCL_NO_SPACE flag for Tcl_SetVar and Tcl_SetVar2.
+*** POTENTIAL INCOMPATIBILITY ***
+
+166. 4/3/93 Eliminated "flags" and "termPtr" arguments to Tcl_Eval.
+*** POTENTIAL INCOMPATIBILITY ***
+
+167. 4/3/93 Changes to expressions:
+ - The "expr" command now accepts multiple arguments, which are
+ concatenated together with space separators.
+ - Integers aren't automatically promoted to floating-point if they
+ overflow the word size: errors are generated instead.
+ - Tcl can now handle "NaN" and other special values if the underlying
+ library procedures handle them.
+ - When printing floating-point numbers, Tcl ensures that there is a "."
+ or "e" in the number, so it can't be treated as an integer accidentally.
+ The procedure Tcl_PrintDouble is available to provide this function
+ in other contexts. Also, the variable "tcl_precision" can be used
+ to set the precision for printing (must be a decimal number giving
+ digits of precision).
+ - Expressions now support transcendental and other functions, e.g. sin,
+ acos, hypot, ceil, and round. Can add new math functions with
+ Tcl_CreateMathFunc().
+ - Boolean expressions can now have any of the string values accepted
+ by Tcl_GetBoolean, such as "yes" or "no".
+*** POTENTIAL INCOMPATIBILITY ***
+
+168. 4/5/93 Changed Tcl_UnsetVar and Tcl_UnsetVar2 to return TCL_OK
+or TCL_ERROR instead of 0 or -1.
+*** POTENTIAL INCOMPATIBILITY ***
+
+169. 4/5/93 Eliminated Tcl_CmdBuf structure and associated procedures;
+can use Tcl_DStrings instead.
+*** POTENTIAL INCOMPATIBILITY ***
+
+170. 4/8/93 Changed interface to Tcl_TildeSubst to use a dynamic
+string for buffer space. This makes the procedure re-entrant and
+thread-safe, whereas it wasn't before.
+*** POTENTIAL INCOMPATIBILITY ***
+
+171. 4/14/93 Eliminated tclHash.h, and moved everything from it to
+tcl.h
+*** POTENTIAL INCOMPATIBILITY ***
+
+172. 4/15/93 Eliminated Tcl_InitHistory, made "history" command always
+be part of interpreter.
+*** POTENTIAL INCOMPATIBILITY ***
+
+173. 4/16/93 Modified "file" command so that "readable" option always
+exists, even on machines that don't support symbolic links (always returns
+same error as if the file wasn't a symbolic link).
+
+174. 4/26/93 Fixed bugs in "regsub" where ^ patterns didn't get handled
+right (pretended not to match when it really did, and looped infinitely
+if -all was specified).
+
+175. 4/29/93 Various improvements in the handling of variables:
+ - Can create variables and array elements during a read trace.
+ - Can delete variables during traces (note: unset traces will be
+ invoked when this happens).
+ - Can upvar to array elements.
+ - Can retarget an upvar to another variable by re-issuing the
+ upvar command with a different "other" variable.
+
+176. 5/3/93 Added Tcl_GetCommandInfo, which returns info about a Tcl
+command such as whether it exists and its ClientData. Also added
+Tcl_SetCommandInfo, which allows any of this information to be modified
+and also allows a command's delete procedure to have a different
+ClientData value than its command procedure.
+
+177. 5/5/93 Added Tcl_RegExpMatch procedure.
+
+178. 5/6/93 Fixed bug in "scan" where it didn't properly handle
+%% conversion specifiers. Also changed "scan" to use Tcl_PrintDouble
+for printing real values.
+
+179. 5/7/93 Added "-exact", "-glob", and "-regexp" options to "lsearch"
+command to allow different kinds of pattern matching.
+
+180. 5/7/93 Added many new switches to "lsort" to control the sorting
+process: "-ascii", "-integer", "-real", "-command", "-increasing",
+and "-decreasing".
+
+181. 5/10/93 Changes to file I/O:
+ - Modified "open" command to support a list of POSIX access flags
+ like {WRONLY CREAT TRUNC} in addition to current fopen-style
+ access modes. Also added "permissions" argument to set permissions
+ of newly-created files.
+ - Fixed Scott Bolte's bug (can close stdin etc. in application and
+ then re-open them with Tcl commands).
+ - Exported access to Tcl's file table with new procedures Tcl_EnterFile
+ and Tcl_GetOpenFile.
+
+182. 5/15/93 Added new "pid" command, which can be used to retrieve
+either the current process id or a list of the process ids in a
+pipeline opened with "open |..."
+
+183. 6/3/93 Changed to use GNU autoconfig for configuration instead of
+the home-brew "config" script. Also made many other configuration-related
+changes, such as using <unistd.h> instead of explicitly declaring system
+calls in tclUnix.h.
+
+184. 6/4/93 Fixed bug where core-dumps could occur if a procedure
+redefined itself (the memory for the procedure's body could get
+reallocated in the middle of evaluating the body); implemented
+simple reference count mechanism.
+
+185. 6/5/93 Changed tclIndex file format in two ways: (a) it's now
+eval-ed instead of parsed, which makes it 3-4x faster; (b) the entries
+in auto_index are now commands to evaluate, which allows commands to
+be loaded in different ways such as dynamic-loading of C code. The
+old tclIndex file format is still supported.
+
+186. 6/7/93 Eliminated tclTest program, added new "tclsh" program
+that is more like wish (allows script files to be invoked automatically
+using "#!/usr/local/bin/tclsh", makes arguments available to script,
+etc.). Added support for Tcl_AppInit plus default version; this
+allows new Tcl applications to be created without modifying the
+main program for tclsh.
+
+187. 6/7/93 Fixed bug in TclWordEnd that kept backslash-newline from
+working correctly in some cases during interactive input.
+
+188. 6/9/93 Added Tcl_LinkVar and related procedures, which automatically
+keep a Tcl variable in sync with a C variable.
+
+189. 6/16/93 Increased maximum nesting depth from 100 to 1000.
+
+190. 6/16/93 Modified "trace var" command so that error messages from
+within traces are returned properly as the result of the variable
+access, instead of the generic "access disallowed by trace command"
+message.
+
+191. 6/16/93 Added Tcl_CallWhenDeleted to provide callbacks when an
+interpreter is deleted (same functionality as Tcl_WatchInterp, which
+used to exist in versions before 6.0).
+
+193. 6/16/93 Added "-code" argument to "return" command; it's there
+primarily for completeness, so that procedures implementing control
+constructs can reflect exceptional conditions back to their callers.
+
+194. 6/16/93 Split up Tcl.n to make separate manual entries for each
+Tcl command. Tcl.n now contains a summary of the language syntax.
+
+195. 6/17/93 Added new "switch" command to replace "case": allows
+alternate forms of pattern matching (exact, glob, regexp), replaces
+pattern lists with single patterns (but you can use "-" bodies to
+share one body among several patterns), eliminates "in" noise word.
+"Case" command is now obsolete.
+
+196. 6/17/93 Changed the "exec", "glob", "regexp", and "regsub" commands
+to include a "--" switch. All initial arguments starting with "-" are now
+treated as switches unless a "--" switch is present to end the list.
+*** POTENTIAL INCOMPATIBILITY ***
+
+197. 6/17/93 Changed auto-exec so that the subprocess gets stdin, stdout,
+and stderr from the parent. This allows truly interactive sub-processes
+(e.g. vi) to be auto-exec'ed from a tcl shell command line.
+
+198. 6/18/93 Added patchlevel.h, for use in coordinating future patch
+releases, and also added "info patchlevel" command to make the patch
+level available to Tcl scripts.
+
+199. 6/19/93 Modified "glob" command so that a leading "//" in a name
+gets left as is (this is needed for systems like Apollos where "//" is
+the super-root; Tcl used to collapse the two slashes into a single
+slash).
+
+200. 7/7/93 Added Tcl_SetRecursionLimit procedure so that the maximum
+allowable nesting depth can be controlled for an interpreter from C.
+
+----------------- Released version 7.0 Beta 1, 7/9/93 ------------------
+
+201. 7/12/93 Modified Tcl_GetInt and tclExpr.c so that full-precision
+unsigned integers can be specified without overflow errors.
+
+202. 7/12/93 Configuration changes: eliminate leading blank line in
+configure script; provide separate targets in Makefile for installing
+binary and non-binary information; check for size_t and a few other
+potentially missing typedefs; don't put tclAppInit.o into libtcl.a;
+better checks for matherr support.
+
+203. 7/14/93 Changed tclExpr.c to check the termination pointer before
+errno after strtod calls, to avoid problems with some versions of
+strtod that set errno in unexpected ways.
+
+204. 7/16/93 Changed "scan" command to be more ANSI-conformant:
+eliminated %F, %D, etc., added code to ignore "l", "h", and "L"
+modifiers but always convert %e, %f, and %g with implicit "l";
+also added support for %u and %i. Also changed "format" command
+to eliminate %D, %U, %O, and add %i.
+*** POTENTIAL INCOMPATIBILITY ***
+
+205. 7/17/93 Changed "uplevel" and "upvar" so that they can be used
+from global level to global level: this used to generate an error.
+
+206. 7/19/93 Renamed "setenv", "putenv", and "unsetenv" procedures
+to avoid conflicts with system procedures with the same names. If
+you want Tcl's procedures to override the system procedures, do it
+in the Makefile (instructions are in the Makefile).
+*** POTENTIAL INCOMPATIBILITY ***
+
+----------------- Released version 7.0 Beta 2, 7/21/93 ------------------
+
+207. 7/21/93 Fixed bug in tclVar.c where freed memory was accidentally
+used if a procedure returned an element of a local array.
+
+208. 7/22/93 Fixed bug in "unknown" where it didn't properly handle
+errors occurring in the "auto_load" procedure, leaving its state
+inconsistent.
+
+209. 7/23/93 Changed exec's ">2" redirection operator to "2>" for
+consistency with sh. This is incompatible with earlier beta releases
+of 7.0 but not with pre-7.0 releases, which didn't support either
+operator.
+
+210. 7/28/93 Changed backslash-newline handling so that the resulting
+space character *is* treated as a word separator unless the backslash
+sequence is in quotes or braces. This is incompatible with 7.0b1
+and 7.0b2 but is more compatible with pre-7.0 versions that the b1
+and b2 releases were.
+
+211. 7/28/93 Eliminated Tcl_LinkedVarWritable, added TCL_LINK_READ_ONLY to
+Tcl_LinkVar to accomplish same purpose. This change is incompatible
+with earlier beta releases, but not with releases before Tcl 7.0.
+
+212. 7/29/93 Renamed regexp C functions so they won't clash with POSIX
+regexp functions that use the same name.
+
+213. 8/3/93 Added "-errorinfo" and "-errorcode" options to "return"
+command: these allow for much better handling of the errorInfo
+and errorCode variables in some cases.
+
+214. 8/12/93 Changed "expr" so that % always returns a remainder with
+the same sign as the divisor and absolute value smaller than the
+divisor.
+
+215. 8/14/93 Turned off auto-exec in "unknown" unless the command
+was typed interactively. This means you must use "exec" when
+invoking subprocesses, unless it's a command that's typed interactively.
+*** POTENTIAL INCOMPATIBILITY ***
+
+216. 8/14/93 Added support for tcl_prompt1 and tcl_prompt2 variables
+to tclMain.c: makes prompts user-settable.
+
+217. 8/14/93 Added asynchronous handlers (Tcl_AsyncCreate etc.) so
+that signals can be taken cleanly by Tcl applications.
+
+218. 8/16/93 Moved information about open files from the interpreter
+structure to global variables so that a file can be opened in one
+interpreter and read or written in another.
+
+219. 8/16/93 Removed ENV_FLAGS from Makefile, so that there's no
+official support for overriding setenv, unsetenv, and putenv.
+
+220. 8/20/93 Various configuration improvements: coerce chars
+to unsigned chars before using macros like isspace; source ~/.tclshrc
+file during initialization if it exists and program is running
+interactively; allow there to be directories in auto_path that don't
+exist or don't have tclIndex files (ignore them); added Tcl_Init
+procedure and changed Tcl_AppInit to call it.
+
+221. 8/21/93 Fixed bug in expr where "+", "-", and " " were all
+getting treated as integers with value 0.
+
+222. 8/26/93 Added "tcl_interactive" variable to tclsh.
+
+223. 8/27/93 Added procedure Tcl_FilePermissions to return whether a
+given file can be read or written or both. Modified Tcl_EnterFile
+to take a permissions mask rather than separate read and write arguments.
+
+224. 8/28/93 Fixed performance bug in "glob" command (unnecessary call
+to "access" for each file caused a 5-10x slow-down for big directories).
+
+----------------- Released version 7.0 Beta 3, 8/28/93 ------------------
+
+225. 9/9/93 Renamed regexp.h to tclRegexp.h to avoid conflicts with system
+include file by same name.
+
+226. 9/9/93 Added Tcl_DontCallWhenDeleted.
+
+227. 9/16/93 Changed not to call exit C procedure directly; instead
+always invoke "exit" Tcl command so that application can redefine the
+command to do additional cleanup.
+
+228. 9/17/93 Changed auto-exec to handle names that contain slashes
+(i.e. don't use PATH for them).
+
+229. 9/23/93 Fixed bug in "read" and "gets" commands where they didn't
+clear EOF conditions.
+
+----------------- Released version 7.0, 9/29/93 ------------------
+
+230. 10/7/93 "Scan" command wasn't properly aligning things in memory,
+so segmentation faults could arise under some circumstances.
+
+231. 10/7/93 Fixed bug in Tcl_ConvertElement where it forgot to
+backslash leading curly brace when creating lists.
+
+232. 10/7/93 Eliminated dependency of tclMain.c on tclInt.h and
+tclUnix.h, so that people can copy the file out of the Tcl source
+directory to make modified private versions.
+
+233. 10/8/93 Fixed bug in auto-loader that reversed the priority order
+of entries in auto_path for new-style index files. Now things are
+back to the way they were before 3.0: first in auto_path is always
+highest priority.
+
+234. 10/13/93 Fixed bug where Tcl_CommandComplete didn't recognize
+comments and treat them as such. Thus if you typed the line
+ # {
+interactively, Tcl would think that the command wasn't complete and
+wait for more input before evaluating the script.
+
+235. 10/14/93 Fixed bug where "regsub" didn't set the output variable
+if the input string was empty.
+
+236. 10/23/93 Fixed bug where Tcl_CreatePipeline didn't close off enough
+file descriptors in child processes, causing children not to exit
+properly in some cases.
+
+237. 10/28/93 Changed "list" and "concat" commands not to generate
+errors if given zero arguments, but instead to just return an empty
+string.
+
+----------------- Released version 7.1, 11/4/93 ------------------
+
+Note: there is no 7.2 release. It was flawed and was thus withdrawn
+shortly after it was released.
+
+238. 11/10/93 TclMain.c didn't compile on some systems because of
+R_OK in call to "access". Changed to eliminate call to "access".
+
+----------------- Released version 7.3, 11/26/93 ------------------
diff --git a/vendor/x11iraf/obm/Tcl/compat/README b/vendor/x11iraf/obm/Tcl/compat/README
new file mode 100644
index 00000000..9af4285a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/README
@@ -0,0 +1,6 @@
+This directory contains various header and code files that are
+used make Tcl compatible with various releases of UNIX and UNIX-like
+systems. Typically, files from this directory are used to compile
+Tcl when a system doesn't contain the corresponding files or when
+they are known to be incorrect. When the whole world becomes POSIX-
+compliant this directory should be unnecessary.
diff --git a/vendor/x11iraf/obm/Tcl/compat/dirent.h b/vendor/x11iraf/obm/Tcl/compat/dirent.h
new file mode 100644
index 00000000..d6adf95f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/dirent.h
@@ -0,0 +1,37 @@
+/*
+ * dirent.h --
+ *
+ * This file is a replacement for <dirent.h> in systems that
+ * support the old BSD-style <sys/dir.h> with a "struct direct".
+ *
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/dirent.h,v 1.2 93/03/19 15:25:03 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _DIRENT
+#define _DIRENT
+
+#include <sys/dir.h>
+
+#define dirent direct
+
+#endif /* _DIRENT */
diff --git a/vendor/x11iraf/obm/Tcl/compat/dirent2.h b/vendor/x11iraf/obm/Tcl/compat/dirent2.h
new file mode 100644
index 00000000..2f61c354
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/dirent2.h
@@ -0,0 +1,73 @@
+/*
+ * dirent.h --
+ *
+ * Declarations of a library of directory-reading procedures
+ * in the POSIX style ("struct dirent").
+ *
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/dirent2.h,v 1.2 93/03/19 15:25:09 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _DIRENT
+#define _DIRENT
+
+#ifndef _TCL
+#include <tcl.h>
+#endif
+
+/*
+ * Dirent structure, which holds information about a single
+ * directory entry.
+ */
+
+#define MAXNAMLEN 255
+#define DIRBLKSIZ 512
+
+struct dirent {
+ long d_ino; /* Inode number of entry */
+ short d_reclen; /* Length of this record */
+ short d_namlen; /* Length of string in d_name */
+ char d_name[MAXNAMLEN + 1]; /* Name must be no longer than this */
+};
+
+/*
+ * State that keeps track of the reading of a directory (clients
+ * should never look inside this structure; the fields should
+ * only be accessed by the library procedures).
+ */
+
+typedef struct _dirdesc {
+ int dd_fd;
+ long dd_loc;
+ long dd_size;
+ char dd_buf[DIRBLKSIZ];
+} DIR;
+
+/*
+ * Procedures defined for reading directories:
+ */
+
+extern void closedir _ANSI_ARGS_((DIR *dirp));
+extern DIR * opendir _ANSI_ARGS_((char *name));
+extern struct dirent * readdir _ANSI_ARGS_((DIR *dirp));
+
+#endif /* _DIRENT */
diff --git a/vendor/x11iraf/obm/Tcl/compat/float.h b/vendor/x11iraf/obm/Tcl/compat/float.h
new file mode 100644
index 00000000..e5b0cb01
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/float.h
@@ -0,0 +1,30 @@
+/*
+ * float.h --
+ *
+ * This is a dummy header file to #include in Tcl when there
+ * is no float.h in /usr/include. Right now this file is empty:
+ * Tcl contains #ifdefs to deal with the lack of definitions;
+ * all it needs is for the #include statement to work.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/float.h,v 1.1 93/04/15 16:10:39 ouster Exp $ SPRITE (Berkeley)
+ */
diff --git a/vendor/x11iraf/obm/Tcl/compat/getcwd.c b/vendor/x11iraf/obm/Tcl/compat/getcwd.c
new file mode 100644
index 00000000..f693a53e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/getcwd.c
@@ -0,0 +1,63 @@
+/*
+ * getcwd.c --
+ *
+ * This file provides an implementation of the getcwd procedure
+ * that uses getwd, for systems with getwd but without getcwd.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/getcwd.c,v 1.2 93/07/12 14:00:59 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+extern char *getwd _ANSI_ARGS_((char *pathname));
+
+char *
+getcwd(buf, size)
+ char *buf; /* Where to put path for current directory. */
+ size_t size; /* Number of bytes at buf. */
+{
+ char realBuffer[MAXPATHLEN+1];
+ int length;
+
+ if (getwd(realBuffer) == NULL) {
+ /*
+ * There's not much we can do besides guess at an errno to
+ * use for the result (the error message in realBuffer isn't
+ * much use...).
+ */
+
+ errno = EACCES;
+ return NULL;
+ }
+ length = strlen(realBuffer);
+ if (length >= size) {
+ errno = ERANGE;
+ return NULL;
+ }
+ strcpy(buf, realBuffer);
+ return buf;
+}
+
diff --git a/vendor/x11iraf/obm/Tcl/compat/limits.h b/vendor/x11iraf/obm/Tcl/compat/limits.h
new file mode 100644
index 00000000..dec6d99e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/limits.h
@@ -0,0 +1,34 @@
+/*
+ * limits.h --
+ *
+ * This is a dummy header file to #include in Tcl when there
+ * is no limits.h in /usr/include. There are only a few
+ * definitions here; also see tclUnix.h, which already
+ * #defines some of the things here if they're not arleady
+ * defined.
+ *
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/limits.h,v 1.3 93/04/08 16:03:59 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#define LONG_MIN 0x80000000
+#define LONG_MAX 0x7fffffff
diff --git a/vendor/x11iraf/obm/Tcl/compat/opendir.c b/vendor/x11iraf/obm/Tcl/compat/opendir.c
new file mode 100644
index 00000000..5602350f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/opendir.c
@@ -0,0 +1,106 @@
+/*
+ * opendir.c --
+ *
+ * This file provides dirent-style directory-reading procedures
+ * for V7 Unix systems that don't have such procedures. The
+ * origin of this code is unclear, but it seems to have come
+ * originally from Larry Wall.
+ *
+ */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+#undef DIRSIZ
+#define DIRSIZ(dp) \
+ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+/*
+ * open a directory.
+ */
+DIR *
+opendir(name)
+char *name;
+{
+ register DIR *dirp;
+ register int fd;
+ char *myname;
+
+ myname = ((*name == '\0') ? "." : name);
+ if ((fd = open(myname, 0, 0)) == -1)
+ return NULL;
+ if ((dirp = (DIR *)ckalloc(sizeof(DIR))) == NULL) {
+ close (fd);
+ return NULL;
+ }
+ dirp->dd_fd = fd;
+ dirp->dd_loc = 0;
+ return dirp;
+}
+
+/*
+ * read an old style directory entry and present it as a new one
+ */
+#ifndef pyr
+#define ODIRSIZ 14
+
+struct olddirect {
+ ino_t od_ino;
+ char od_name[ODIRSIZ];
+};
+#else /* a Pyramid in the ATT universe */
+#define ODIRSIZ 248
+
+struct olddirect {
+ long od_ino;
+ short od_fill1, od_fill2;
+ char od_name[ODIRSIZ];
+};
+#endif
+
+/*
+ * get next entry in a directory.
+ */
+struct dirent *
+readdir(dirp)
+register DIR *dirp;
+{
+ register struct olddirect *dp;
+ static struct dirent dir;
+
+ for (;;) {
+ if (dirp->dd_loc == 0) {
+ dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+ DIRBLKSIZ);
+ if (dirp->dd_size <= 0)
+ return NULL;
+ }
+ if (dirp->dd_loc >= dirp->dd_size) {
+ dirp->dd_loc = 0;
+ continue;
+ }
+ dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
+ dirp->dd_loc += sizeof(struct olddirect);
+ if (dp->od_ino == 0)
+ continue;
+ dir.d_ino = dp->od_ino;
+ strncpy(dir.d_name, dp->od_name, ODIRSIZ);
+ dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
+ dir.d_namlen = strlen(dir.d_name);
+ dir.d_reclen = DIRSIZ(&dir);
+ return (&dir);
+ }
+}
+
+/*
+ * close a directory.
+ */
+void
+closedir(dirp)
+register DIR *dirp;
+{
+ close(dirp->dd_fd);
+ dirp->dd_fd = -1;
+ dirp->dd_loc = 0;
+ ckfree((char *) dirp);
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/stdlib.h b/vendor/x11iraf/obm/Tcl/compat/stdlib.h
new file mode 100644
index 00000000..9aec51a5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/stdlib.h
@@ -0,0 +1,59 @@
+/*
+ * stdlib.h --
+ *
+ * Declares facilities exported by the "stdlib" portion of
+ * the C library. This file isn't complete in the ANSI-C
+ * sense; it only declares things that are needed by Tcl.
+ * This file is needed even on many systems with their own
+ * stdlib.h (e.g. SunOS) because not all stdlib.h files
+ * declare all the procedures needed here (such as strtod).
+ *
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/stdlib.h,v 1.8 93/03/19 15:25:31 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _STDLIB
+#define _STDLIB
+
+#include <tcl.h>
+
+extern void abort _ANSI_ARGS_((void));
+extern double atof _ANSI_ARGS_((CONST char *string));
+extern int atoi _ANSI_ARGS_((CONST char *string));
+extern long atol _ANSI_ARGS_((CONST char *string));
+extern char * calloc _ANSI_ARGS_((unsigned int numElements,
+ unsigned int size));
+extern void exit _ANSI_ARGS_((int status));
+extern int free _ANSI_ARGS_((char *blockPtr));
+extern char * getenv _ANSI_ARGS_((CONST char *name));
+extern char * malloc _ANSI_ARGS_((unsigned int numBytes));
+extern void qsort _ANSI_ARGS_((VOID *base, int n, int size,
+ int (*compar)(CONST VOID *element1, CONST VOID
+ *element2)));
+extern char * realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes));
+extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr));
+extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr,
+ int base));
+extern unsigned long strtoul _ANSI_ARGS_((CONST char *string,
+ char **endPtr, int base));
+
+#endif /* _STDLIB */
diff --git a/vendor/x11iraf/obm/Tcl/compat/strerror.c b/vendor/x11iraf/obm/Tcl/compat/strerror.c
new file mode 100644
index 00000000..773b9d5e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/strerror.c
@@ -0,0 +1,484 @@
+/*
+ * strerror.c --
+ *
+ * Source code for the "strerror" library routine.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strerror.c,v 1.8 93/10/28 16:32:16 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+/*
+ *----------------------------------------------------------------------
+ *
+ * strerror --
+ *
+ * Map an integer error number into a printable string.
+ *
+ * Results:
+ * The return value is a pointer to a string describing
+ * error. The first character of string isn't capitalized.
+ *
+ * Side effects:
+ * Each call to this procedure may overwrite the value returned
+ * by the previous call.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+strerror(error)
+ int error; /* Integer identifying error (must be
+ * one of the officially-defined Sprite
+ * errors, as defined in errno.h). */
+{
+ static char msg[50];
+
+#ifndef NO_SYS_ERRLIST
+ if ((error <= sys_nerr) && (error > 0)) {
+ return sys_errlist[error];
+ }
+#else
+ switch (error) {
+#ifdef E2BIG
+ case E2BIG: return "argument list too long";
+#endif
+#ifdef EACCES
+ case EACCES: return "permission denied";
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return "address already in use";
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return "can't assign requested address";
+#endif
+#ifdef EADV
+ case EADV: return "advertise error";
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return "address family not supported by protocol family";
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return "no more processes";
+#endif
+#ifdef EALIGN
+ case EALIGN: return "EALIGN";
+#endif
+#ifdef EALREADY
+ case EALREADY: return "operation already in progress";
+#endif
+#ifdef EBADE
+ case EBADE: return "bad exchange descriptor";
+#endif
+#ifdef EBADF
+ case EBADF: return "bad file number";
+#endif
+#ifdef EBADFD
+ case EBADFD: return "file descriptor in bad state";
+#endif
+#ifdef EBADMSG
+ case EBADMSG: return "not a data message";
+#endif
+#ifdef EBADR
+ case EBADR: return "bad request descriptor";
+#endif
+#ifdef EBADRPC
+ case EBADRPC: return "RPC structure is bad";
+#endif
+#ifdef EBADRQC
+ case EBADRQC: return "bad request code";
+#endif
+#ifdef EBADSLT
+ case EBADSLT: return "invalid slot";
+#endif
+#ifdef EBFONT
+ case EBFONT: return "bad font file format";
+#endif
+#ifdef EBUSY
+ case EBUSY: return "mount device busy";
+#endif
+#ifdef ECHILD
+ case ECHILD: return "no children";
+#endif
+#ifdef ECHRNG
+ case ECHRNG: return "channel number out of range";
+#endif
+#ifdef ECOMM
+ case ECOMM: return "communication error on send";
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return "software caused connection abort";
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return "connection refused";
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return "connection reset by peer";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+ case EDEADLK: return "resource deadlock avoided";
+#endif
+#ifdef EDEADLOCK
+ case EDEADLOCK: return "resource deadlock avoided";
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return "destination address required";
+#endif
+#ifdef EDIRTY
+ case EDIRTY: return "mounting a dirty fs w/o force";
+#endif
+#ifdef EDOM
+ case EDOM: return "math argument out of range";
+#endif
+#ifdef EDOTDOT
+ case EDOTDOT: return "cross mount point";
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return "disk quota exceeded";
+#endif
+#ifdef EDUPPKG
+ case EDUPPKG: return "duplicate package name";
+#endif
+#ifdef EEXIST
+ case EEXIST: return "file already exists";
+#endif
+#ifdef EFAULT
+ case EFAULT: return "bad address in system call argument";
+#endif
+#ifdef EFBIG
+ case EFBIG: return "file too large";
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return "host is down";
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return "host is unreachable";
+#endif
+#ifdef EIDRM
+ case EIDRM: return "identifier removed";
+#endif
+#ifdef EINIT
+ case EINIT: return "initialization error";
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return "operation now in progress";
+#endif
+#ifdef EINTR
+ case EINTR: return "interrupted system call";
+#endif
+#ifdef EINVAL
+ case EINVAL: return "invalid argument";
+#endif
+#ifdef EIO
+ case EIO: return "I/O error";
+#endif
+#ifdef EISCONN
+ case EISCONN: return "socket is already connected";
+#endif
+#ifdef EISDIR
+ case EISDIR: return "illegal operation on a directory";
+#endif
+#ifdef EISNAME
+ case EISNAM: return "is a name file";
+#endif
+#ifdef ELBIN
+ case ELBIN: return "ELBIN";
+#endif
+#ifdef EL2HLT
+ case EL2HLT: return "level 2 halted";
+#endif
+#ifdef EL2NSYNC
+ case EL2NSYNC: return "level 2 not synchronized";
+#endif
+#ifdef EL3HLT
+ case EL3HLT: return "level 3 halted";
+#endif
+#ifdef EL3RST
+ case EL3RST: return "level 3 reset";
+#endif
+#ifdef ELIBACC
+ case ELIBACC: return "can not access a needed shared library";
+#endif
+#ifdef ELIBBAD
+ case ELIBBAD: return "accessing a corrupted shared library";
+#endif
+#ifdef ELIBEXEC
+ case ELIBEXEC: return "can not exec a shared library directly";
+#endif
+#ifdef ELIBMAX
+ case ELIBMAX: return
+ "attempting to link in more shared libraries than system limit";
+#endif
+#ifdef ELIBSCN
+ case ELIBSCN: return ".lib section in a.out corrupted";
+#endif
+#ifdef ELNRNG
+ case ELNRNG: return "link number out of range";
+#endif
+#ifdef ELOOP
+ case ELOOP: return "too many levels of symbolic links";
+#endif
+#ifdef EMFILE
+ case EMFILE: return "too many open files";
+#endif
+#ifdef EMLINK
+ case EMLINK: return "too many links";
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return "message too long";
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP: return "multihop attempted";
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return "file name too long";
+#endif
+#ifdef ENAVAIL
+ case ENAVAIL: return "not available";
+#endif
+#ifdef ENET
+ case ENET: return "ENET";
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return "network is down";
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return "network dropped connection on reset";
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return "network is unreachable";
+#endif
+#ifdef ENFILE
+ case ENFILE: return "file table overflow";
+#endif
+#ifdef ENOANO
+ case ENOANO: return "anode table overflow";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+ case ENOBUFS: return "no buffer space available";
+#endif
+#ifdef ENOCSI
+ case ENOCSI: return "no CSI structure available";
+#endif
+#ifdef ENODATA
+ case ENODATA: return "no data available";
+#endif
+#ifdef ENODEV
+ case ENODEV: return "no such device";
+#endif
+#ifdef ENOENT
+ case ENOENT: return "no such file or directory";
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return "exec format error";
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return "no locks available";
+#endif
+#ifdef ENOLINK
+ case ENOLINK: return "link has be severed";
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return "not enough memory";
+#endif
+#ifdef ENOMSG
+ case ENOMSG: return "no message of desired type";
+#endif
+#ifdef ENONET
+ case ENONET: return "machine is not on the network";
+#endif
+#ifdef ENOPKG
+ case ENOPKG: return "package not installed";
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return "bad proocol option";
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return "no space left on device";
+#endif
+#ifdef ENOSR
+ case ENOSR: return "out of stream resources";
+#endif
+#ifdef ENOSTR
+ case ENOSTR: return "not a stream device";
+#endif
+#ifdef ENOSYM
+ case ENOSYM: return "unresolved symbol name";
+#endif
+#ifdef ENOSYS
+ case ENOSYS: return "function not implemented";
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: return "block device required";
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return "socket is not connected";
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return "not a directory";
+#endif
+#ifdef ENOTEMPTY
+ case ENOTEMPTY: return "directory not empty";
+#endif
+#ifdef ENOTNAM
+ case ENOTNAM: return "not a name file";
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return "socket operation on non-socket";
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return "inappropriate device for ioctl";
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return "name not unique on network";
+#endif
+#ifdef ENXIO
+ case ENXIO: return "no such device or address";
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP: return "operation not supported on socket";
+#endif
+#ifdef EPERM
+ case EPERM: return "not owner";
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: return "protocol family not supported";
+#endif
+#ifdef EPIPE
+ case EPIPE: return "broken pipe";
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: return "too many processes";
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL: return "bad procedure for program";
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH: return "program version wrong";
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL: return "RPC program not available";
+#endif
+#ifdef EPROTO
+ case EPROTO: return "protocol error";
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return "protocol not suppored";
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return "protocol wrong type for socket";
+#endif
+#ifdef ERANGE
+ case ERANGE: return "math result unrepresentable";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+ case EREFUSED: return "EREFUSED";
+#endif
+#ifdef EREMCHG
+ case EREMCHG: return "remote address changed";
+#endif
+#ifdef EREMDEV
+ case EREMDEV: return "remote device";
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return "pathname hit remote file system";
+#endif
+#ifdef EREMOTEIO
+ case EREMOTEIO: return "remote i/o error";
+#endif
+#ifdef EREMOTERELEASE
+ case EREMOTERELEASE: return "EREMOTERELEASE";
+#endif
+#ifdef EROFS
+ case EROFS: return "read-only file system";
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH: return "RPC version is wrong";
+#endif
+#ifdef ERREMOTE
+ case ERREMOTE: return "object is remote";
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return "can't send afer socket shutdown";
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return "socket type not supported";
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return "invalid seek";
+#endif
+#ifdef ESRCH
+ case ESRCH: return "no such process";
+#endif
+#ifdef ESRMNT
+ case ESRMNT: return "srmount error";
+#endif
+#ifdef ESTALE
+ case ESTALE: return "stale remote file handle";
+#endif
+#ifdef ESUCCESS
+ case ESUCCESS: return "Error 0";
+#endif
+#ifdef ETIME
+ case ETIME: return "timer expired";
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return "connection timed out";
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return "too many references: can't splice";
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return "text file or pseudo-device busy";
+#endif
+#ifdef EUCLEAN
+ case EUCLEAN: return "structure needs cleaning";
+#endif
+#ifdef EUNATCH
+ case EUNATCH: return "protocol driver not attached";
+#endif
+#ifdef EUSERS
+ case EUSERS: return "too many users";
+#endif
+#ifdef EVERSION
+ case EVERSION: return "version mismatch";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK: return "operation would block";
+#endif
+#ifdef EXDEV
+ case EXDEV: return "cross-domain link";
+#endif
+#ifdef EXFULL
+ case EXFULL: return "message tables full";
+#endif
+ }
+#endif /* ! NO_SYS_ERRLIST */
+ sprintf(msg, "unknown error (%d)", error);
+ return msg;
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/string.h b/vendor/x11iraf/obm/Tcl/compat/string.h
new file mode 100644
index 00000000..863961f7
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/string.h
@@ -0,0 +1,78 @@
+/*
+ * string.h --
+ *
+ * Declarations of ANSI C library procedures for string handling.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/string.h,v 1.9 93/03/19 15:25:36 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _STRING
+#define _STRING
+
+#include <tcl.h>
+
+/*
+ * The following #include is needed to define size_t. (This used to
+ * include sys/stdtypes.h but that doesn't exist on older versions
+ * of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully
+ * it exists everywhere)
+ */
+
+#include <sys/types.h>
+
+extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n));
+extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2,
+ size_t n));
+extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n));
+extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f,
+ size_t n));
+extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n));
+
+extern int strcasecmp _ANSI_ARGS_((CONST char *s1,
+ CONST char *s2));
+extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src));
+extern char * strchr _ANSI_ARGS_((CONST char *string, int c));
+extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2));
+extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src));
+extern size_t strcspn _ANSI_ARGS_((CONST char *string,
+ CONST char *chars));
+extern char * strdup _ANSI_ARGS_((CONST char *string));
+extern char * strerror _ANSI_ARGS_((int error));
+extern size_t strlen _ANSI_ARGS_((CONST char *string));
+extern int strncasecmp _ANSI_ARGS_((CONST char *s1,
+ CONST char *s2, size_t n));
+extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src,
+ size_t numChars));
+extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2,
+ size_t nChars));
+extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src,
+ size_t numChars));
+extern char * strpbrk _ANSI_ARGS_((CONST char *string, char *chars));
+extern char * strrchr _ANSI_ARGS_((CONST char *string, int c));
+extern size_t strspn _ANSI_ARGS_((CONST char *string,
+ CONST char *chars));
+extern char * strstr _ANSI_ARGS_((CONST char *string,
+ CONST char *substring));
+extern char * strtok _ANSI_ARGS_((CONST char *s, CONST char *delim));
+
+#endif /* _STRING */
diff --git a/vendor/x11iraf/obm/Tcl/compat/strstr.c b/vendor/x11iraf/obm/Tcl/compat/strstr.c
new file mode 100644
index 00000000..4fd5e1bc
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/strstr.c
@@ -0,0 +1,84 @@
+/*
+ * strstr.c --
+ *
+ * Source code for the "strstr" library routine.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strstr.c,v 1.2 93/03/19 15:25:40 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strstr --
+ *
+ * Locate the first instance of a substring in a string.
+ *
+ * Results:
+ * If string contains substring, the return value is the
+ * location of the first matching instance of substring
+ * in string. If string doesn't contain substring, the
+ * return value is 0. Matching is done on an exact
+ * character-for-character basis with no wildcards or special
+ * characters.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+strstr(string, substring)
+ register char *string; /* String to search. */
+ char *substring; /* Substring to try to find in string. */
+{
+ register char *a, *b;
+
+ /* First scan quickly through the two strings looking for a
+ * single-character match. When it's found, then compare the
+ * rest of the substring.
+ */
+
+ b = substring;
+ if (*b == 0) {
+ return string;
+ }
+ for ( ; *string != 0; string += 1) {
+ if (*string != *b) {
+ continue;
+ }
+ a = string;
+ while (1) {
+ if (*b == 0) {
+ return string;
+ }
+ if (*a++ != *b++) {
+ break;
+ }
+ }
+ b = substring;
+ }
+ return (char *) 0;
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/strtod.c b/vendor/x11iraf/obm/Tcl/compat/strtod.c
new file mode 100644
index 00000000..eb4b3234
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/strtod.c
@@ -0,0 +1,273 @@
+/*
+ * strtod.c --
+ *
+ * Source code for the "strtod" library procedure.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strtod.c,v 1.6 93/07/23 16:31:17 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tcl.h"
+#ifdef NO_STDLIB_H
+# include "compat/stdlib.h"
+#else
+# include <stdlib.h>
+#endif
+#include <ctype.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int maxExponent = 511; /* Largest possible base 10 exponent. Any
+ * exponent larger than this will already
+ * produce underflow or overflow, so there's
+ * no need to worry about additional digits.
+ */
+static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
+ 10., /* is 10^2^i. Used to convert decimal */
+ 100., /* exponents into floating-point numbers. */
+ 1.0e4,
+ 1.0e8,
+ 1.0e16,
+ 1.0e32,
+ 1.0e64,
+ 1.0e128,
+ 1.0e256
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtod --
+ *
+ * This procedure converts a floating-point number from an ASCII
+ * decimal representation to internal double-precision format.
+ *
+ * Results:
+ * The return value is the double-precision floating-point
+ * representation of the characters in string. If endPtr isn't
+ * NULL, then *endPtr is filled in with the address of the
+ * next character after the last one that was part of the
+ * floating-point number.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+double
+strtod(string, endPtr)
+ CONST char *string; /* A decimal ASCII floating-point number,
+ * optionally preceded by white space.
+ * Must have form "-I.FE-X", where I is the
+ * integer part of the mantissa, F is the
+ * fractional part of the mantissa, and X
+ * is the exponent. Either of the signs
+ * may be "+", "-", or omitted. Either I
+ * or F may be omitted, or both. The decimal
+ * point isn't necessary unless F is present.
+ * The "E" may actually be an "e". E and X
+ * may both be omitted (but not just one).
+ */
+ char **endPtr; /* If non-NULL, store terminating character's
+ * address here. */
+{
+ int sign, expSign = FALSE;
+ double fraction, dblExp, *d;
+ register CONST char *p;
+ register int c;
+ int exp = 0; /* Exponent read from "EX" field. */
+ int fracExp = 0; /* Exponent that derives from the fractional
+ * part. Under normal circumstatnces, it is
+ * the negative of the number of digits in F.
+ * However, if I is very long, the last digits
+ * of I get dropped (otherwise a long I with a
+ * large negative exponent could cause an
+ * unnecessary overflow on I alone). In this
+ * case, fracExp is incremented one for each
+ * dropped digit. */
+ int mantSize; /* Number of digits in mantissa. */
+ int decPt; /* Number of mantissa digits BEFORE decimal
+ * point. */
+ CONST char *pExp; /* Temporarily holds location of exponent
+ * in string. */
+
+ /*
+ * Strip off leading blanks and check for a sign.
+ */
+
+ p = string;
+ while (isspace(*p)) {
+ p += 1;
+ }
+ if (*p == '-') {
+ sign = TRUE;
+ p += 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ sign = FALSE;
+ }
+
+ /*
+ * Count the number of digits in the mantissa (including the decimal
+ * point), and also locate the decimal point.
+ */
+
+ decPt = -1;
+ for (mantSize = 0; ; mantSize += 1)
+ {
+ c = *p;
+ if (!isdigit(c)) {
+ if ((c != '.') || (decPt >= 0)) {
+ break;
+ }
+ decPt = mantSize;
+ }
+ p += 1;
+ }
+
+ /*
+ * Now suck up the digits in the mantissa. Use two integers to
+ * collect 9 digits each (this is faster than using floating-point).
+ * If the mantissa has more than 18 digits, ignore the extras, since
+ * they can't affect the value anyway.
+ */
+
+ pExp = p;
+ p -= mantSize;
+ if (decPt < 0) {
+ decPt = mantSize;
+ } else {
+ mantSize -= 1; /* One of the digits was the point. */
+ }
+ if (mantSize > 18) {
+ fracExp = decPt - 18;
+ mantSize = 18;
+ } else {
+ fracExp = decPt - mantSize;
+ }
+ if (mantSize == 0) {
+ fraction = 0.0;
+ p = string;
+ goto done;
+ } else {
+ int frac1, frac2;
+ frac1 = 0;
+ for ( ; mantSize > 9; mantSize -= 1)
+ {
+ c = *p;
+ p += 1;
+ if (c == '.') {
+ c = *p;
+ p += 1;
+ }
+ frac1 = 10*frac1 + (c - '0');
+ }
+ frac2 = 0;
+ for (; mantSize > 0; mantSize -= 1)
+ {
+ c = *p;
+ p += 1;
+ if (c == '.') {
+ c = *p;
+ p += 1;
+ }
+ frac2 = 10*frac2 + (c - '0');
+ }
+ fraction = (1.0e9 * frac1) + frac2;
+ }
+
+ /*
+ * Skim off the exponent.
+ */
+
+ p = pExp;
+ if ((*p == 'E') || (*p == 'e')) {
+ p += 1;
+ if (*p == '-') {
+ expSign = TRUE;
+ p += 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ expSign = FALSE;
+ }
+ while (isdigit(*p)) {
+ exp = exp * 10 + (*p - '0');
+ p += 1;
+ }
+ }
+ if (expSign) {
+ exp = fracExp - exp;
+ } else {
+ exp = fracExp + exp;
+ }
+
+ /*
+ * Generate a floating-point number that represents the exponent.
+ * Do this by processing the exponent one bit at a time to combine
+ * many powers of 2 of 10. Then combine the exponent with the
+ * fraction.
+ */
+
+ if (exp < 0) {
+ expSign = TRUE;
+ exp = -exp;
+ } else {
+ expSign = FALSE;
+ }
+ if (exp > maxExponent) {
+ exp = maxExponent;
+ }
+ dblExp = 1.0;
+ for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
+ if (exp & 01) {
+ dblExp *= *d;
+ }
+ }
+ if (expSign) {
+ fraction /= dblExp;
+ } else {
+ fraction *= dblExp;
+ }
+
+done:
+ if (endPtr != NULL) {
+ *endPtr = (char *) p;
+ }
+
+ if (sign) {
+ return -fraction;
+ }
+ return fraction;
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/strtol.c b/vendor/x11iraf/obm/Tcl/compat/strtol.c
new file mode 100644
index 00000000..b5341a78
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/strtol.c
@@ -0,0 +1,99 @@
+/*
+ * strtol.c --
+ *
+ * Source code for the "strtol" library procedure.
+ *
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strtol.c,v 1.2 93/03/19 15:25:43 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include <ctype.h>
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtol --
+ *
+ * Convert an ASCII string into an integer.
+ *
+ * Results:
+ * The return value is the integer equivalent of string. If endPtr
+ * is non-NULL, then *endPtr is filled in with the character
+ * after the last one that was part of the integer. If string
+ * doesn't contain a valid integer value, then zero is returned
+ * and *endPtr is set to string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+long int
+strtol(string, endPtr, base)
+ char *string; /* String of ASCII digits, possibly
+ * preceded by white space. For bases
+ * greater than 10, either lower- or
+ * upper-case digits may be used.
+ */
+ char **endPtr; /* Where to store address of terminating
+ * character, or NULL. */
+ int base; /* Base for conversion. Must be less
+ * than 37. If 0, then the base is chosen
+ * from the leading characters of string:
+ * "0x" means hex, "0" means octal, anything
+ * else means decimal.
+ */
+{
+ register char *p;
+ int result;
+
+ /*
+ * Skip any leading blanks.
+ */
+
+ p = string;
+ while (isspace(*p)) {
+ p += 1;
+ }
+
+ /*
+ * Check for a sign.
+ */
+
+ if (*p == '-') {
+ p += 1;
+ result = -(strtoul(p, endPtr, base));
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ result = strtoul(p, endPtr, base);
+ }
+ if ((result == 0) && (endPtr != 0) && (*endPtr == p)) {
+ *endPtr = string;
+ }
+ return result;
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/strtoul.c b/vendor/x11iraf/obm/Tcl/compat/strtoul.c
new file mode 100644
index 00000000..8981e2c8
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/strtoul.c
@@ -0,0 +1,199 @@
+/*
+ * strtoul.c --
+ *
+ * Source code for the "strtoul" library procedure.
+ *
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strtoul.c,v 1.3 93/03/19 15:25:41 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include <ctype.h>
+
+/*
+ * The table below is used to convert from ASCII digits to a
+ * numerical equivalent. It maps from '0' through 'z' to integers
+ * (100 for non-digit characters).
+ */
+
+static char cvtIn[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */
+ 100, 100, 100, 100, 100, 100, 100, /* punctuation */
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35,
+ 100, 100, 100, 100, 100, 100, /* punctuation */
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtoul --
+ *
+ * Convert an ASCII string into an integer.
+ *
+ * Results:
+ * The return value is the integer equivalent of string. If endPtr
+ * is non-NULL, then *endPtr is filled in with the character
+ * after the last one that was part of the integer. If string
+ * doesn't contain a valid integer value, then zero is returned
+ * and *endPtr is set to string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+unsigned long int
+strtoul(string, endPtr, base)
+ char *string; /* String of ASCII digits, possibly
+ * preceded by white space. For bases
+ * greater than 10, either lower- or
+ * upper-case digits may be used.
+ */
+ char **endPtr; /* Where to store address of terminating
+ * character, or NULL. */
+ int base; /* Base for conversion. Must be less
+ * than 37. If 0, then the base is chosen
+ * from the leading characters of string:
+ * "0x" means hex, "0" means octal, anything
+ * else means decimal.
+ */
+{
+ register char *p;
+ register unsigned long int result = 0;
+ register unsigned digit;
+ int anyDigits = 0;
+
+ /*
+ * Skip any leading blanks.
+ */
+
+ p = string;
+ while (isspace(*p)) {
+ p += 1;
+ }
+
+ /*
+ * If no base was provided, pick one from the leading characters
+ * of the string.
+ */
+
+ if (base == 0)
+ {
+ if (*p == '0') {
+ p += 1;
+ if (*p == 'x') {
+ p += 1;
+ base = 16;
+ } else {
+
+ /*
+ * Must set anyDigits here, otherwise "0" produces a
+ * "no digits" error.
+ */
+
+ anyDigits = 1;
+ base = 8;
+ }
+ }
+ else base = 10;
+ } else if (base == 16) {
+
+ /*
+ * Skip a leading "0x" from hex numbers.
+ */
+
+ if ((p[0] == '0') && (p[1] == 'x')) {
+ p += 2;
+ }
+ }
+
+ /*
+ * Sorry this code is so messy, but speed seems important. Do
+ * different things for base 8, 10, 16, and other.
+ */
+
+ if (base == 8) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > 7) {
+ break;
+ }
+ result = (result << 3) + digit;
+ anyDigits = 1;
+ }
+ } else if (base == 10) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > 9) {
+ break;
+ }
+ result = (10*result) + digit;
+ anyDigits = 1;
+ }
+ } else if (base == 16) {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > ('z' - '0')) {
+ break;
+ }
+ digit = cvtIn[digit];
+ if (digit > 15) {
+ break;
+ }
+ result = (result << 4) + digit;
+ anyDigits = 1;
+ }
+ } else {
+ for ( ; ; p += 1) {
+ digit = *p - '0';
+ if (digit > ('z' - '0')) {
+ break;
+ }
+ digit = cvtIn[digit];
+ if (digit >= base) {
+ break;
+ }
+ result = result*base + digit;
+ anyDigits = 1;
+ }
+ }
+
+ /*
+ * See if there were any digits at all.
+ */
+
+ if (!anyDigits) {
+ p = string;
+ }
+
+ if (endPtr != 0) {
+ *endPtr = p;
+ }
+
+ return result;
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/tmpnam.c b/vendor/x11iraf/obm/Tcl/compat/tmpnam.c
new file mode 100644
index 00000000..48074716
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/tmpnam.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tmpnam.c 4.4 (Berkeley) 6/8/88";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <stdio.h>
+
+/*
+ * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars
+ * on some machines (like NeXT machines) and /usr/tmp will cause
+ * buffer overflows.
+ */
+
+#define P_tmpdir "/tmp"
+
+char *
+tmpnam(s)
+ char *s;
+{
+ static char name[50];
+ char *mktemp();
+
+ if (!s)
+ s = name;
+ (void)sprintf(s, "%s/XXXXXX", P_tmpdir);
+ return(mktemp(s));
+}
diff --git a/vendor/x11iraf/obm/Tcl/compat/unistd.h b/vendor/x11iraf/obm/Tcl/compat/unistd.h
new file mode 100644
index 00000000..a0f31dca
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/unistd.h
@@ -0,0 +1,83 @@
+/*
+ * unistd.h --
+ *
+ * Macros, CONSTants and prototypes for Posix conformance.
+ *
+ * Copyright 1989 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies. The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ * $Header: /user6/ouster/tcl/compat/RCS/unistd.h,v 1.4 93/09/02 16:35:38 ouster Exp $
+ */
+
+#ifndef _UNISTD
+#define _UNISTD
+
+#include <sys/types.h>
+#ifndef _TCL
+# include "tcl.h"
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * Strict POSIX stuff goes here. Extensions go down below, in the
+ * ifndef _POSIX_SOURCE section.
+ */
+
+extern void _exit _ANSI_ARGS_((int status));
+extern int access _ANSI_ARGS_((CONST char *path, int mode));
+extern int chdir _ANSI_ARGS_((CONST char *path));
+extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group));
+extern int close _ANSI_ARGS_((int fd));
+extern int dup _ANSI_ARGS_((int oldfd));
+extern int dup2 _ANSI_ARGS_((int oldfd, int newfd));
+extern int execl _ANSI_ARGS_((CONST char *path, ...));
+extern int execle _ANSI_ARGS_((CONST char *path, ...));
+extern int execlp _ANSI_ARGS_((CONST char *file, ...));
+extern int execv _ANSI_ARGS_((CONST char *path, char **argv));
+extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp));
+extern int execvp _ANSI_ARGS_((CONST char *file, char **argv));
+extern pid_t fork _ANSI_ARGS_((void));
+extern char *getcwd _ANSI_ARGS_((char *buf, size_t size));
+extern gid_t getegid _ANSI_ARGS_((void));
+extern uid_t geteuid _ANSI_ARGS_((void));
+extern gid_t getgid _ANSI_ARGS_((void));
+extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer));
+extern pid_t getpid _ANSI_ARGS_((void));
+extern uid_t getuid _ANSI_ARGS_((void));
+extern int isatty _ANSI_ARGS_((int fd));
+extern off_t lseek _ANSI_ARGS_((int fd, off_t offset, int whence));
+extern int pipe _ANSI_ARGS_((int *fildes));
+extern int read _ANSI_ARGS_((int fd, char *buf, size_t size));
+extern int setgid _ANSI_ARGS_((gid_t group));
+extern int setuid _ANSI_ARGS_((uid_t user));
+extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds));
+extern char *ttyname _ANSI_ARGS_((int fd));
+extern int unlink _ANSI_ARGS_((CONST char *path));
+extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size));
+
+#ifndef _POSIX_SOURCE
+extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *));
+extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group));
+extern int flock _ANSI_ARGS_((int fd, int operation));
+extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length));
+extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize));
+extern int setegid _ANSI_ARGS_((gid_t group));
+extern int seteuid _ANSI_ARGS_((uid_t user));
+extern int setreuid _ANSI_ARGS_((int ruid, int euid));
+extern int symlink _ANSI_ARGS_((CONST char *, CONST char *));
+extern int ttyslot _ANSI_ARGS_((void));
+extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length));
+extern int vfork _ANSI_ARGS_((void));
+#endif /* _POSIX_SOURCE */
+
+#endif /* _UNISTD */
+
diff --git a/vendor/x11iraf/obm/Tcl/compat/waitpid.c b/vendor/x11iraf/obm/Tcl/compat/waitpid.c
new file mode 100644
index 00000000..dd9713fa
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/compat/waitpid.c
@@ -0,0 +1,186 @@
+/*
+ * waitpid.c --
+ *
+ * This procedure emulates the POSIX waitpid kernel call on
+ * BSD systems that don't have waitpid but do have wait3.
+ * This code is based on a prototype version written by
+ * Mark Diekhans and Karl Lehenbauer.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/waitpid.c,v 1.5 93/07/01 15:25:18 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ * A linked list of the following structures is used to keep track
+ * of processes for which we received notification from the kernel,
+ * but the application hasn't waited for them yet (this can happen
+ * because wait may not return the process we really want). We
+ * save the information here until the application finally does
+ * wait for the process.
+ */
+
+typedef struct WaitInfo {
+ int pid; /* Pid of process that exited. */
+ WAIT_STATUS_TYPE status; /* Status returned when child exited
+ * or suspended. */
+ struct WaitInfo *nextPtr; /* Next in list of exited processes. */
+} WaitInfo;
+
+static WaitInfo *deadList = NULL; /* First in list of all dead
+ * processes. */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * waitpid --
+ *
+ * This procedure emulates the functionality of the POSIX
+ * waitpid kernel call, using the BSD wait3 kernel call.
+ * Note: it doesn't emulate absolutely all of the waitpid
+ * functionality, in that it doesn't support pid's of 0
+ * or < -1.
+ *
+ * Results:
+ * -1 is returned if there is an error in the wait kernel call.
+ * Otherwise the pid of an exited or suspended process is
+ * returned and *statusPtr is set to the status value of the
+ * process.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifdef waitpid
+# undef waitpid
+#endif
+
+int
+waitpid(pid, statusPtr, options)
+ int pid; /* The pid to wait on. Must be -1 or
+ * greater than zero. */
+ int *statusPtr; /* Where to store wait status for the
+ * process. */
+ int options; /* OR'ed combination of WNOHANG and
+ * WUNTRACED. */
+{
+ register WaitInfo *waitPtr, *prevPtr;
+ int result;
+ WAIT_STATUS_TYPE status;
+
+ if ((pid < -1) || (pid == 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * See if there's a suitable process that has already stopped or
+ * exited. If so, remove it from the list of exited processes and
+ * return its information.
+ */
+
+ for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL;
+ prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) {
+ if ((pid != waitPtr->pid) && (pid != -1)) {
+ continue;
+ }
+ if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) {
+ continue;
+ }
+ result = waitPtr->pid;
+ *statusPtr = *((int *) &waitPtr->status);
+ if (prevPtr == NULL) {
+ deadList = waitPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = waitPtr->nextPtr;
+ }
+ ckfree((char *) waitPtr);
+ return result;
+ }
+
+ /*
+ * Wait for any process to stop or exit. If it's an acceptable one
+ * then return it to the caller; otherwise store information about it
+ * in the list of exited processes and try again. On systems that
+ * have only wait but not wait3, there are several situations we can't
+ * handle, but we do the best we can (e.g. can still handle some
+ * combinations of options by invoking wait instead of wait3).
+ */
+
+ while (1) {
+#if NO_WAIT3
+ if (options & WNOHANG) {
+ return 0;
+ }
+ if (options != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ result = wait(&status);
+#else
+ result = wait3(&status, options, 0);
+#endif
+ if ((result == -1) && (errno == EINTR)) {
+ continue;
+ }
+ if (result <= 0) {
+ return result;
+ }
+
+ if ((pid != result) && (pid != -1)) {
+ goto saveInfo;
+ }
+ if (!(options & WUNTRACED) && (WIFSTOPPED(status))) {
+ goto saveInfo;
+ }
+ *statusPtr = *((int *) &status);
+ return result;
+
+ /*
+ * Can't return this info to caller. Save it in the list of
+ * stopped or exited processes. Tricky point: first check for
+ * an existing entry for the process and overwrite it if it
+ * exists (e.g. a previously stopped process might now be dead).
+ */
+
+ saveInfo:
+ for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) {
+ if (waitPtr->pid == result) {
+ waitPtr->status = status;
+ goto waitAgain;
+ }
+ }
+ waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo));
+ waitPtr->pid = result;
+ waitPtr->status = status;
+ waitPtr->nextPtr = deadList;
+ deadList = waitPtr;
+
+ waitAgain: continue;
+ }
+}
diff --git a/vendor/x11iraf/obm/Tcl/config.status b/vendor/x11iraf/obm/Tcl/config.status
new file mode 100755
index 00000000..d53efe58
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/config.status
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host apus:
+#
+# ./configure
+
+for arg
+do
+ case "$arg" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ exec /bin/sh ./configure ;;
+ *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;;
+ esac
+done
+
+trap 'rm -f Makefile; exit 1' 1 3 15
+INSTALL='cp'
+INSTALL_PROGRAM='$(INSTALL)'
+INSTALL_DATA='$(INSTALL)'
+RANLIB='echo ranlib'
+CC='cc'
+LIBOBJS=' tclMtherr.o'
+CPP='cc -E'
+LIBS=''
+srcdir='.'
+DEFS=' -DNO_GETWD=1 -DNO_WAIT3=1 -DHAVE_UNISTD_H=1 -DNO_UNION_WAIT=1 -DNEED_MATHERR=1'
+prefix=''
+exec_prefix=''
+prsub=''
+
+top_srcdir=$srcdir
+
+# Allow make-time overrides of the generated file list.
+test -n "$gen_files" || gen_files="Makefile"
+
+for file in .. $gen_files; do if [ "x$file" != "x.." ]; then
+ srcdir=$top_srcdir
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ dir=`echo $file|sed 's%/[^/][^/]*$%%'`
+ if test "$dir" != "$file"; then
+ test "$top_srcdir" != . && srcdir=$top_srcdir/$dir
+ test ! -d $dir && mkdir $dir
+ fi
+ echo creating $file
+ rm -f $file
+ echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file
+ sed -e "
+$prsub
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@CC@%$CC%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@CPP@%$CPP%g
+s%@LIBS@%$LIBS%g
+s%@srcdir@%$srcdir%g
+s%@DEFS@%$DEFS%
+" $top_srcdir/${file}.in >> $file
+fi; done
+
+exit 0
diff --git a/vendor/x11iraf/obm/Tcl/configure b/vendor/x11iraf/obm/Tcl/configure
new file mode 100755
index 00000000..61f0a4d3
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/configure
@@ -0,0 +1,1015 @@
+#!/bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf.
+# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create]
+# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET]
+# Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and
+# --with-PACKAGE unless this script has special code to handle it.
+
+
+for arg
+do
+ # Handle --exec-prefix with a space before the argument.
+ if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix=
+ # Handle --host with a space before the argument.
+ elif test x$next_host = xyes; then next_host=
+ # Handle --prefix with a space before the argument.
+ elif test x$next_prefix = xyes; then prefix=$arg; next_prefix=
+ # Handle --srcdir with a space before the argument.
+ elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir=
+ else
+ case $arg in
+ # For backward compatibility, also recognize exact --exec_prefix.
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*)
+ exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
+ next_exec_prefix=yes ;;
+
+ -gas | --gas | --ga | --g) ;;
+
+ -host=* | --host=* | --hos=* | --ho=* | --h=*) ;;
+ -host | --host | --hos | --ho | --h)
+ next_host=yes ;;
+
+ -nfp | --nfp | --nf) ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no)
+ no_create=1 ;;
+
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ next_prefix=yes ;;
+
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*)
+ srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s)
+ next_srcdir=yes ;;
+
+ -with-* | --with-*)
+ package=`echo $arg|sed 's/-*with-//'`
+ # Delete all the valid chars; see if any are left.
+ if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then
+ echo "configure: $package: invalid package name" >&2; exit 1
+ fi
+ eval "with_`echo $package|sed s/-/_/g`=1" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v)
+ verbose=yes ;;
+
+ *) ;;
+ esac
+ fi
+done
+
+trap 'rm -fr conftest* core; exit 1' 1 3 15
+
+# NLS nuisances.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = 'set' ; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = 'set' ; then LANG=C; export LANG; fi
+
+rm -f conftest*
+compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1'
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+unique_file=tcl.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ srcdirdefaulted=yes
+ # Try the directory containing this script, then `..'.
+ prog=$0
+ confdir=`echo $prog|sed 's%/[^/][^/]*$%%'`
+ test "X$confdir" = "X$prog" && confdir=.
+ srcdir=$confdir
+ if test ! -r $srcdir/$unique_file; then
+ srcdir=..
+ fi
+fi
+if test ! -r $srcdir/$unique_file; then
+ if test x$srcdirdefaulted = xyes; then
+ echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2
+ else
+ echo "configure: Can not find sources in \`${srcdir}'." 1>&2
+ fi
+ exit 1
+fi
+# Preserve a srcdir of `.' to avoid automounter screwups with pwd.
+# But we can't avoid them for `..', to make subdirectories work.
+case $srcdir in
+ .|/*|~*) ;;
+ *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute.
+esac
+
+# Save the original args to write them into config.status later.
+configure_args="$*"
+
+# Make sure to not get the incompatible SysV /etc/install and
+# /usr/sbin/install, which might be in PATH before a BSD-like install,
+# or the SunOS /usr/etc/install directory, or the AIX /bin/install,
+# or the AFS install, which mishandles nonexistent args, or
+# /usr/ucb/install on SVR4, which tries to use the nonexistent group
+# `staff'. On most BSDish systems install is in /usr/bin, not /usr/ucb
+# anyway. Sigh.
+if test "z${INSTALL}" = "z" ; then
+ echo checking for install
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ case $dir in
+ /etc|/usr/sbin|/usr/etc|/usr/afsws/bin|/usr/ucb) ;;
+ *)
+ if test -f $dir/installbsd; then
+ INSTALL="$dir/installbsd -c" # OSF1
+ INSTALL_PROGRAM='$(INSTALL)'
+ INSTALL_DATA='$(INSTALL) -m 644'
+ break
+ fi
+ if test -f $dir/install; then
+ if grep dspmsg $dir/install >/dev/null 2>&1; then
+ : # AIX
+ else
+ INSTALL="$dir/install -c"
+ INSTALL_PROGRAM='$(INSTALL)'
+ INSTALL_DATA='$(INSTALL) -m 644'
+ break
+ fi
+ fi
+ ;;
+ esac
+ done
+ IFS="$saveifs"
+fi
+INSTALL=${INSTALL-cp}
+INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'}
+INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'}
+
+if test -z "$RANLIB"; then
+ # Extract the first word of `ranlib', so it can be a program name with args.
+ set dummy ranlib; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+test -z "$RANLIB" && RANLIB=":"
+test -n "$RANLIB" -a -n "$verbose" && echo " setting RANLIB to $RANLIB"
+
+CC=${CC-cc}
+
+
+#--------------------------------------------------------------------
+# Supply substitutes for missing POSIX library procedures, or
+# set flags so Tcl uses alternate procedures.
+#--------------------------------------------------------------------
+
+for func in getcwd opendir strerror strstr
+do
+echo checking for ${func}
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_${func}) || defined (__stub___${func})
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char ${func}(); ${func}();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ LIBOBJS="$LIBOBJS ${func}.o"
+test -n "$verbose" && echo " using ${func}.o instead"
+fi
+rm -f conftest*
+
+done
+
+for func in strtol tmpnam waitpid
+do
+echo checking for ${func}
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_${func}) || defined (__stub___${func})
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char ${func}(); ${func}();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ LIBOBJS="$LIBOBJS ${func}.o"
+test -n "$verbose" && echo " using ${func}.o instead"
+fi
+rm -f conftest*
+
+done
+
+echo checking for gettimeofday
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gettimeofday) || defined (__stub___gettimeofday)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char gettimeofday(); gettimeofday();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo " defining NO_GETTOD"
+DEFS="$DEFS -DNO_GETTOD=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for getwd
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getwd) || defined (__stub___getwd)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char getwd(); getwd();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo " defining NO_GETWD"
+DEFS="$DEFS -DNO_GETWD=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for wait3
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_wait3) || defined (__stub___wait3)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char wait3(); wait3();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo " defining NO_WAIT3"
+DEFS="$DEFS -DNO_WAIT3=1"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# Supply substitutes for missing POSIX header files. Special
+# notes:
+# - Sprite's dirent.h exists but is bogus.
+# - stdlib.h doesn't define strtol, strtoul, or
+# strtod insome versions of SunOS
+# - some versions of string.h don't declare procedures such
+# as strstr
+#--------------------------------------------------------------------
+
+echo checking for unistd.h
+echo checking how to run the C preprocessor
+if test -z "$CPP"; then
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and ``${CC-cc}'' will simply confuse
+ # make. It must be expanded now.
+ CPP="${CC-cc} -E"
+ cat > conftest.c <<EOF
+#include <stdio.h>
+Syntax Error
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+test ".${verbose}" != "." && echo " setting CPP to $CPP"
+
+cat > conftest.c <<EOF
+#include <unistd.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+
+{
+test -n "$verbose" && \
+echo " defining HAVE_UNISTD_H"
+DEFS="$DEFS -DHAVE_UNISTD_H=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for dirent.h
+cat > conftest.c <<EOF
+#include <sys/types.h>
+#include <dirent.h>
+int main() { exit(0); }
+int t() {
+DIR *d;
+struct dirent *entryPtr;
+char *p;
+d = opendir("foobar");
+entryPtr = readdir(d);
+p = entryPtr->d_name;
+closedir(d);
+ }
+EOF
+if eval $compile; then
+ tcl_ok=1
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <tcl_ok=0>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "Sprite version.* NOT POSIX" conftest.out >/dev/null 2>&1; then
+ :
+fi
+rm -f conftest*
+
+if test $tcl_ok = 0; then
+
+{
+test -n "$verbose" && \
+echo " defining NO_DIRENT_H"
+DEFS="$DEFS -DNO_DIRENT_H=1"
+}
+
+fi
+echo checking for errno.h
+cat > conftest.c <<EOF
+#include <errno.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_ERRNO_H"
+DEFS="$DEFS -DNO_ERRNO_H=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for float.h
+cat > conftest.c <<EOF
+#include <float.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_FLOAT_H"
+DEFS="$DEFS -DNO_FLOAT_H=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for limits.h
+cat > conftest.c <<EOF
+#include <limits.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_LIMITS_H"
+DEFS="$DEFS -DNO_LIMITS_H=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for stdlib.h
+cat > conftest.c <<EOF
+#include <stdlib.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ tcl_ok=1
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <stdlib.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "strtol" conftest.out >/dev/null 2>&1; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <stdlib.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "strtoul" conftest.out >/dev/null 2>&1; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <stdlib.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "strtod" conftest.out >/dev/null 2>&1; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+if test $tcl_ok = 0; then
+
+{
+test -n "$verbose" && \
+echo " defining NO_STDLIB_H"
+DEFS="$DEFS -DNO_STDLIB_H=1"
+}
+
+fi
+echo checking for string.h
+cat > conftest.c <<EOF
+#include <string.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ tcl_ok=1
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <string.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "strstr" conftest.out >/dev/null 2>&1; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+echo '#include <string.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "strerror" conftest.out >/dev/null 2>&1; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+if test $tcl_ok = 0; then
+
+{
+test -n "$verbose" && \
+echo " defining NO_STRING_H"
+DEFS="$DEFS -DNO_STRING_H=1"
+}
+
+fi
+echo checking for sys/time.h
+cat > conftest.c <<EOF
+#include <sys/time.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_SYS_TIME_H"
+DEFS="$DEFS -DNO_SYS_TIME_H=1"
+}
+
+fi
+rm -f conftest*
+
+echo checking for sys/wait.h
+cat > conftest.c <<EOF
+#include <sys/wait.h>
+EOF
+err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"`
+if test -z "$err"; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_SYS_WAIT_H"
+DEFS="$DEFS -DNO_SYS_WAIT_H=1"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# On some systems strstr is broken: it returns a pointer even
+# even if the original string is empty.
+#--------------------------------------------------------------------
+
+cat > conftest.c <<EOF
+
+extern int strstr();
+int main()
+{
+ exit(strstr("\0test", "test") ? 1 : 0);
+}
+
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ LIBOBJS="$LIBOBJS strstr.o"
+fi
+rm -f conftest*
+
+#--------------------------------------------------------------------
+# Check for strtoul function. This is tricky because under some
+# versions of AIX strtoul returns an incorrect terminator
+# pointer for the string "0".
+#--------------------------------------------------------------------
+
+echo checking for strtoul
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strtoul) || defined (__stub___strtoul)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char strtoul(); strtoul();
+#endif
+ }
+EOF
+if eval $compile; then
+ tcl_ok=1
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+cat > conftest.c <<EOF
+
+extern int strtoul();
+int main()
+{
+ char *string = "0";
+ char *term;
+ int value;
+ value = strtoul(string, &term, 0);
+ if ((value != 0) || (term != (string+1))) {
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+if test $tcl_ok = 0; then
+ LIBOBJS="$LIBOBJS strtoul.o"
+fi
+
+#--------------------------------------------------------------------
+# Check for the strtod function. This is tricky because under
+# some versions of Linux it mis-parses the string "+".
+#--------------------------------------------------------------------
+
+echo checking for strtod
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strtod) || defined (__stub___strtod)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char strtod(); strtod();
+#endif
+ }
+EOF
+if eval $compile; then
+ tcl_ok=1
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+
+cat > conftest.c <<EOF
+
+extern double strtod();
+int main()
+{
+ char *string = "+";
+ char *term;
+ double value;
+ value = strtod(string, &term);
+ if (term != string) {
+ exit(1);
+ }
+ exit(0);
+}
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ tcl_ok=0
+fi
+rm -f conftest*
+if test $tcl_ok = 0; then
+ LIBOBJS="$LIBOBJS strtod.o"
+fi
+
+#--------------------------------------------------------------------
+# Check for various typedefs and provide substitutes if
+# they don't exist.
+#--------------------------------------------------------------------
+
+echo checking for mode_t in sys/types.h
+echo '#include <sys/types.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "mode_t" conftest.out >/dev/null 2>&1; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining mode_t to be int"
+DEFS="$DEFS -Dmode_t=int"
+}
+
+fi
+rm -f conftest*
+
+echo checking for pid_t in sys/types.h
+echo '#include <sys/types.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "pid_t" conftest.out >/dev/null 2>&1; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining pid_t to be int"
+DEFS="$DEFS -Dpid_t=int"
+}
+
+fi
+rm -f conftest*
+
+echo checking for size_t in sys/types.h
+echo '#include <sys/types.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "size_t" conftest.out >/dev/null 2>&1; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining size_t to be unsigned"
+DEFS="$DEFS -Dsize_t=unsigned"
+}
+
+fi
+rm -f conftest*
+
+echo checking for uid_t in sys/types.h
+echo '#include <sys/types.h>' > conftest.c
+eval "$CPP \$DEFS conftest.c > conftest.out 2>&1"
+if egrep "uid_t" conftest.out >/dev/null 2>&1; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining uid_t to be int"
+DEFS="$DEFS -Duid_t=int"
+}
+
+{
+test -n "$verbose" && \
+echo " defining gid_t to be int"
+DEFS="$DEFS -Dgid_t=int"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# If a system doesn't have an opendir function (man, that's old!)
+# then we have to supply a different version of dirent.h which
+# is compatible with the substitute version of opendir that's
+# provided. This version only works with V7-style directories.
+#--------------------------------------------------------------------
+
+echo checking for opendir
+cat > conftest.c <<EOF
+#include <ctype.h>
+int main() { exit(0); }
+int t() {
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_opendir) || defined (__stub___opendir)
+choke me
+#else
+/* Override any gcc2 internal prototype to avoid an error. */
+extern char opendir(); opendir();
+#endif
+ }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo " defining USE_DIRENT2_H"
+DEFS="$DEFS -DUSE_DIRENT2_H=1"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# Check for the existence of sys_errlist (this is only needed if
+# there's no strerror, but I don't know how to conditionalize the
+# check).
+#--------------------------------------------------------------------
+
+echo checking for sys_errlist
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() {
+extern char *sys_errlist[];
+extern int sys_nerr;
+sys_errlist[sys_nerr-1][0] = 0;
+ }
+EOF
+if eval $compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_SYS_ERRLIST"
+DEFS="$DEFS -DNO_SYS_ERRLIST=1"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# The check below checks whether <sys/wait.h> defines the type
+# "union wait" correctly. It's needed because of weirdness in
+# HP-UX where "union wait" is defined in both the BSD and SYS-V
+# environments. Checking the usability of WIFEXITED seems to do
+# the trick.
+#--------------------------------------------------------------------
+
+echo checking for union wait
+cat > conftest.c <<EOF
+#include <sys/types.h>
+#include <sys/wait.h>
+int main() { exit(0); }
+int t() {
+union wait x;
+WIFEXITED(x); /* Generates compiler error if WIFEXITED
+ * uses an int. */
+ }
+EOF
+if eval $compile; then
+ :
+else
+
+{
+test -n "$verbose" && \
+echo " defining NO_UNION_WAIT"
+DEFS="$DEFS -DNO_UNION_WAIT=1"
+}
+
+fi
+rm -f conftest*
+
+
+#--------------------------------------------------------------------
+# Check to see whether the system supports the matherr function
+# and its associated type "struct exception".
+#--------------------------------------------------------------------
+
+echo checking for matherr support
+cat > conftest.c <<EOF
+#include <math.h>
+int main() { exit(0); }
+int t() {
+struct exception x;
+x.type = DOMAIN;
+x.type = SING;
+ }
+EOF
+if eval $compile; then
+ LIBOBJS="$LIBOBJS tclMtherr.o";
+{
+test -n "$verbose" && \
+echo " defining NEED_MATHERR"
+DEFS="$DEFS -DNEED_MATHERR=1"
+}
+
+fi
+rm -f conftest*
+
+
+if test -n "$prefix"; then
+ test -z "$exec_prefix" && exec_prefix='${prefix}'
+ prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%"
+fi
+if test -n "$exec_prefix"; then
+ prsub="$prsub
+s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%exec_prefix\\1=\\2$exec_prefix%"
+fi
+cat >conftest.def <<EOF
+$DEFS
+EOF
+escape_ampersand_and_backslash='s%[&\\]%\\&%g'
+DEFS=`sed "$escape_ampersand_and_backslash" <conftest.def`
+rm -f conftest.def
+
+trap 'rm -f config.status; exit 1' 1 3 15
+echo creating config.status
+rm -f config.status
+cat > config.status <<EOF
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $configure_args
+
+for arg
+do
+ case "\$arg" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ exec /bin/sh $0 $configure_args ;;
+ *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;;
+ esac
+done
+
+trap 'rm -f Makefile; exit 1' 1 3 15
+INSTALL='$INSTALL'
+INSTALL_PROGRAM='$INSTALL_PROGRAM'
+INSTALL_DATA='$INSTALL_DATA'
+RANLIB='$RANLIB'
+CC='$CC'
+LIBOBJS='$LIBOBJS'
+CPP='$CPP'
+LIBS='$LIBS'
+srcdir='$srcdir'
+DEFS='$DEFS'
+prefix='$prefix'
+exec_prefix='$exec_prefix'
+prsub='$prsub'
+EOF
+cat >> config.status <<\EOF
+
+top_srcdir=$srcdir
+
+# Allow make-time overrides of the generated file list.
+test -n "$gen_files" || gen_files="Makefile"
+
+for file in .. $gen_files; do if [ "x$file" != "x.." ]; then
+ srcdir=$top_srcdir
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ dir=`echo $file|sed 's%/[^/][^/]*$%%'`
+ if test "$dir" != "$file"; then
+ test "$top_srcdir" != . && srcdir=$top_srcdir/$dir
+ test ! -d $dir && mkdir $dir
+ fi
+ echo creating $file
+ rm -f $file
+ echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file
+ sed -e "
+$prsub
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@CC@%$CC%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@CPP@%$CPP%g
+s%@LIBS@%$LIBS%g
+s%@srcdir@%$srcdir%g
+s%@DEFS@%$DEFS%
+" $top_srcdir/${file}.in >> $file
+fi; done
+
+exit 0
+EOF
+chmod +x config.status
+test -n "$no_create" || ./config.status
+
diff --git a/vendor/x11iraf/obm/Tcl/configure.in b/vendor/x11iraf/obm/Tcl/configure.in
new file mode 100755
index 00000000..f1fa256c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/configure.in
@@ -0,0 +1,182 @@
+dnl This file is an input file used by the GNU "autoconf" program to
+dnl generate the file "configure", which is run during Tcl installation
+dnl to configure the system for the local environment.
+AC_INIT(tcl.h)
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+CC=${CC-cc}
+AC_SUBST(CC)
+
+#--------------------------------------------------------------------
+# Supply substitutes for missing POSIX library procedures, or
+# set flags so Tcl uses alternate procedures.
+#--------------------------------------------------------------------
+
+AC_REPLACE_FUNCS(getcwd opendir strerror strstr)
+AC_REPLACE_FUNCS(strtol tmpnam waitpid)
+AC_FUNC_CHECK(gettimeofday, , AC_DEFINE(NO_GETTOD))
+AC_FUNC_CHECK(getwd, , AC_DEFINE(NO_GETWD))
+AC_FUNC_CHECK(wait3, , AC_DEFINE(NO_WAIT3))
+
+#--------------------------------------------------------------------
+# Supply substitutes for missing POSIX header files. Special
+# notes:
+# - Sprite's dirent.h exists but is bogus.
+# - stdlib.h doesn't define strtol, strtoul, or
+# strtod insome versions of SunOS
+# - some versions of string.h don't declare procedures such
+# as strstr
+#--------------------------------------------------------------------
+
+AC_UNISTD_H
+AC_COMPILE_CHECK(dirent.h, [#include <sys/types.h>
+#include <dirent.h>], [
+DIR *d;
+struct dirent *entryPtr;
+char *p;
+d = opendir("foobar");
+entryPtr = readdir(d);
+p = entryPtr->d_name;
+closedir(d);
+], tcl_ok=1, tcl_ok=0)
+AC_HEADER_EGREP([Sprite version.* NOT POSIX], tcl_ok=0)
+if test $tcl_ok = 0; then
+ AC_DEFINE(NO_DIRENT_H)
+fi
+AC_HEADER_CHECK(errno.h, , AC_DEFINE(NO_ERRNO_H))
+AC_HEADER_CHECK(float.h, , AC_DEFINE(NO_FLOAT_H))
+AC_HEADER_CHECK(limits.h, , AC_DEFINE(NO_LIMITS_H))
+AC_HEADER_CHECK(stdlib.h, tcl_ok=1, tcl_ok=0)
+AC_HEADER_EGREP(strtol, stdlib.h, , tcl_ok=0)
+AC_HEADER_EGREP(strtoul, stdlib.h, , tcl_ok=0)
+AC_HEADER_EGREP(strtod, stdlib.h, , tcl_ok=0)
+if test $tcl_ok = 0; then
+ AC_DEFINE(NO_STDLIB_H)
+fi
+AC_HEADER_CHECK(string.h, tcl_ok=1, tcl_ok=0)
+AC_HEADER_EGREP(strstr, string.h, , tcl_ok=0)
+AC_HEADER_EGREP(strerror, string.h, , tcl_ok=0)
+if test $tcl_ok = 0; then
+ AC_DEFINE(NO_STRING_H)
+fi
+AC_HEADER_CHECK(sys/time.h, , AC_DEFINE(NO_SYS_TIME_H))
+AC_HEADER_CHECK(sys/wait.h, , AC_DEFINE(NO_SYS_WAIT_H))
+
+#--------------------------------------------------------------------
+# On some systems strstr is broken: it returns a pointer even
+# even if the original string is empty.
+#--------------------------------------------------------------------
+
+AC_TEST_PROGRAM([
+extern int strstr();
+int main()
+{
+ exit(strstr("\0test", "test") ? 1 : 0);
+}
+], , [LIBOBJS="$LIBOBJS strstr.o"])
+
+#--------------------------------------------------------------------
+# Check for strtoul function. This is tricky because under some
+# versions of AIX strtoul returns an incorrect terminator
+# pointer for the string "0".
+#--------------------------------------------------------------------
+
+AC_FUNC_CHECK(strtoul, tcl_ok=1, tcl_ok=0)
+AC_TEST_PROGRAM([
+extern int strtoul();
+int main()
+{
+ char *string = "0";
+ char *term;
+ int value;
+ value = strtoul(string, &term, 0);
+ if ((value != 0) || (term != (string+1))) {
+ exit(1);
+ }
+ exit(0);
+}], , tcl_ok=0)
+if test $tcl_ok = 0; then
+ LIBOBJS="$LIBOBJS strtoul.o"
+fi
+
+#--------------------------------------------------------------------
+# Check for the strtod function. This is tricky because under
+# some versions of Linux it mis-parses the string "+".
+#--------------------------------------------------------------------
+
+AC_FUNC_CHECK(strtod, tcl_ok=1, tcl_ok=0)
+AC_TEST_PROGRAM([
+extern double strtod();
+int main()
+{
+ char *string = "+";
+ char *term;
+ double value;
+ value = strtod(string, &term);
+ if (term != string) {
+ exit(1);
+ }
+ exit(0);
+}], , tcl_ok=0)
+if test $tcl_ok = 0; then
+ LIBOBJS="$LIBOBJS strtod.o"
+fi
+
+#--------------------------------------------------------------------
+# Check for various typedefs and provide substitutes if
+# they don't exist.
+#--------------------------------------------------------------------
+
+AC_MODE_T
+AC_PID_T
+AC_SIZE_T
+AC_UID_T
+
+#--------------------------------------------------------------------
+# If a system doesn't have an opendir function (man, that's old!)
+# then we have to supply a different version of dirent.h which
+# is compatible with the substitute version of opendir that's
+# provided. This version only works with V7-style directories.
+#--------------------------------------------------------------------
+
+AC_FUNC_CHECK(opendir, , AC_DEFINE(USE_DIRENT2_H))
+
+#--------------------------------------------------------------------
+# Check for the existence of sys_errlist (this is only needed if
+# there's no strerror, but I don't know how to conditionalize the
+# check).
+#--------------------------------------------------------------------
+
+AC_COMPILE_CHECK(sys_errlist, , [
+extern char *sys_errlist[];
+extern int sys_nerr;
+sys_errlist[sys_nerr-1][0] = 0;
+], , AC_DEFINE(NO_SYS_ERRLIST))
+
+#--------------------------------------------------------------------
+# The check below checks whether <sys/wait.h> defines the type
+# "union wait" correctly. It's needed because of weirdness in
+# HP-UX where "union wait" is defined in both the BSD and SYS-V
+# environments. Checking the usability of WIFEXITED seems to do
+# the trick.
+#--------------------------------------------------------------------
+
+AC_COMPILE_CHECK([union wait], [#include <sys/types.h>
+#include <sys/wait.h>], [
+union wait x;
+WIFEXITED(x); /* Generates compiler error if WIFEXITED
+ * uses an int. */
+], , AC_DEFINE(NO_UNION_WAIT))
+
+#--------------------------------------------------------------------
+# Check to see whether the system supports the matherr function
+# and its associated type "struct exception".
+#--------------------------------------------------------------------
+
+AC_COMPILE_CHECK([matherr support], [#include <math.h>], [
+struct exception x;
+x.type = DOMAIN;
+x.type = SING;
+], [LIBOBJS="$LIBOBJS tclMtherr.o"; AC_DEFINE(NEED_MATHERR)])
+
+AC_OUTPUT(Makefile)
diff --git a/vendor/x11iraf/obm/Tcl/configure.info b/vendor/x11iraf/obm/Tcl/configure.info
new file mode 100755
index 00000000..1b15d613
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/configure.info
@@ -0,0 +1,81 @@
+This file provides more information about the "configure" script
+and how you can personalize it for your local environment.
+
+The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and
+creates the Makefile. It also creates a file `config.status'
+that you can run in the future to recreate the current configuration.
+
+Running `configure' takes a minute or two. While it is running, it
+prints some messages that tell what it is doing. If you don't want to
+see the messages, run `configure' with its standard output redirected
+to `/dev/null'; for example, `./configure >/dev/null'.
+
+To compile the package in a different directory from the one
+containing the source code, you must use a version of make that
+supports the VPATH variable, such as GNU make. `cd' to the directory
+where you want the object files and executables to go and run
+`configure'. `configure' automatically checks for the source code in
+the directory that `configure' is in and in `..'. If for some reason
+`configure' is not in the source code directory that you are
+configuring, then it will report that it can't find the source code.
+In that case, run `configure' with the option `--srcdir=DIR', where
+DIR is the directory that contains the source code.
+
+By default, `make install' will install the package's files in
+/usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify
+an installation prefix other than /usr/local by giving `configure' the
+option `--prefix=PATH'. Alternately, you can do so by giving a value
+for the `prefix' variable when you run `make', e.g.,
+ make prefix=/usr/gnu
+
+You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If
+you give `configure' the option `--exec_prefix=PATH' or set the
+`make' variable `exec_prefix' to PATH, the package will use PATH as
+the prefix for installing programs and libraries. Data files and
+documentation will still use the regular prefix. Normally, all files
+are installed using the regular prefix.
+
+You can tell `configure' to figure out the configuration for your
+system, and record it in `config.status', without actually configuring
+the package (creating `Makefile's and perhaps a configuration header
+file). To do this, give `configure' the `--no-create' option. Later,
+you can run `./config.status' to actually configure the package. This
+option is useful mainly in `Makefile' rules for updating `config.status'
+and `Makefile'. You can also give `config.status' the `--recheck'
+option, which makes it re-run `configure' with the same arguments you
+used before. This is useful if you change `configure'.
+
+`configure' ignores any other arguments that you give it.
+
+If your system requires unusual options for compilation or linking
+that `configure' doesn't know about, you can give `configure' initial
+values for some variables by setting them in the environment. In
+Bourne-compatible shells, you can do that on the command line like
+this:
+ CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure
+
+The `make' variables that you might want to override with environment
+variables when running `configure' are:
+
+(For these variables, any value given in the environment overrides the
+value that `configure' would choose:)
+CC C compiler program.
+ Default is `cc', or `gcc' if `gcc' is in your PATH.
+INSTALL Program to use to install files.
+ Default is `install' if you have it, `cp' otherwise.
+
+(For these variables, any value given in the environment is added to
+the value that `configure' chooses:)
+DEFS Configuration options, in the form `-Dfoo -Dbar ...'
+LIBS Libraries to link with, in the form `-lfoo -lbar ...'
+
+If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+The file `configure.in' is used as a template to create `configure' by
+a program called `autoconf'. You will only need it if you want to
+regenerate `configure' using a newer version of `autoconf'.
diff --git a/vendor/x11iraf/obm/Tcl/doc/AddErrInfo.3 b/vendor/x11iraf/obm/Tcl/doc/AddErrInfo.3
new file mode 100644
index 00000000..0ed3da3b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/AddErrInfo.3
@@ -0,0 +1,143 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/AddErrInfo.3,v 1.15 93/04/08 13:54:29 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_AddErrorInfo tclc
+.BS
+.SH NAME
+Tcl_AddErrorInfo, Tcl_SetErrorCode, Tcl_PosixError \- record information about errors
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_AddErrorInfo\fR(\fIinterp, message\fR)
+.sp
+\fBTcl_SetErrorCode\fR(\fIinterp, element, element, ...\fB (char *) NULL\fR)
+.sp
+char *
+\fBTcl_PosixError\fR(\fIinterp\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *message
+.AP Tcl_Interp *interp in
+Interpreter in which to record information.
+.AP char *message in
+Identifying string to record in \fBerrorInfo\fR variable.
+.AP char *element in
+String to record as one element of \fBerrorCode\fR variable.
+Last \fIelement\fR argument must be NULL.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures are used to manipulate two global variables
+that hold information about errors.
+The variable \fBerrorInfo\fR holds a stack trace of the
+operations that were in progress when an error occurred, and
+is intended to be human-readable.
+The variable \fBerrorCode\fR holds a list of items that
+are intended to be machine-readable.
+The first item in \fBerrorCode\fR identifies the class of
+.VS
+error that occurred (e.g. POSIX means an error occurred in
+.VE
+a POSIX system call) and additional elements in \fBerrorCode\fR
+hold additional pieces of information that depend on the class.
+See the Tcl overview manual entry for details on the various
+formats for \fBerrorCode\fR.
+.PP
+The \fBerrorInfo\fR variable is gradually built up as an
+error unwinds through the nested operations.
+Each time an error code is returned to \fBTcl_Eval\fR
+it calls the procedure \fBTcl_AddErrorInfo\fR to add
+additional text to \fBerrorInfo\fR describing the
+command that was being executed when the error occurred.
+By the time the error has been passed all the way back
+to the application, it will contain a complete trace
+of the activity in progress when the error occurred.
+.PP
+It is sometimes useful to add additional information to
+\fBerrorInfo\fR beyond what can be supplied automatically
+by \fBTcl_Eval\fR.
+\fBTcl_AddErrorInfo\fR may be used for this purpose:
+its \fImessage\fR argument contains an additional
+string to be appended to \fBerrorInfo\fR.
+For example, the \fBsource\fR command calls \fBTcl_AddErrorInfo\fR
+to record the name of the file being processed and the
+line number on which the error occurred; for Tcl procedures, the
+procedure name and line number within the procedure are recorded,
+and so on.
+The best time to call \fBTcl_AddErrorInfo\fR is just after
+\fBTcl_Eval\fR has returned \fBTCL_ERROR\fR.
+In calling \fBTcl_AddErrorInfo\fR, you may find it useful to
+use the \fBerrorLine\fR field of the interpreter (see the
+\fBTcl_Interp\fR manual entry for details).
+.PP
+The procedure \fBTcl_SetErrorCode\fR is used to set the
+\fBerrorCode\fR variable.
+Its \fIelement\fR arguments give one or more strings to record
+in \fBerrorCode\fR: each \fIelement\fR will become one item
+of a properly-formed Tcl list stored in \fBerrorCode\fR.
+\fBTcl_SetErrorCode\fR is typically invoked just before returning
+an error.
+If an error is returned without calling \fBTcl_SetErrorCode\fR
+then the Tcl interpreter automatically sets \fBerrorCode\fR
+to \fBNONE\fR.
+.PP
+\fBTcl_PosixError\fR
+.VS
+sets the \fBerrorCode\fR variable after an error in a POSIX kernel call.
+It reads the value of the \fBerrno\fR C variable and calls
+\fBTcl_SetErrorCode\fR to set \fBerrorCode\fR in the
+\fBPOSIX\fR format.
+In addition, \fBTcl_PosixError\fR returns a human-readable
+.VE
+diagnostic message for the error (this is the same value that
+will appear as the third element in \fBerrorCode\fR).
+It may be convenient to include this string as part of the
+error message returned to the application in \fIinterp->result\fR.
+.PP
+It is important to call the procedures described here rather than
+setting \fBerrorInfo\fR or \fBerrorCode\fR directly with
+\fBTcl_SetVar\fR.
+The reason for this is that the Tcl interpreter keeps information
+about whether these procedures have been called.
+For example, the first time \fBTcl_AppendResult\fR is called
+for an error, it clears the existing value of \fBerrorInfo\fR
+and adds the error message in \fIinterp->result\fR to the variable
+before appending \fImessage\fR; in subsequent calls, it just
+appends the new \fImessage\fR.
+When \fBTcl_SetErrorCode\fR is called, it sets a flag indicating
+that \fBerrorCode\fR has been set; this allows the Tcl interpreter
+to set \fBerrorCode\fR to \fBNONE\fB if it receives an error return
+when \fBTcl_SetErrorCode\fR hasn't been called.
+.PP
+If the procedure \fBTcl_ResetResult\fR is called, it clears all
+of the state associated with \fBerrorInfo\fR and \fBerrorCode\fR
+(but it doesn't actually modify the variables).
+If an error had occurred, this will clear the error state to
+make it appear as if no error had occurred after all.
+
+.SH "SEE ALSO"
+Tcl_ResetResult, Tcl_Interp
+
+.SH KEYWORDS
+error, stack, trace, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/AppInit.3 b/vendor/x11iraf/obm/Tcl/doc/AppInit.3
new file mode 100644
index 00000000..e957926b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/AppInit.3
@@ -0,0 +1,68 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/AppInit.3,v 1.2 93/06/07 15:11:46 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_AppInit tclc 7.0
+.BS
+.SH NAME
+Tcl_AppInit \- Perform application-specific initialization
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_AppInit\fR(\fIinterp\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp
+.AP Tcl_Interp *interp in
+Interpreter for the application.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_AppInit\fR is a procedure that is invoked by the main programs
+for Tcl applications such as \fBtclsh\fR and \fBwish\fR.
+Its purpose is to allow new Tcl applications to be created without
+modifying existing main programs such as those for \fBtclsh\fR
+and \fBwish\fR.
+To create a new application simply write a new version of
+\fBTcl_AppInit\fR to replace the default version provided by Tcl,
+then link your new \fBTcl_AppInit\fR with the Tcl library, which
+contains the main program from \fBtclsh\fR (be sure to specify the
+switch ``\fB\-u _main\fR'' to the linker to force it to use the
+version of \fBmain\fR from the Tcl library).
+.PP
+\fBTcl_AppInit\fR is invoked after other initialization in
+\fBmain\fR and before entering the main loop to process commands.
+Here are some examples of things that \fBTcl_AppInit\fR might do:
+.IP [1]
+Call initialization procedures for various packages used by
+the application.
+Each initialization procedure adds new commands to \fIinterp\fR
+for its package and performs other package-specific initialization.
+.IP [2]
+Process command-line arguments, which can be accessed from the
+Tcl variables \fBargv\fR and \fBargv0\fR in \fIinterp\fR.
+.IP [3]
+Invoke a startup script to initialize the application.
+
+.SH KEYWORDS
+application, argument, command, initialization, interpreter
diff --git a/vendor/x11iraf/obm/Tcl/doc/Async.3 b/vendor/x11iraf/obm/Tcl/doc/Async.3
new file mode 100644
index 00000000..730284d8
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Async.3
@@ -0,0 +1,172 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Async.3,v 1.5 93/09/17 15:21:50 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_AsyncCreate tclc 7.0
+.BS
+.SH NAME
+Tcl_AsyncCreate, Tcl_AsyncMark, Tcl_AsyncInvoke, Tcl_AsyncDelete \- handle asynchronous events
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+extern int \fBtcl_AsyncReady\fR;
+.sp
+Tcl_AsyncHandler
+\fBTcl_AsyncCreate\fR(\fIproc, clientData\fR)
+.sp
+\fBTcl_AsyncMark\fR(\fIasync\fR)
+.sp
+int
+\fBTcl_AsyncInvoke\fR(\fIinterp, code\fR)
+.sp
+\fBTcl_AsyncDelete\fR(\fIasync\fR)
+.SH ARGUMENTS
+.AS Tcl_AsyncHandler clientData
+.AP Tcl_AsyncProc *proc in
+Procedure to invoke to handle an asynchronous event.
+.AP ClientData clientData in
+One-word value to pass to \fIproc\fR.
+.AP Tcl_AsyncHandler async in
+Token for asynchronous event handler.
+.AP Tcl_Interp *interp in
+Tcl interpreter in which command was being evaluated when handler was
+invoked, or NULL if handler was invoked when there was no interpreter
+active.
+.AP int code in
+Completion code from command that just completed in \fIinterp\fR,
+or 0 if \fIinterp\fR is NULL.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures provide a safe mechanism for dealing with
+asynchronous events such as signals.
+If an event such as a signal occurs while a Tcl script is being
+evaluated then it isn't safe to take any substantive action to
+process the event.
+For example, it isn't safe to evaluate a Tcl script since the
+intepreter may already be in the middle of evaluating a script;
+it may not even be safe to allocate memory, since a memory
+allocation could have been in progress when the event occurred.
+The only safe approach is to set a flag indicating that the event
+occurred, then handle the event later when the world has returned
+to a clean state, such as after the current Tcl command completes.
+.PP
+\fBTcl_AsyncCreate\fR creates an asynchronous handler and returns
+a token for it.
+The asynchronous handler must be created before
+any occurrences of the asynchronous event that it is intended
+to handle (it is not safe to create a handler at the time of
+an event).
+When an asynchronous event occurs the code that detects the event
+(such as a signal handler) should call \fBTcl_AsyncMark\fR with the
+token for the handler.
+\fBTcl_AsyncMark\fR will mark the handler as ready to execute, but it
+will not invoke the handler immediately.
+Tcl will call the \fIproc\fR associated with the handler later, when
+the world is in a safe state, and \fIproc\fR can then carry out
+the actions associated with the asynchronous event.
+\fIProc\fR should have arguments and result that match the
+type \fBTcl_AsyncProc\fR:
+.nf
+.RS
+typedef int Tcl_AsyncProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR,
+int \fIcode\fR);
+.RE
+.RE
+.fi
+The \fIclientData\fR will be the same as the \fIclientData\fR
+argument passed to \fBTcl_AsyncCreate\fR when the handler was
+created.
+If \fIproc\fR is invoked just after a command has completed
+execution in an interpreter, then \fIinterp\fR will identify
+the interpreter in which the command was evaluated and
+\fIcode\fR will be the completion code returned by that
+command.
+The command's result will be present in \fIinterp->result\fR.
+When \fIproc\fR returns, whatever it leaves in \fIinterp->result\fR
+will be returned as the result of the command and the integer
+value returned by \fIproc\fR will be used as the new completion
+code for the command.
+.PP
+It is also possible for \fIproc\fR to be invoked when no interpreter
+is active.
+This can happen, for example, if an asynchronous event occurs while
+the application is waiting for interactive input or an X event.
+In this case \fIinterp\fR will be NULL and \fIcode\fR will be
+0, and the return value from \fIproc\fR will be ignored.
+.PP
+The procedure \fBTcl_AsyncInvoke\fR is called to invoke all of the
+handlers that are ready.
+The global variable \fBtcl_AsyncReady\fR will be non-zero whenever any
+asynchronous handlers are ready; it can be checked to avoid calls
+to \fBTcl_AsyncInvoke\fR when there are no ready handlers.
+Tcl checks \fBtcl_AsyncReady\fR after each command is evaluated
+and calls \fBTcl_AsyncInvoke\fR if needed.
+Applications may also call \fBTcl_AsyncInvoke\fR at interesting
+times for that application.
+For example, Tk's event handler checks \fBtcl_AsyncReady\fR
+after each event and calls \fBTcl_AsyncInvoke\fR if needed.
+The \fIinterp\fR and \fIcode\fR arguments to \fBTcl_AsyncInvoke\fR
+have the same meaning as for \fIproc\fR: they identify the active
+intepreter, if any, and the completion code from the command
+that just completed.
+.PP
+\fBTcl_AsyncDelete\fR removes an asynchronous handler so that
+its \fIproc\fR will never be invoked again.
+A handler can be deleted even when ready, and it will still
+not be invoked.
+.PP
+If multiple handlers become active at the same time, the
+handlers are invoked in the order they were created (oldest
+handler first).
+The \fIcode\fR and \fIinterp->result\fR for later handlers
+reflect the values returned by earlier handlers, so that
+the most recently created handler has last say about
+the interpreter's result and completion code.
+If new handlers become ready while handlers are executing,
+\fBTcl_AsyncInvoke\fR will invoke them all; at each point it
+invokes the highest-priority (oldest) ready handler, repeating
+this over and over until there are no longer any ready handlers.
+
+.SH WARNING
+.PP
+It is almost always a bad idea for an asynchronous event
+handler to modify \fIinterp->result\fR or return a code different
+from its \fIcode\fR argument.
+This sort of behavior can disrupt the execution of scripts in
+subtle ways and result in bugs that are extremely difficult
+to track down.
+If an asynchronous event handler needs to evaluate Tcl scripts
+then it should first save \fIinterp->result\fR plus the values
+of the variables \fBerrorInfo\fR and \fBerrorCode\fR (this can
+be done, for example, by storing them in dynamic strings).
+When the asynchronous handler is finished it should restore
+\fIinterp->result\fR, \fBerrorInfo\fR, and \fBerrorCode\fR,
+and return the \fIcode\fR argument.
+
+.SH KEYWORDS
+asynchronous event, handler, signal
diff --git a/vendor/x11iraf/obm/Tcl/doc/Backslash.3 b/vendor/x11iraf/obm/Tcl/doc/Backslash.3
new file mode 100644
index 00000000..e8b0325d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Backslash.3
@@ -0,0 +1,58 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Backslash.3,v 1.12 93/04/01 09:25:22 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_Backslash tclc
+.BS
+.SH NAME
+Tcl_Backslash \- parse a backslash sequence
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+char
+\fBTcl_Backslash\fR(\fIsrc, countPtr\fR)
+.SH ARGUMENTS
+.AS char *countPtr
+.AP char *src in
+Pointer to a string starting with a backslash.
+.AP int *countPtr out
+If \fIcountPtr\fR isn't NULL, \fI*countPtr\fR gets filled
+in with number of characters in the backslash sequence, including
+the backslash character.
+.BE
+
+.SH DESCRIPTION
+.PP
+This is a utility procedure used by several of the Tcl
+commands. It parses a backslash sequence and returns
+the single character corresponding to the sequence.
+\fBTcl_Backslash\fR modifies \fI*countPtr\fR to contain the number
+of characters in the backslash sequence.
+.PP
+See the Tcl manual entry for information on the valid
+backslash sequences.
+All of the sequences described in the Tcl
+manual entry are supported by \fBTcl_Backslash\fR.
+
+.SH KEYWORDS
+backslash, parse
diff --git a/vendor/x11iraf/obm/Tcl/doc/CallDel.3 b/vendor/x11iraf/obm/Tcl/doc/CallDel.3
new file mode 100644
index 00000000..1454ca36
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CallDel.3
@@ -0,0 +1,82 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CallDel.3,v 1.3 93/09/09 16:49:23 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CallWhenDeleted tclc 7.0
+.BS
+.SH NAME
+.na
+Tcl_CallWhenDeleted, Tcl_DontCallWhenDeleted \- Arrange for callback when interpreter is deleted
+.ad
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_CallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR)
+.sp
+\fBTcl_DontCallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR)
+.SH ARGUMENTS
+.AS Tcl_InterpDeleteProc clientData
+.AP Tcl_Interp *interp in
+Interpreter with which to associated callback.
+.AP Tcl_InterpDeleteProc *proc in
+Procedure to call when \fIinterp\fR is deleted.
+.AP ClientData clientData in
+Arbitrary one-word value to pass to \fIproc\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CallWhenDeleted\fR arranges for \fIproc\fR to be called by
+\fBTcl_DeleteInterp\fR if/when \fIinterp\fR is deleted at some future
+time. \fIProc\fR will be invoked just before the interpreter
+is deleted, but the interpreter will still be valid at the
+time of the call.
+\fIProc\fR should have arguments and result that match the
+type \fBTcl_InterpDeleteProc\fR:
+.nf
+.RS
+typedef int Tcl_InterpDeleteProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR);
+.RE
+.RE
+.fi
+The \fIclientData\fP and \fIinterp\fR parameters are
+copies of the \fIclientData\fP and \fIinterp\fR arguments given
+to \fBTcl_CallWhenDeleted\fR.
+Typically, \fIclientData\fR points to an application-specific
+data structure that \fIproc\fR uses to perform cleanup when an
+interpreter is about to go away.
+\fIProc\fR does not return a value.
+.PP
+\fBTcl_DontCallWhenDeleted\fR cancels a previous call to
+\fBTcl_CallWhenDeleted\fR with the same arguments, so that
+\fIproc\fR won't be called after all when \fIinterp\fR is
+deleted.
+If there is no deletion callback that matches \fIinterp\fR,
+\fIproc\fR, and \fIclientData\fR then the call to
+\fBTcl_DontCallWhenDeleted\fR has no effect.
+
+.SH KEYWORDS
+callback, delete, interpreter
diff --git a/vendor/x11iraf/obm/Tcl/doc/CmdCmplt.3 b/vendor/x11iraf/obm/Tcl/doc/CmdCmplt.3
new file mode 100644
index 00000000..968d6dfa
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CmdCmplt.3
@@ -0,0 +1,49 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CmdCmplt.3,v 1.1 93/04/05 10:04:55 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CmdComplete tclc
+.BS
+.SH NAME
+Tcl_CmdComplete \- Check for unmatched braces in a Tcl command
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_CommandComplete\fR(\fIcmd\fR)
+.SH ARGUMENTS
+.AS char *cmd
+.AP char *cmd in
+Command string to test for completeness.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CommandComplete\fR takes a Tcl command string
+as argument and determines whether it contains one or more
+complete commands (i.e. there are no unclosed quotes, braces,
+brackets, or variable references).
+If the command string is complete then it returns 1; otherwise it returns 0.
+
+.SH KEYWORDS
+complete command, partial command
diff --git a/vendor/x11iraf/obm/Tcl/doc/Concat.3 b/vendor/x11iraf/obm/Tcl/doc/Concat.3
new file mode 100644
index 00000000..85096014
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Concat.3
@@ -0,0 +1,64 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Concat.3,v 1.6 93/04/01 09:25:23 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_Concat tclc
+.BS
+.SH NAME
+Tcl_Concat \- concatenate a collection of strings
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+char *
+\fBTcl_Concat\fR(\fIargc, argv\fR)
+.SH ARGUMENTS
+.AP int argc in
+Number of strings.
+.AP char *argv[] in
+Array of strings to concatenate. Must have \fIargc\fR entries.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_Concat\fR is a utility procedure used by several of the
+Tcl commands. Given a collection of strings, it concatenates
+them together into a single string, with the original strings
+separated by spaces. This procedure behaves differently than
+\fBTcl_Merge\fR, in that the arguments are simply concatenated:
+no effort is made to ensure proper list structure.
+However, in most common usage the arguments will all be proper
+lists themselves; if this is true, then the result will also have
+proper list structure.
+.PP
+\fBTcl_Concat\fR eliminates leading and trailing white space as it
+copies strings from \fBargv\fR to the result. If an element of
+\fBargv\fR consists of nothing but white space, then that string
+is ignored entirely. This white-space removal was added to make
+the output of the \fBconcat\fR command cleaner-looking.
+.PP
+The result string is dynamically allocated
+using \fBmalloc()\fR; the caller must eventually release the space
+by calling \fBfree()\fR.
+
+.SH KEYWORDS
+concatenate, strings
diff --git a/vendor/x11iraf/obm/Tcl/doc/CrtCommand.3 b/vendor/x11iraf/obm/Tcl/doc/CrtCommand.3
new file mode 100644
index 00000000..9f61f49d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CrtCommand.3
@@ -0,0 +1,172 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CrtCommand.3,v 1.12 93/10/29 15:52:29 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CreateCommand tclc
+.BS
+.SH NAME
+Tcl_CreateCommand, Tcl_DeleteCommand, Tcl_GetCommandInfo, Tcl_SetCommandInfo \- implement new commands in C
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_CreateCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR)
+.sp
+int
+\fBTcl_DeleteCommand\fR(\fIinterp, cmdName\fR)
+.sp
+.VS
+int
+\fBTcl_GetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR)
+.sp
+int
+\fBTcl_SetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR)
+.VE
+.SH ARGUMENTS
+.AS Tcl_CmdDeleteProc **deleteProcPtr
+.AP Tcl_Interp *interp in
+Interpreter in which to create new command.
+.AP char *cmdName in
+Name of command.
+.AP Tcl_CmdProc *proc in
+Implementation of new command: \fIproc\fR will be called whenever
+\fIcmdName\fR is invoked as a command.
+.AP ClientData clientData in
+Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR.
+.AP Tcl_CmdDeleteProc *deleteProc in
+Procedure to call before \fIcmdName\fR is deleted from the interpreter;
+allows for command-specific cleanup. If NULL, then no procedure is
+called before the command is deleted.
+.AP Tcl_CmdInfo *infoPtr in/out
+.VS
+Pointer to structure containing various information about a
+Tcl command.
+.VE
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CreateCommand\fR defines a new command in \fIinterp\fR and associates
+it with procedure \fIproc\fR such that whenever \fIcmdName\fR is
+invoked as a Tcl command (via a call to \fBTcl_Eval\fR) the Tcl interpreter
+will call \fIproc\fR
+to process the command. If there is already a command \fIcmdName\fR
+associated with the interpreter, it is deleted. \fIProc\fP should
+have arguments and result that match the type \fBTcl_CmdProc\fR:
+.nf
+.RS
+typedef int Tcl_CmdProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR,
+int \fIargc\fR,
+char *\fIargv\fR[]);
+.RE
+.RE
+.fi
+When \fIproc\fR is invoked the \fIclientData\fP and \fIinterp\fR
+parameters will be copies of the \fIclientData\fP and \fIinterp\fR
+arguments given to \fBTcl_CreateCommand\fR.
+Typically, \fIclientData\fR points to an application-specific
+data structure that describes what to do when the command procedure
+is invoked. \fIArgc\fR and \fIargv\fR describe the arguments to
+the command, \fIargc\fR giving the number of arguments (including
+the command name) and \fIargv\fR giving the values of the arguments
+as strings. The \fIargv\fR array will contain \fIargc\fR+1 values;
+the first \fIargc\fR values point to the argument strings, and the
+last value is NULL.
+.PP
+\fIProc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR,
+\fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page
+for details on what these codes mean. Most normal commands will only
+return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, \fIproc\fR must set
+\fIinterp->result\fR to point to a string value;
+in the case of a \fBTCL_OK\fR return code this gives the result
+of the command, and in the case of \fBTCL_ERROR\fR it gives an error message.
+The \fBTcl_SetResult\fR procedure provides an easy interface for setting
+the return value; for complete details on how the \fIinterp->result\fR
+field is managed, see the \fBTcl_Interp\fR man page.
+Before invoking a command procedure,
+\fBTcl_Eval\fR sets \fIinterp->result\fR to point to an empty string, so simple
+commands can return an empty result by doing nothing at all.
+.PP
+.VS
+The contents of the \fIargv\fR array belong to Tcl and are not
+guaranteed to persist once \fIproc\fR returns: \fIproc\fR should
+not modify them, nor should it set \fIinterp->result\fR to point
+anywhere within the \fIargv\fR values.
+Call \fBTcl_SetResult\fR with status \fBTCL_VOLATILE\fR if you want
+to return something from the \fIargv\fR array.
+.VE
+.PP
+\fIDeleteProc\fR will be invoked when (if) \fIcmdName\fR is deleted.
+This can occur through a call to \fBTcl_DeleteCommand\fR or \fBTcl_DeleteInterp\fR,
+or by replacing \fIcmdName\fR in another call to \fBTcl_CreateCommand\fR.
+\fIDeleteProc\fR is invoked before the command is deleted, and gives the
+application an opportunity to release any structures associated
+with the command. \fIDeleteProc\fR should have arguments and
+result that match the type \fBTcl_CmdDeleteProc\fR:
+.nf
+.RS
+.sp
+typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR);
+.sp
+.RE
+.fi
+The \fIclientData\fR argument will be the same as the \fIclientData\fR
+argument passed to \fBTcl_CreateCommand\fR.
+.PP
+\fBTcl_DeleteCommand\fR deletes a command from a command interpreter.
+Once the call completes, attempts to invoke \fIcmdName\fR in
+\fIinterp\fR will result in errors.
+If \fIcmdName\fR isn't bound as a command in \fIinterp\fR then
+\fBTcl_DeleteCommand\fR does nothing and returns -1; otherwise
+it returns 0.
+There are no restrictions on \fIcmdName\fR: it may refer to
+a built-in command, an application-specific command, or a Tcl procedure.
+.PP
+.VS
+\fBTcl_GetCommandInfo\fR checks to see whether its \fIcmdName\fR argument
+exists as a command in \fIinterp\fR. If not then it returns 0.
+Otherwise it places information about the command in the structure
+pointed to by \fIinfoPtr\fR and returns 1.
+Tcl_CmdInfo structures have fields named \fIproc\fR, \fIclientData\fR,
+and \fIdeleteProc\fR, which have the same meaning as the corresponding
+arguments to \fBTcl_CreateCommand\fR.
+There is also a field \fIdeleteData\fR, which is the ClientData value
+to pass to \fIdeleteProc\fR; it is normally the same as
+\fIclientData\fR but may be set independently using the
+\fBTcl_SetCommandInfo\fR procedure.
+.PP
+\fBTcl_SetCommandInfo\fR is used to modify the procedures and
+ClientData values associated with a command.
+Its \fIcmdName\fR argument is the name of a command in \fIinterp\fR.
+If this command exists then \fBTcl_SetCommandInfo\fR returns 0.
+Otherwise, it copies the information from \fI*infoPtr\fR to
+Tcl's internal structure for the command and returns 1.
+Note that this procedure allows the ClientData for a command's
+deletion procedure to be given a different value than the ClientData
+for its command procedure.
+.VE
+
+.SH KEYWORDS
+bind, command, create, delete, interpreter
diff --git a/vendor/x11iraf/obm/Tcl/doc/CrtInterp.3 b/vendor/x11iraf/obm/Tcl/doc/CrtInterp.3
new file mode 100644
index 00000000..c987801c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CrtInterp.3
@@ -0,0 +1,61 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CrtInterp.3,v 1.7 93/04/01 09:25:24 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CreateInterp tclc
+.BS
+.SH NAME
+Tcl_CreateInterp, Tcl_DeleteInterp \- create and delete Tcl command interpreters
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+Tcl_Interp *
+\fBTcl_CreateInterp\fR()
+.sp
+\fBTcl_DeleteInterp\fR(\fIinterp\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp
+.AP Tcl_Interp *interp in
+Token for interpreter to be destroyed.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CreateInterp\fR creates a new interpreter structure and returns
+a token for it. The token is required in calls to most other Tcl
+procedures, such as \fBTcl_CreateCommand\fR, \fBTcl_Eval\fR, and
+\fBTcl_DeleteInterp\fR.
+Clients are only allowed to access a few of the fields of
+Tcl_Interp structures; see the Tcl_Interp
+and \fBTcl_CreateCommand\fR man pages for details.
+The new interpreter is initialized with no defined variables and only
+the built-in Tcl commands. To bind in additional commands, call
+\fBTcl_CreateCommand\fR.
+.PP
+\fBTcl_DeleteInterp\fR destroys a command interpreter and releases all of
+the resources associated with it, including variables, procedures,
+and application-specific command bindings. After \fBTcl_DeleteInterp\fR
+returns the caller should never again use the \fIinterp\fR token.
+
+.SH KEYWORDS
+command, create, delete, interpreter
diff --git a/vendor/x11iraf/obm/Tcl/doc/CrtMathFnc.3 b/vendor/x11iraf/obm/Tcl/doc/CrtMathFnc.3
new file mode 100644
index 00000000..1a48b6c1
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CrtMathFnc.3
@@ -0,0 +1,114 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CrtMathFnc.3,v 1.1 93/04/14 16:35:59 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CreateMathFunc tclc 7.0
+.BS
+.SH NAME
+Tcl_CreateMathFunc \- Define a new math function for expressions
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_CreateMathFunc\fR(\fIinterp, name, numArgs, argTypes, proc, clientData\fR)
+.SH ARGUMENTS
+.AS Tcl_ValueType clientData
+.AP Tcl_Interp *interp in
+Interpreter in which new function will be defined.
+.AP char *name in
+Name for new function.
+.AP int numArgs in
+Number of arguments to new function; also gives size of \fIargTypes\fR array.
+.AP Tcl_ValueType *argTypes in
+Points to an array giving the permissible types for each argument to
+function.
+.AP Tcl_MathProc *proc in
+Procedure that implements the function.
+.AP ClientData clientData in
+Arbitrary one-word value to pass to \fIproc\fR when it is invoked.
+.BE
+
+.SH DESCRIPTION
+.PP
+Tcl allows a number of mathematical functions to be used in
+expressions, such as \fBsin\fR, \fBcos\fR, and \fBhypot\fR.
+\fBTcl_CreateMathFunc\fR allows applications to add additional functions
+to those already provided by Tcl or to replace existing functions.
+\fIName\fR is the name of the function as it will appear in expressions.
+If \fIname\fR doesn't already exist as a function then a new function
+is created. If it does exist, then the existing function is replaced.
+\fINumArgs\fR and \fIargTypes\fR describe the arguments to the function.
+Each entry in the \fIargTypes\fR array must be either TCL_INT, TCL_DOUBLE,
+or TCL_EITHER to indicate whether the corresponding argument must be an
+integer, a double-precision floating value, or either, respectively.
+.PP
+Whenever the function is invoked in an expression Tcl will invoke
+\fIproc\fR. \fIProc\fR should have arguments and result that match
+the type \fBTcl_MathProc\fR:
+.nf
+.RS
+typedef int Tcl_MathProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR,
+Tcl_Value *\fIargs\fR,
+Tcl_Value *resultPtr\fR);
+.RE
+.RE
+.fi
+.PP
+When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR
+arguments will be the same as those passed to \fBTcl_CreateMathFunc\fR.
+\fIArgs\fR will point to an array of \fInumArgs\fR Tcl_Value structures,
+which describe the actual arguments to the function:
+.nf
+.RS
+typedef struct Tcl_Value {
+.RS
+Tcl_ValueType \fItype\fR;
+int \fIintValue\fR;
+double \fIdoubleValue\fR;
+.RE
+} Tcl_Value;
+.RE
+.fi
+.PP
+The \fItype\fR field indicates the type of the argument and is
+either TCL_INT or TCL_DOUBLE.
+It will match the \fIargTypes\fR value specified for the function unless
+the \fIargTypes\fR value was TCL_EITHER. Tcl converts
+the argument supplied in the expression to the type requested in
+\fIargTypes\fR, if that is necessary.
+Depending on the value of the \fItype\fR field, the \fIintValue\fR
+or \fIdoubleValue\fR field will contain the actual value of the argument.
+.PP
+\fIProc\fR should compute its result and store it either as an integer
+in \fIresultPtr->intValue\fR or as a floating value in
+\fIresultPtr->doubleValue\fR.
+It should set also \fIresultPtr->type\fR to either TCL_INT or TCL_DOUBLE
+to indicate which value was set.
+Under normal circumstances \fIproc\fR should return TCL_OK.
+If an error occurs while executing the function, \fIproc\fR should
+return TCL_ERROR and leave an error message in \fIinterp->result\fR.
+
+.SH KEYWORDS
+expression, mathematical function
diff --git a/vendor/x11iraf/obm/Tcl/doc/CrtPipelin.3 b/vendor/x11iraf/obm/Tcl/doc/CrtPipelin.3
new file mode 100644
index 00000000..f5064b6c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CrtPipelin.3
@@ -0,0 +1,114 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CrtPipelin.3,v 1.7 93/04/09 11:53:47 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CreatePipeline tclc
+.BS
+.SH NAME
+Tcl_CreatePipeline \- create one or more child processes, with I/O redirection
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_CreatePipeline\fR(\fIinterp, argc, argv, pidArrayPtr, inPipePtr, outPipePtr, errFilePtr\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp **pidArrayPtr
+.AP Tcl_Interp *interp in
+Interpreter to use for error reporting.
+.AP int argc in
+Number of strings in \fIargv\fR array.
+.AP char **argv in
+Array of strings describing command(s) and I/O redirection.
+.AP int **pidArrayPtr out
+The value at \fI*pidArrayPtr\fR is modified to hold a pointer to
+an array of process identifiers. The array is dynamically
+allocated and must be freed by the caller.
+.AP int *inPipePtr out
+If this argument is NULL then standard input for the first command
+in the pipeline comes from the current standard input.
+If \fIinPipePtr\fR is not NULL then \fBTcl_CreatePipeline\fR will
+create a pipe, arrange for it to be used for standard input
+to the first command,
+and store a file id for writing to that pipe at \fI*inPipePtr\fR.
+If the command specified its own input using redirection, then
+no pipe is created and -1 is stored at \fI*inPipePtr\fR.
+.AP int *outPipePtr out
+If this argument is NULL then standard output for the last command
+in the pipeline goes to the current standard output.
+If \fIoutPipePtr\fR is not NULL then \fBTcl_CreatePipeline\fR will
+create a pipe, arrange for it to be used for standard output from
+the last command, and store a file id for reading from that
+pipe at \fI*outPipePtr\fR.
+If the command specified its own output using redirection then
+no pipe is created and -1 is stored at \fI*outPipePtr\fR.
+.AP int *errFilePtr out
+If this argument is NULL then error output for all the commands
+in the pipeline will go to the current standard error file.
+If \fIerrFilePtr\fR is not NULL, error output from all the commands
+in the pipeline will go to a temporary file created by
+\fBTcl_CreatePipeline\fR.
+A file id to read from that file will be stored at \fI*errFilePtr\fR.
+The file will already have been removed, so closing the file
+descriptor at \fI*errFilePtr\fR will cause the file to be flushed
+completely.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CreatePipeline\fR processes the \fIargv\fR array and sets
+up one or more child processes in a pipeline configuration.
+\fBTcl_CreatePipeline\fR handles pipes specified with ``|'',
+input redirection specified with ``<'' or ``<<'', and output
+redirection specified with ``>''; see the documentation for
+the \fBexec\fR command for details on these specifications.
+The return value from \fBTcl_CreatePipeline\fR is a count of
+the number of child processes created; the process identifiers
+for those processes are stored in a \fImalloc\fR-ed array and
+a pointer to that array is stored at \fI*pidArrayPtr\fR.
+It is the caller's responsibility to free the array when finished
+with it.
+.PP
+If the \fIinPipePtr\fR, \fIoutPipePtr\fR, and \fIerrFilePtr\fR
+arguments are NULL then the pipeline's standard input, standard
+output, and standard error are taken from the corresponding
+streams of the process. Non-NULL values may be specified for
+these arguments to use pipes for standard input and standard
+output and a file for standard error. \fBTcl_CreatePipeline\fR
+will create the requested pipes or file and return file identifiers
+that may be used to read or write them. It is the caller's
+responsibility to close all of these files when they are no
+longer needed. If \fIargv\fR specifies redirection for standard
+input or standard output, then pipes will not be created even
+if requested by the \fIinPipePtr\fR and \fIoutPipePtr\fR
+arguments.
+.PP
+If an error occurs in \fBTcl_CreatePipeline\fR (e.g. ``|'' or
+``<'' was the last argument in \fIargv\fR, or it wasn't possible
+to fork off a child), then -1 is returned
+and \fIinterp->result\fR is set to an error message.
+
+.SH "SEE ALSO"
+\fBTcl_DetachPids\fR, \fBTcl_ReapDetachedProcs\fR
+
+.SH KEYWORDS
+background, child, detach, fork, process, status, wait
diff --git a/vendor/x11iraf/obm/Tcl/doc/CrtTrace.3 b/vendor/x11iraf/obm/Tcl/doc/CrtTrace.3
new file mode 100644
index 00000000..796346d9
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/CrtTrace.3
@@ -0,0 +1,125 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/CrtTrace.3,v 1.8 93/04/01 09:25:26 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_CreateTrace tclc
+.BS
+.SH NAME
+Tcl_CreateTrace, Tcl_DeleteTrace \- arrange for command execution to be traced
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+Tcl_Trace
+\fBTcl_CreateTrace\fR(\fIinterp, level, proc, clientData\fR)
+.sp
+\fBTcl_DeleteTrace\fR(\fIinterp, trace\fR)
+.SH ARGUMENTS
+.AS Tcl_CmdTraceProc (clientData)()
+.AP Tcl_Interp *interp in
+Interpreter containing command to be traced or untraced.
+.AP int level in
+Only commands at or below this nesting level will be traced. 1 means
+top-level commands only, 2 means top-level commands or those that are
+invoked as immediate consequences of executing top-level commands
+(procedure bodies, bracketed commands, etc.) and so on.
+.AP Tcl_CmdTraceProc *proc in
+Procedure to call for each command that's executed. See below for
+details on the calling sequence.
+.AP ClientData clientData in
+Arbitrary one-word value to pass to \fIproc\fR.
+.AP Tcl_Trace trace in
+Token for trace to be removed (return value from previous call
+to \fBTcl_CreateTrace\fR).
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_CreateTrace\fR arranges for command tracing. From now on, \fIproc\fR
+will be invoked before Tcl calls command procedures to process
+commands in \fIinterp\fR. The return value from
+\fBTcl_CreateTrace\fR is a token for the trace,
+which may be passed to \fBTcl_DeleteTrace\fR to remove the trace. There may
+be many traces in effect simultaneously for the same command interpreter.
+.PP
+\fIProc\fR should have arguments and result that match the
+type \fBTcl_CmdTraceProc\fR:
+.nf
+.sp
+.RS
+typedef void Tcl_CmdTraceProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR,
+int \fIlevel\fR,
+char *\fIcommand\fR,
+Tcl_CmdProc *\fIcmdProc\fR,
+ClientData \fIcmdClientData\fR,
+int \fIargc\fR,
+char *\fIargv\fR[]));
+.sp
+.RE
+.RE
+.fi
+The \fIclientData\fP and \fIinterp\fP parameters are
+copies of the corresponding arguments given to \fBTcl_CreateTrace\fR.
+\fIClientData\fR typically points to an application-specific
+data structure that describes what to do when \fIproc\fR
+is invoked. \fILevel\fR gives the nesting level of the command
+(1 for top-level commands passed to \fBTcl_Eval\fR by the application,
+2 for the next-level commands passed to \fBTcl_Eval\fR as part of parsing
+or interpreting level-1 commands, and so on). \fICommand\fR
+points to a string containing the text of the
+command, before any argument substitution.
+\fICmdProc\fR contains the address of the command procedure that
+will be called to process the command (i.e. the \fIproc\fR argument
+of some previous call to \fBTcl_CreateCommand\fR) and \fIcmdClientData\fR
+contains the associated client data for \fIcmdProc\fR (the \fIclientData\fR
+value passed to \fBTcl_CreateCommand\fR). \fIArgc\fR and \fIargv\fR give
+the final argument information that will be passed to \fIcmdProc\fR, after
+command, variable, and backslash substitution.
+\fIProc\fR must not modify the \fIcommand\fR or \fIargv\fR strings.
+.PP
+Tracing will only occur for commands at nesting level less than
+or equal to the \fIlevel\fR parameter (i.e. the \fIlevel\fR
+parameter to \fIproc\fR will always be less than or equal to the
+\fIlevel\fR parameter to \fBTcl_CreateTrace\fR).
+.PP
+Calls to \fIproc\fR will be made by the Tcl parser immediately before
+it calls the command procedure for the command (\fIcmdProc\fR). This
+occurs after argument parsing and substitution, so tracing for
+substituted commands occurs before tracing of the commands
+containing the substitutions. If there is a syntax error in a
+command, or if there is no command procedure associated with a
+command name, then no tracing will occur for that command. If a
+string passed to Tcl_Eval contains multiple commands (bracketed, or
+on different lines) then multiple calls to \fIproc\fR will occur,
+one for each command. The \fIcommand\fR string for each of these
+trace calls will reflect only a single command, not the entire string
+passed to Tcl_Eval.
+.PP
+\fBTcl_DeleteTrace\fR removes a trace, so that no future calls will be
+made to the procedure associated with the trace. After \fBTcl_DeleteTrace\fR
+returns, the caller should never again use the \fItrace\fR token.
+
+.SH KEYWORDS
+command, create, delete, interpreter, trace
diff --git a/vendor/x11iraf/obm/Tcl/doc/DString.3 b/vendor/x11iraf/obm/Tcl/doc/DString.3
new file mode 100644
index 00000000..9d72b423
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/DString.3
@@ -0,0 +1,141 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/DString.3,v 1.10 93/08/16 13:24:52 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_DStringInit tclc 7.0
+.BS
+.SH NAME
+.na
+Tcl_DStringInit, Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_DStringStartSublist, Tcl_DStringEndSublist, Tcl_DStringLength, Tcl_DStringValue, Tcl_DStringTrunc, Tcl_DStringFree, Tcl_DStringResult \- manipulate dynamic strings
+.ad
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_DStringInit\fR(\fIdsPtr\fR)
+.sp
+char *
+\fBTcl_DStringAppend\fR(\fIdsPtr, string, length\fR)
+.sp
+char *
+\fBTcl_DStringAppendElement\fR(\fIdsPtr, string\fR)
+.sp
+\fBTcl_DStringStartSublist\fR(\fIdsPtr\fR)
+.sp
+\fBTcl_DStringEndSublist\fR(\fIdsPtr\fR)
+.sp
+int
+\fBTcl_DStringLength\fR(\fIdsPtr\fR)
+.sp
+char *
+\fBTcl_DStringValue\fR(\fIdsPtr\fR)
+.sp
+\fBTcl_DStringTrunc\fR(\fIdsPtr, newLength\fR)
+.sp
+\fBTcl_DStringFree\fR(\fIdsPtr\fR)
+.sp
+\fBTcl_DStringResult\fR(\fIinterp, dsPtr\fR)
+.SH ARGUMENTS
+.AS Tcl_DString newLength
+.AP Tcl_DString *dsPtr in/out
+Pointer to structure that is used to manage a dynamic string.
+.AP char *string in
+Pointer to characters to add to dynamic string.
+.AP int length in
+Number of characters from string to add to dynamic string. If -1,
+add all characters up to null terminating character.
+.AP int newLength in
+New length for dynamic string, not including null terminating
+character.
+.BE
+
+.SH DESCRIPTION
+.PP
+Dynamic strings provide a mechanism for building up arbitrarily long
+strings by gradually appending information. If the dynamic string is
+short then there will be no memory allocation overhead; as the string
+gets larger, additional space will be allocated as needed.
+.PP
+\fBTcl_DStringInit\fR initializes a dynamic string to zero length.
+The Tcl_DString structure must have been allocated by the caller.
+No assumptions are made about the current state of the structure;
+anything already in it is discarded.
+If the structure has been used previously, \fBTcl_DStringFree\fR should
+be called first to free up any memory allocated for the old
+string.
+.PP
+\fBTcl_DStringAppend\fR adds new information to a dynamic string,
+allocating more memory for the string if needed.
+If \fIlength\fR is less than zero then everything in \fIstring\fR
+is appended to the dynamic string; otherwise \fIlength\fR
+specifies the number of bytes to append.
+\fBTcl_DStringAppend\fR returns a pointer to the characters of
+the new string. The string can also be retrieved from the
+\fIstring\fR field of the Tcl_DString structure.
+.PP
+\fBTcl_DStringAppendElement\fR is similar to \fBTcl_DStringAppend\fR
+except that it doesn't take a \fIlength\fR argument (it appends
+all of \fIstring\fR) and it converts the string to a proper list element
+before appending.
+\fBTcl_DStringAppendElement\fR adds a separator space before the
+new list element unless the new list element is the first in a
+list or sub-list (i.e. either the current string is empty, or it
+contains the single character ``{'', or the last two characters of
+the current string are `` {'').
+\fBTcl_DStringAppendElement\fR returns a pointer to the
+characters of the new string.
+.PP
+\fBTcl_DStringStartSublist\fR and \fBTcl_DStringEndSublist\fR can be
+used to create nested lists.
+To append a list element that is itself a sublist, first
+call \fBTcl_DStringStartSublist\fR, then call \fBTcl_DStringAppendElement\fR
+for each of the elements in the sublist, then call
+\fBTcl_DStringEndSublist\fR to end the sublist.
+\fBTcl_DStringStartSublist\fR appends a space character if needed,
+followed by an open brace; \fBTcl_DStringAppendElement\fR appends
+a close brace.
+Lists can be nested to any depth.
+.PP
+\fBTcl_DStringLength\fR is a macro that returns the current length
+of a dynamic string (not including the terminating null character).
+\fBTcl_DStringValue\fR is a macro that returns a pointer to the
+current contents of a dynamic string.
+.PP
+\fBTcl_DStringTrunc\fR truncates a dynamic string to a given length.
+It has no effect if the string was already smaller than \fInewLength\fR.
+This procedure does not free up the string's storage space, even
+if the string is truncated to zero length, so \fBTcl_DStringFree\fR
+will still need to be called.
+.PP
+\fBTcl_DStringFree\fR should be called when you're finished using
+the string. It frees up any memory that was allocated for the string
+and reinitializes the string's value to an empty string.
+.PP
+\fBTcl_DStringResult\fR sets the result of \fIinterp\fR to the value of
+the dynamic string given by \fIdsPtr\fR. It does this by moving
+a pointer from \fIdsPtr\fR to \fIinterp->result\fR.
+This saves the cost of allocating new memory and copying the string.
+\fBTcl_DStringResult\fR also reinitializes the dynamic string to
+an empty string.
+
+.SH KEYWORDS
+append, dynamic string, free, result
diff --git a/vendor/x11iraf/obm/Tcl/doc/DetachPids.3 b/vendor/x11iraf/obm/Tcl/doc/DetachPids.3
new file mode 100644
index 00000000..4862d92d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/DetachPids.3
@@ -0,0 +1,79 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/DetachPids.3,v 1.10 93/09/09 10:53:24 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_DetachPids tclc
+.BS
+.SH NAME
+Tcl_DetachPids, Tcl_ReapDetachedProcs \- manage child processes in background
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_DetachPids\fR(\fInumPids, pidPtr\fR)
+.sp
+.VS
+\fBTcl_ReapDetachedProcs\fR()
+.VE
+.SH ARGUMENTS
+.AS int *statusPtr
+.AP int numPids in
+Number of process ids contained in the array pointed to by \fIpidPtr\fR.
+.AP int *pidPtr in
+Address of array containing \fInumPids\fR process ids.
+.BE
+
+.SH DESCRIPTION
+.PP
+.VS
+\fBTcl_DetachPids\fR and \fBTcl_ReapDetachedProcs\fR provide a
+mechanism for managing subprocesses that are running in background.
+These procedures are needed because the parent of a process must
+eventually invoke the \fBwaitpid\fR kernel call (or one of a few other
+similar kernel calls) to wait for the child to exit. Until the
+parent waits for the child, the child's state cannot be completely
+reclaimed by the system. If a parent continually creates children
+and doesn't wait on them, the system's process table will eventually
+overflow, even if all the children have exited.
+.PP
+\fBTcl_DetachPids\fR may be called to ask Tcl to take responsibility
+for one or more processes whose process ids are contained in the
+\fIpidPtr\fR array passed as argument. The caller presumably
+has started these processes running in background and doesn't
+want to have to deal with them again.
+.PP
+\fBTcl_ReapDetachedProcs\fR invokes the \fBwaitpid\fR kernel call
+on each of the background processes so that its state can be cleaned
+up if it has exited. If the process hasn't exited yet,
+\fBTcl_ReapDetachedProcs\fR doesn't wait for it to exit; it will check again
+the next time it is invoked.
+Tcl automatically calls \fBTcl_ReapDetachedProcs\fR each time the
+\fBexec\fR command is executed, so in most cases it isn't necessary
+for any code outside of Tcl to invoke \fBTcl_ReapDetachedProcs\fR.
+However, if you call \fBTcl_DetachPids\fR in situations where the
+\fBexec\fR command may never get executed, you may wish to call
+\fBTcl_ReapDetachedProcs\fR from time to time so that background
+processes can be cleaned up.
+.VE
+
+.SH KEYWORDS
+background, child, detach, process, wait
diff --git a/vendor/x11iraf/obm/Tcl/doc/EnterFile.3 b/vendor/x11iraf/obm/Tcl/doc/EnterFile.3
new file mode 100644
index 00000000..12f15299
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/EnterFile.3
@@ -0,0 +1,98 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/EnterFile.3,v 1.4 93/08/27 13:20:42 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_EnterFile tclc 7.0
+.BS
+.SH NAME
+Tcl_EnterFile, Tcl_GetOpenFile, Tcl_FilePermissions \- manipulate the table of open files
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_EnterFile\fR(\fIinterp, file, permissions\fR)
+.sp
+int
+\fBTcl_GetOpenFile\fR(\fIinterp, string, write, checkUsage, filePtr\fR)
+.sp
+int
+\fBTcl_FilePermissions(\fIfile\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp checkUsage
+.AP Tcl_Interp *interp in
+Tcl interpreter from which file is to be accessed.
+.AP FILE *file in
+Handle for file that is to become accessible in \fIinterp\fR.
+.AP int permissions in
+OR-ed combination of TCL_FILE_READABLE and TCL_FILE_WRITABLE;
+indicates whether \fIfile\fR was opened for reading or writing or both.
+.AP char *string in
+String identifying file, such as \fBstdin\fR or \fBfile4\fR.
+.AP int write in
+Non-zero means the file will be used for writing, zero means it will
+be used for reading.
+.AP int checkUsage in
+If non-zero, then an error will be generated if the file wasn't opened
+for the access indicated by \fIwrite\fR.
+.AP FILE **filePtr out
+Points to word in which to store pointer to FILE structure for
+the file given by \fIstring\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures provide access to Tcl's file naming mechanism.
+\fBTcl_EnterFile\fR enters an open file into Tcl's file table so
+that it can be accessed using Tcl commands like \fBgets\fR,
+\fBputs\fR, \fBseek\fR, and \fBclose\fR.
+It returns in \fIinterp->result\fR an identifier such as \fBfile4\fR
+that can be used to refer to the file in subsequent Tcl commands.
+\fBTcl_EnterFile\fR is typically used to implement new Tcl commands
+that open sockets, pipes, or other kinds of files not already supported
+by the built-in commands.
+.PP
+\fBTcl_GetOpenFile\fR takes as argument a file identifier of the form
+returned by the \fBopen\fR command or \fBTcl_EnterFile\fR and
+returns at \fI*filePtr\fR a pointer to the FILE structure for
+the file.
+The \fIwrite\fR argument indicates whether the FILE pointer will
+be used for reading or writing.
+In some cases, such as a file that connects to a pipeline of
+subprocesses, different FILE pointers will be returned for reading
+and writing.
+\fBTcl_GetOpenFile\fR normally returns TCL_OK.
+If an error occurs in \fBTcl_GetOpenFile\fR (e.g. \fIstring\fR didn't
+make any sense or \fIcheckUsage\fR was set and the file wasn't opened
+for the access specified by \fIwrite\fR) then TCL_ERROR is returned
+and \fIinterp->result\fR will contain an error message.
+If \fIcheckUsage\fR is zero and the file wasn't opened for the
+access specified by \fIwrite\fR, then the FILE pointer returned
+at \fI*filePtr\fR may not correspond to \fIwrite\fR.
+.PP
+\fBTcl_FilePermissions\fR returns an OR-ed combination of the
+mask bits TCL_FILE_READABLE and TCL_FILE_WRITABLE; these indicate
+whether the given file was opened for reading or writing or both.
+If \fIfile\fR does not refer to a file in Tcl's file table then
+\-1 is returned.
+
+.SH KEYWORDS
+file table, permissions, pipeline, read, write
diff --git a/vendor/x11iraf/obm/Tcl/doc/Eval.3 b/vendor/x11iraf/obm/Tcl/doc/Eval.3
new file mode 100644
index 00000000..db2cbf40
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Eval.3
@@ -0,0 +1,119 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Eval.3,v 1.13 93/04/03 16:40:04 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_Eval tclc 7.0
+.BS
+.SH NAME
+Tcl_Eval, Tcl_VarEval, Tcl_EvalFile, Tcl_GlobalEval \- execute Tcl commands
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+.VS
+\fBTcl_Eval\fR(\fIinterp, cmd\fR)
+.VE
+.sp
+int
+\fBTcl_VarEval\fR(\fIinterp, string, string, ... \fB(char *) NULL\fR)
+.sp
+int
+\fBTcl_EvalFile\fR(\fIinterp, fileName\fR)
+.sp
+int
+\fBTcl_GlobalEval\fR(\fIinterp, cmd\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp **termPtr;
+.AP Tcl_Interp *interp in
+Interpreter in which to execute the command. String result will be
+stored in \fIinterp->result\fR.
+.AP char *cmd in
+Command (or sequence of commands) to execute. Must be in writable
+memory (\fBTcl_Eval\fR makes temporary modifications to the command).
+.AP char *string in
+String forming part of Tcl command.
+.AP char *fileName in
+Name of file containing Tcl command string.
+.BE
+
+.SH DESCRIPTION
+.PP
+All four of these procedures execute Tcl commands.
+\fBTcl_Eval\fR is the core procedure: it parses commands
+from \fIcmd\fR and executes them in
+.VS
+order until either an error occurs or it reaches the end of the string.
+.VE
+The return value from \fBTcl_Eval\fR is one
+of the Tcl return codes \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or
+\fBTCL_CONTINUE\fR, and \fIinterp->result\fR will point to
+a string with additional information (result value or error message).
+This return information corresponds to the last command executed from
+\fIcmd\fR.
+.PP
+\fBTcl_VarEval\fR takes any number of string arguments
+of any length, concatenates
+them into a single string, then calls \fBTcl_Eval\fR to
+execute that string as a Tcl command.
+It returns the result of the command and also modifies
+\fIinterp->result\fR in the usual fashion for Tcl commands. The
+last argument to \fBTcl_VarEval\fR must be NULL to indicate the end
+of arguments.
+.PP
+\fBTcl_EvalFile\fR reads the file given by \fIfileName\fR and evaluates
+its contents as a Tcl command by calling \fBTcl_Eval\fR. It returns
+a standard Tcl result that reflects the result of evaluating the
+file.
+If the file couldn't be read then a Tcl error is returned to describe
+why the file couldn't be read.
+.PP
+\fBTcl_GlobalEval\fR is similar to \fBTcl_Eval\fR except that it
+processes the command at global level.
+This means that the variable context for the command consists of
+global variables only (it ignores any Tcl procedure that is active).
+This produces an effect similar to the Tcl command ``\fBuplevel 0\fR''.
+.PP
+During the processing of a Tcl command it is legal to make nested
+calls to evaluate other commands (this is how conditionals, loops,
+and procedures are implemented).
+If a code other than
+\fBTCL_OK\fR is returned from a nested \fBTcl_Eval\fR invocation, then the
+caller should normally return immediately, passing that same
+return code back to its caller, and so on until the top-level application is
+reached. A few commands, like \fBfor\fR, will check for certain
+return codes, like \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR, and process them
+specially without returning.
+.PP
+\fBTcl_Eval\fR keeps track of how many nested Tcl_Eval invocations are
+in progress for \fIinterp\fR.
+If a code of \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR is
+about to be returned from the topmost \fBTcl_Eval\fR invocation for
+\fIinterp\fR, then \fBTcl_Eval\fR converts the return code to \fBTCL_ERROR\fR
+and sets \fIinterp->result\fR to point to an error message indicating that
+the \fBreturn\fR, \fBbreak\fR, or \fBcontinue\fR command was
+invoked in an inappropriate place. This means that top-level
+applications should never see a return code from \fBTcl_Eval\fR other then
+\fBTCL_OK\fR or \fBTCL_ERROR\fR.
+
+.SH KEYWORDS
+command, execute, file, global, interpreter, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/ExprLong.3 b/vendor/x11iraf/obm/Tcl/doc/ExprLong.3
new file mode 100644
index 00000000..a043347b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/ExprLong.3
@@ -0,0 +1,119 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/ExprLong.3,v 1.11 93/04/17 15:31:16 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_ExprLong tclc 7.0
+.BS
+.SH NAME
+Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBool, Tcl_ExprString \- evaluate an expression
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_ExprLong\fR(\fIinterp, string, longPtr\fR)
+.sp
+int
+\fBTcl_ExprDouble\fR(\fIinterp, string, doublePtr\fR)
+.sp
+int
+\fBTcl_ExprBoolean\fR(\fIinterp, string, booleanPtr\fR)
+.sp
+int
+\fBTcl_ExprString\fR(\fIinterp, string\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *booleanPtr
+.AP Tcl_Interp *interp in
+Interpreter in whose context to evaluate \fIstring\fR.
+.AP char *string in
+Expression to be evaluated. Must be in writable memory (the expression
+parser makes temporary modifications to the string during parsing, which
+it undoes before returning).
+.AP long *longPtr out
+Pointer to location in which to store the integer value of the
+expression.
+.AP int *doublePtr out
+Pointer to location in which to store the floating-point value of the
+expression.
+.AP int *booleanPtr out
+Pointer to location in which to store the 0/1 boolean value of the
+expression.
+.BE
+
+.SH DESCRIPTION
+.PP
+These four procedures all evaluate an expression, returning
+the result in one of four different forms.
+The expression is given by the \fIstring\fR argument, and it
+can have any of the forms accepted by the \fBexpr\fR command.
+The \fIinterp\fR argument refers to an interpreter used to
+evaluate the expression (e.g. for variables and nested Tcl
+commands) and to return error information. \fIInterp->result\fR
+is assumed to be initialized in the standard fashion when any
+of the procedures are invoked.
+.PP
+For all of these procedures the return value is a standard
+Tcl result: \fBTCL_OK\fR means the expression was succesfully
+evaluated, and \fBTCL_ERROR\fR means that an error occurred while
+evaluating the expression. If \fBTCL_ERROR\fR is returned then
+\fIinterp->result\fR will hold a message describing the error.
+If an error occurs while executing a Tcl command embedded in
+the expression then that error will be returned.
+.PP
+If the expression is successfully evaluated, then its value is
+returned in one of four forms, depending on which procedure
+is invoked.
+\fBTcl_ExprLong\fR stores an integer value at \fI*longPtr\fR.
+If the expression's actual value is a floating-point number,
+then it is truncated to an integer.
+If the expression's actual value is a non-numeric string then
+an error is returned.
+.PP
+\fBTcl_ExprDouble\fR stores a floating-point value at \fI*doublePtr\fR.
+If the expression's actual value is an integer, it is converted to
+floating-point.
+If the expression's actual value is a non-numeric string then
+an error is returned.
+.PP
+\fBTcl_ExprBoolean\fR stores a 0/1 integer value at \fI*booleanPtr\fR.
+If the expression's actual value is an integer or floating-point
+number, then \fBTcl_ExprBoolean\fR stores 0 at \fI*booleanPtr\fR if
+the value was zero and 1 otherwise.
+.VS
+If the expression's actual value is a non-numeric string then
+it must be one of the values accepted by \fBTcl_GetBoolean\fR,
+such as ``yes'' or ``no'', or else an error occurs.
+.VE
+.PP
+\fBTcl_ExprString\fR returns the value of the expression as a
+string stored in \fIinterp->result\fR.
+.VS
+If the expression's actual value is an integer
+then \fBTcl_ExprString\fR converts it to a string using \fBsprintf\fR
+with a ``%d'' converter.
+If the expression's actual value is a floating-point
+number, then \fBTcl_ExprString\fR calls \fBTcl_PrintDouble\fR
+to convert it to a string.
+.VE
+
+.SH KEYWORDS
+boolean, double, evaluate, expression, integer, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/GetInt.3 b/vendor/x11iraf/obm/Tcl/doc/GetInt.3
new file mode 100644
index 00000000..b3cf91d5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/GetInt.3
@@ -0,0 +1,94 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/GetInt.3,v 1.8 93/04/01 09:25:29 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_GetInt tclc
+.BS
+.SH NAME
+Tcl_GetInt, Tcl_GetDouble, Tcl_GetBoolean \- convert from string to integer, double, or boolean
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_GetInt\fR(\fIinterp, string, intPtr\fR)
+.sp
+int
+\fBTcl_GetDouble\fR(\fIinterp, string, doublePtr\fR)
+.sp
+int
+\fBTcl_GetBoolean\fR(\fIinterp, string, boolPtr\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *doublePtr
+.AP Tcl_Interp *interp in
+Interpreter to use for error reporting.
+.AP char *string in
+Textual value to be converted.
+.AP int *intPtr out
+Points to place to store integer value converted from \fIstring\fR.
+.AP double *doublePtr out
+Points to place to store double-precision floating-point
+value converted from \fIstring\fR.
+.AP int *boolPtr out
+Points to place to store boolean value (0 or 1) converted from \fIstring\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures convert from strings to integers or double-precision
+floating-point values or booleans (represented as 0- or 1-valued
+integers). Each of the procedures takes a \fIstring\fR argument,
+converts it to an internal form of a particular type, and stores
+the converted value at the location indicated by the procedure's
+third argument. If all goes well, each of the procedures returns
+TCL_OK. If \fIstring\fR doesn't have the proper syntax for the
+desired type then TCL_ERROR is returned, an error message is left
+in \fIinterp->result\fR, and nothing is stored at *\fIintPtr\fR
+or *\fIdoublePtr\fR or *\fIboolPtr\fR.
+.PP
+\fBTcl_GetInt\fR expects \fIstring\fR to consist of a collection
+of integer digits, optionally signed and optionally preceded by
+white space. If the first two characters of \fIstring\fR are ``0x''
+then \fIstring\fR is expected to be in hexadecimal form; otherwise,
+if the first character of \fIstring\fR is ``0'' then \fIstring\fR
+is expected to be in octal form; otherwise, \fIstring\fR is
+expected to be in decimal form.
+.PP
+\fBTcl_GetDouble\fR expects \fIstring\fR to consist of a floating-point
+number, which is: white space; a sign; a sequence of digits; a
+decimal point; a sequence of digits; the letter ``e''; and a
+signed decimal exponent. Any of the fields may be omitted, except that
+the digits either before or after the decimal point must be present
+and if the ``e'' is present then it must be followed by the
+exponent number.
+.PP
+\fBTcl_GetBoolean\fR expects \fIstring\fR to specify a boolean
+value. If \fIstring\fR is any of \fB0\fR, \fBfalse\fR,
+\fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero
+value at \fI*boolPtr\fR.
+If \fIstring\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR,
+then 1 is stored at \fI*boolPtr\fR.
+Any of these values may be abbreviated, and upper-case spellings
+are also acceptable.
+
+.SH KEYWORDS
+boolean, conversion, double, floating-point, integer
diff --git a/vendor/x11iraf/obm/Tcl/doc/Hash.3 b/vendor/x11iraf/obm/Tcl/doc/Hash.3
new file mode 100644
index 00000000..fec89035
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Hash.3
@@ -0,0 +1,222 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Hash.3,v 1.9 93/07/23 08:30:53 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_Hash tclc
+.BS
+.SH NAME
+.na
+Tcl_InitHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_InitHashTable\fR(\fItablePtr, keyType\fR)
+.sp
+\fBTcl_DeleteHashTable\fR(\fItablePtr\fR)
+.sp
+Tcl_HashEntry *
+\fBTcl_CreateHashEntry\fR(\fItablePtr, key, newPtr\fR)
+.sp
+\fBTcl_DeleteHashEntry\fR(\fIentryPtr\fR)
+.sp
+Tcl_HashEntry *
+\fBTcl_FindHashEntry\fR(\fItablePtr, key\fR)
+.sp
+ClientData
+\fBTcl_GetHashValue\fR(\fIentryPtr\fR)
+.sp
+\fBTcl_SetHashValue\fR(\fIentryPtr, value\fR)
+.sp
+char *
+\fBTcl_GetHashKey\fR(\fItablePtr, entryPtr\fR)
+.sp
+Tcl_HashEntry *
+\fBTcl_FirstHashEntry\fR(\fItablePtr, searchPtr\fR)
+.sp
+Tcl_HashEntry *
+\fBTcl_NextHashEntry\fR(\fIsearchPtr\fR)
+.sp
+char *
+\fBTcl_HashStats\fR(\fItablePtr\fR)
+.SH ARGUMENTS
+.AS Tcl_HashSearch *searchPtr
+.AP Tcl_HashTable *tablePtr in
+Address of hash table structure (for all procedures but
+\fBTcl_InitHashTable\fR, this must have been initialized by
+previous call to \fBTcl_InitHashTable\fR).
+.AP int keyType in
+Kind of keys to use for new hash table. Must be either
+TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, or an integer value
+greater than 1.
+.AP char *key in
+Key to use for probe into table. Exact form depends on
+\fIkeyType\fR used to create table.
+.AP int *newPtr out
+The word at \fI*newPtr\fR is set to 1 if a new entry was created
+and 0 if there was already an entry for \fIkey\fR.
+.AP Tcl_HashEntry *entryPtr in
+Pointer to hash table entry.
+.AP ClientData value in
+New value to assign to hash table entry. Need not have type
+ClientData, but must fit in same space as ClientData.
+.AP Tcl_HashSearch *searchPtr in
+Pointer to record to use to keep track of progress in enumerating
+all the entries in a hash table.
+.BE
+
+.SH DESCRIPTION
+.PP
+A hash table consists of zero or more entries, each consisting of
+a key and a value.
+Given the key for an entry, the hashing routines can very quickly
+locate the entry, and hence its value.
+There may be at most one entry in a hash table with a
+particular key, but many entries may have the same value.
+Keys can take one of three forms: strings,
+one-word values, or integer arrays.
+All of the keys in a given table have the same form, which is
+specified when the table is initialized.
+.PP
+The value of a hash table entry can be anything that fits in
+the same space as a ``char *'' pointer.
+Values for hash table entries are managed entirely by clients,
+not by the hash module itself.
+Typically each entry's value is a pointer to a data structure
+managed by client code.
+.PP
+Hash tables grow gracefully as the number of entries increases,
+so that there are always less than three entries per hash bucket,
+on average.
+This allows for fast lookups regardless of the number of entries
+in a table.
+.PP
+\fBTcl_InitHashTable\fR initializes a structure that describes
+a new hash table.
+The space for the structure is provided by the caller, not by
+the hash module.
+The value of \fIkeyType\fR indicates what kinds of keys will
+be used for all entries in the table. \fIKeyType\fR must have
+one of the following values:
+.IP \fBTCL_STRING_KEYS\fR 25
+Keys are null-terminated ASCII strings.
+They are passed to hashing routines using the address of the
+first character of the string.
+.IP \fBTCL_ONE_WORD_KEYS\fR 25
+Keys are single-word values; they are passed to hashing routines
+and stored in hash table entries as ``char *'' values.
+The pointer value is the key; it need not (and usually doesn't)
+actually point to a string.
+.IP \fIother\fR 25
+If \fIkeyType\fR is not TCL_STRING_KEYS or TCL_ONE_WORD_KEYS,
+then it must be an integer value greater than 1.
+In this case the keys will be arrays of ``int'' values, where
+\fIkeyType\fR gives the number of ints in each key.
+This allows structures to be used as keys.
+All keys must have the same size.
+Array keys are passed into hashing functions using the address
+of the first int in the array.
+.PP
+\fBTcl_DeleteHashTable\fR deletes all of the entries in a hash
+table and frees up the memory associated with the table's
+bucket array and entries.
+It does not free the actual table structure (pointed to
+by \fItablePtr\fR), since that memory is assumed to be managed
+by the client.
+\fBTcl_DeleteHashTable\fR also does not free or otherwise
+manipulate the values of the hash table entries.
+If the entry values point to dynamically-allocated memory, then
+it is the client's responsibility to free these structures
+before deleting the table.
+.PP
+\fBTcl_CreateHashEntry\fR locates the entry corresponding to a
+particular key, creating a new entry in the table if there
+wasn't already one with the given key.
+If an entry already existed with the given key then \fI*newPtr\fR
+is set to zero.
+If a new entry was created, then \fI*newPtr\fR is set to a non-zero
+value and the value of the new entry will be set to zero.
+The return value from \fBTcl_CreateHashEntry\fR is a pointer to
+the entry, which may be used to retrieve and modify the entry's
+value or to delete the entry from the table.
+.PP
+\fBTcl_DeleteHashEntry\fR will remove an existing entry from a
+table.
+The memory associated with the entry itself will be freed, but
+the client is responsible for any cleanup associated with the
+entry's value, such as freeing a structure that it points to.
+.PP
+\fBTcl_FindHashEntry\fR is similar to \fBTcl_CreateHashEntry\fR
+except that it doesn't create a new entry if the key doesn't exist;
+instead, it returns NULL as result.
+.PP
+\fBTcl_GetHashValue\fR and \fBTcl_SetHashValue\fR are used to
+read and write an entry's value, respectively.
+Values are stored and retrieved as type ``ClientData'', which is
+large enough to hold a pointer value. On almost all machines this is
+large enough to hold an integer value too.
+.PP
+\fBTcl_GetHashKey\fR returns the key for a given hash table entry,
+either as a pointer to a string, a one-word (``char *'') key, or
+as a pointer to the first word of an array of integers, depending
+on the \fIkeyType\fR used to create a hash table.
+In all cases \fBTcl_GetHashKey\fR returns a result with type
+``char *''.
+When the key is a string or array, the result of \fBTcl_GetHashKey\fR
+points to information in the table entry; this information will
+remain valid until the entry is deleted or its table is deleted.
+.PP
+\fBTcl_FirstHashEntry\fR and \fBTcl_NextHashEntry\fR may be used
+to scan all of the entries in a hash table.
+A structure of type ``Tcl_HashSearch'', provided by the client,
+is used to keep track of progress through the table.
+\fBTcl_FirstHashEntry\fR initializes the search record and
+returns the first entry in the table (or NULL if the table is
+empty).
+Each susequent call to \fBTcl_NextHashEntry\fR returns the
+next entry in the table or
+NULL if the end of the table has been reached.
+A call to \fBTcl_FirstHashEntry\fR followed by calls to
+\fBTcl_NextHashEntry\fR will return each of the entries in
+the table exactly once, in an arbitrary order.
+It is unadvisable to modify the structure of the table, e.g.
+by creating or deleting entries, while the search is in
+progress.
+.PP
+\fBTcl_HashStats\fR returns a dynamically-allocated string with
+overall information about a hash table, such as the number of
+entries it contains, the number of buckets in its hash array,
+and the utilization of the buckets.
+It is the caller's responsibility to free the result string
+by passing it to \fBfree\fR.
+.PP
+The header file \fBtcl.h\fR defines the actual data structures
+used to implement hash tables.
+This is necessary so that clients can allocate Tcl_HashTable
+structures and so that macros can be used to read and write
+the values of entries.
+However, users of the hashing routines should never refer directly
+to any of the fields of any of the hash-related data structures;
+use the procedures and macros defined here.
+
+.SH KEYWORDS
+hash table, key, lookup, search, value
diff --git a/vendor/x11iraf/obm/Tcl/doc/Interp.3 b/vendor/x11iraf/obm/Tcl/doc/Interp.3
new file mode 100644
index 00000000..a93cfccb
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Interp.3
@@ -0,0 +1,132 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Interp.3,v 1.10 93/04/01 09:25:32 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_Interp tclc
+.BS
+.SH NAME
+Tcl_Interp \- client-visible fields of interpreter structures
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+typedef struct {
+ char *\fIresult\fR;
+ Tcl_FreeProc *\fIfreeProc\fR;
+ int \fIerrorLine\fR;
+} Tcl_Interp;
+
+typedef void Tcl_FreeProc(char *\fIblockPtr\fR);
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fBTcl_CreateInterp\fR procedure returns a pointer to a Tcl_Interp
+structure. This pointer is then passed into other Tcl procedures
+to process commands in the interpreter and perform other operations
+on the interpreter. Interpreter structures contain many many fields
+that are used by Tcl, but only three that may be accessed by
+clients: \fIresult\fR, \fIfreeProc\fR, and \fIerrorLine\fR.
+.PP
+The \fIresult\fR and \fIfreeProc\fR fields are used to return
+results or error messages from commands.
+This information is returned by command procedures back to \fBTcl_Eval\fR,
+and by \fBTcl_Eval\fR back to its callers.
+The \fIresult\fR field points to the string that represents the
+result or error message, and the \fIfreeProc\fR field tells how
+to dispose of the storage for the string when it isn't needed anymore.
+The easiest way for command procedures to manipulate these
+fields is to call procedures like \fBTcl_SetResult\fR
+or \fBTcl_AppendResult\fR; they
+will hide all the details of managing the fields.
+The description below is for those procedures that manipulate the
+fields directly.
+.PP
+Whenever a command procedure returns, it must ensure
+that the \fIresult\fR field of its interpreter points to the string
+being returned by the command.
+The \fIresult\fR field must always point to a valid string.
+If a command wishes to return no result then \fIinterp->result\fR
+should point to an empty string.
+Normally, results are assumed to be statically allocated,
+which means that the contents will not change before the next time
+\fBTcl_Eval\fR is called or some other command procedure is invoked.
+In this case, the \fIfreeProc\fR field must be zero.
+Alternatively, a command procedure may dynamically
+allocate its return value (e.g. using \fBmalloc\fR)
+and store a pointer to it in \fIinterp->result\fR.
+In this case, the command procedure must also set \fIinterp->freeProc\fR
+to the address of a procedure that can free the value (usually \fBfree\fR).
+If \fIinterp->freeProc\fR is non-zero, then Tcl will call \fIfreeProc\fR
+to free the space pointed to by \fIinterp->result\fR before it
+invokes the next command.
+If a client procedure overwrites \fIinterp->result\fR when
+\fIinterp->freeProc\fR is non-zero, then it is responsible for calling
+\fIfreeProc\fR to free the old \fIinterp->result\fR (the \fBTcl_FreeResult\fR
+macro should be used for this purpose).
+.PP
+\fIFreeProc\fR should have arguments and result that match the
+\fBTcl_FreeProc\fR declaration above: it receives a single
+argument which is a pointer to the result value to free.
+In most applications \fBfree\fR is the only non-zero value ever
+used for \fIfreeProc\fR.
+However, an application may store a different procedure address
+in \fIfreeProc\fR in order to use an alternate memory allocator
+or in order to do other cleanup when the result memory is freed.
+.PP
+As part of processing each command, \fBTcl_Eval\fR initializes
+\fIinterp->result\fR
+and \fIinterp->freeProc\fR just before calling the command procedure for
+the command. The \fIfreeProc\fR field will be initialized to zero,
+and \fIinterp->result\fR will point to an empty string. Commands that
+do not return any value can simply leave the fields alone.
+Furthermore, the empty string pointed to by \fIresult\fR is actually
+part of an array of \fBTCL_RESULT_SIZE\fR characters (approximately 200).
+If a command wishes to return a short string, it can simply copy
+it to the area pointed to by \fIinterp->result\fR. Or, it can use
+the sprintf procedure to generate a short result string at the location
+pointed to by \fIinterp->result\fR.
+.PP
+It is a general convention in Tcl-based applications that the result
+of an interpreter is normally in the initialized state described
+in the previous paragraph.
+Procedures that manipulate an interpreter's result (e.g. by
+returning an error) will generally assume that the result
+has been initialized when the procedure is called.
+If such a procedure is to be called after the result has been
+changed, then \fBTcl_ResetResult\fR should be called first to
+reset the result to its initialized state.
+.PP
+The \fIerrorLine\fR
+field is valid only after \fBTcl_Eval\fR returns
+a \fBTCL_ERROR\fR return code. In this situation the \fIerrorLine\fR
+field identifies the line number of the command being executed when
+the error occurred. The line numbers are relative to the command
+being executed: 1 means the first line of the command passed to
+\fBTcl_Eval\fR, 2 means the second line, and so on.
+The \fIerrorLine\fR field is typically used in conjunction with
+\fBTcl_AddErrorInfo\fR to report information about where an error
+occurred.
+\fIErrorLine\fR should not normally be modified except by \fBTcl_Eval\fR.
+
+.SH KEYWORDS
+free, initialized, interpreter, malloc, result
diff --git a/vendor/x11iraf/obm/Tcl/doc/LinkVar.3 b/vendor/x11iraf/obm/Tcl/doc/LinkVar.3
new file mode 100644
index 00000000..f44c96c6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/LinkVar.3
@@ -0,0 +1,113 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/LinkVar.3,v 1.4 93/07/28 15:18:56 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_LinkVar tclc 7.0
+.BS
+.SH NAME
+.na
+Tcl_LinkVar, Tcl_UnlinkVar \- link Tcl variable to C variable
+.ad
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_LinkVar\fR(\fIinterp, varName, addr, type\fR)
+.sp
+\fBTcl_UnlinkVar\fR(\fIinterp, varName\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp writable
+.AP Tcl_Interp *interp in
+Interpreter that contains \fIvarName\fR.
+Also used by \fBTcl_LinkVar\fR to return error messages.
+.AP char *varName in
+Name of global variable.
+.AP char *addr in
+Address of C variable that is to be linked to \fIvarName\fR.
+.AP int type in
+.na
+Type of C variable. Must be one of TCL_LINK_INT, TCL_LINK_DOUBLE,
+TCL_LINK_BOOLEAN, or TCL_LINK_STRING, optionally OR'ed with
+TCL_LINK_READ_ONLY to make Tcl variable read-only.
+.ad
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_LinkVar\fR uses variable traces to keep the Tcl variable
+named by \fIvarName\fR in sync with the C variable at the address
+given by \fIaddr\fR.
+Whenever the Tcl variable is read the value of the C variable will
+be returned, and whenever the Tcl variable is written the C
+variable will be updated to have the same value.
+\fBTcl_LinkVar\fR normally returns TCL_OK; if an error occurs
+while setting up the link (e.g. because \fIvarName\fR is the
+name of array) then TCL_ERROR is returned and \fIinterp->result\fR
+contains an error message.
+.PP
+The \fItype\fR argument specifies the type of the C variable,
+and must have one of the following values, optionally OR'ed with
+TCL_LINK_READ_ONLY:
+.TP
+\fBTCL_LINK_INT\fR
+The C variable is of type \fBint\fR.
+Any value written into the Tcl variable must have a proper integer
+form acceptable to \fBTcl_GetInt\fR; attempts to write
+non-integer values into \fIvarName\fR will be rejected with
+Tcl errors.
+.TP
+\fBTCL_LINK_DOUBLE\fR
+The C variable is of type \fBdouble\fR.
+Any value written into the Tcl variable must have a proper real
+form acceptable to \fBTcl_GetDouble\fR; attempts to write
+non-real values into \fIvarName\fR will be rejected with
+Tcl errors.
+.TP
+\fBTCL_LINK_BOOLEAN\fR
+The C variable is of type \fBint\fR.
+If its value is zero then it will read from Tcl as ``0'';
+otherwise it will read from Tcl as ``1''.
+Whenver \fIvarName\fR is
+modified, the C variable will be set to a 0 or 1 value.
+Any value written into the Tcl variable must have a proper boolean
+form acceptable to \fBTcl_GetBoolean\fR; attempts to write
+non-boolean values into \fIvarName\fR will be rejected with
+Tcl errors.
+.TP
+\fBTCL_LINK_STRING\fR
+The C variable is of type \fBchar *\fR.
+If its value is not null then it must be a pointer to a string
+allocated with \fBmalloc\fR.
+Whenever the Tcl variable is modified the current C string will be
+freed and new memory will be allocated to hold a copy of the variable's
+new value.
+If the C variable contains a null pointer then the Tcl variable
+will read as ``NULL''.
+.PP
+If the TCL_LINK_READ_ONLY flag is present in \fItype\fR then the
+variable will be read-only from Tcl, so that its value can only be
+changed by modifying the C variable.
+Attempts to write the variable from Tcl will be rejected with errors.
+
+.SH KEYWORDS
+boolean, integer, link, read-only, real, string, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/PrintDbl.3 b/vendor/x11iraf/obm/Tcl/doc/PrintDbl.3
new file mode 100644
index 00000000..51d7f884
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/PrintDbl.3
@@ -0,0 +1,58 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/PrintDbl.3,v 1.2 93/06/05 15:32:01 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_PrintDouble tclc 7.0
+.BS
+.SH NAME
+Tcl_PrintDouble \- Convert floating value to string
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_PrintDouble\fR(\fIinterp, value, dst\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp
+.AP Tcl_Interp *interp in
+Interpreter that controls the conversion.
+.AP double value in
+Floating-point value to be converted.
+.AP char *dst out
+Where to store string representing \fIvalue\fR. Must have at
+least TCL_DOUBLE_SPACE characters of storage.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_PrintDouble\fR generates a string that represents the value
+of \fIvalue\fR and stores it in memory at the location given by
+\fIdst\fR. It uses %g format to generate the string, with two
+special twists. First, the string is guaranteed to contain either
+a ``.'' or an ``e'' so that it doesn't look like an integer (where
+%g would generate an integer with no decimal point, \fBTcl_PrintDouble\fR
+adds ``.0''). Second, the number of significant digits printed at
+\fIdst\fR is controlled by the \fBtcl_precision\fR variable in
+\fIinterp\fR; if \fBtcl_precision\fR is undefined then 6 significant
+digits are printed.
+
+.SH KEYWORDS
+conversion, double-precision, floating-point, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/RecordEval.3 b/vendor/x11iraf/obm/Tcl/doc/RecordEval.3
new file mode 100644
index 00000000..02e11d8c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/RecordEval.3
@@ -0,0 +1,60 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/RecordEval.3,v 1.9 93/04/16 15:02:27 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_RecordAndEval tclc
+.BS
+.SH NAME
+Tcl_RecordAndEval \- save command on history list before evaluating
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_RecordAndEval\fR(\fIinterp, cmd, eval\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp;
+.AP Tcl_Interp *interp in
+Tcl interpreter in which to evaluate command.
+.AP char *cmd in
+Command (or sequence of commands) to execute.
+.AP int eval in
+0 means evaluate \fIcmd\fR, TCL_NO_EVAL means record it but don't
+evaluate it.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_RecordAndEval\fR is invoked to record a command as an event
+on the history list and then execute it.
+It returns a completion code such as TCL_OK just like \fBTcl_Eval\fR
+and it leaves information in \fIinterp->result\fR.
+If you don't want the command recorded on the history list then
+you should invoke \fBTcl_Eval\fR instead of \fBTcl_RecordAndEval\fR.
+Normally \fBTcl_RecordAndEval\fR is only called with top-level
+commands typed by the user, since the purpose of history is to
+allow the user to re-issue recently-invoked commands.
+If the \fIeval\fR argument is TCL_NO_EVAL then the command is
+recorded without being evaluated.
+
+.SH KEYWORDS
+command, event, execute, history, interpreter, record
diff --git a/vendor/x11iraf/obm/Tcl/doc/RegExp.3 b/vendor/x11iraf/obm/Tcl/doc/RegExp.3
new file mode 100644
index 00000000..13546ee6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/RegExp.3
@@ -0,0 +1,57 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/RegExp.3,v 1.1 93/05/05 17:06:04 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_RegExpMatch tclc 7.0
+.BS
+.SH NAME
+Tcl_RegExpMatch \- Test whether a string matches a regular expression
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_RegExpMatch\fR(\fIinterp\fR, \fIstring\fR, \fIregexp\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp
+.AP Tcl_Interp *interp in
+Tcl interpreter to use for error reporting.
+.AP char *string in
+String to test.
+.AP char *regexp in
+Regular expression to match against \fIstring\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_RegExpMatch\fR determines whether its \fIstring\fR argument
+matches \fIregexp\fR, where \fIregexp\fR is interpreted
+as a regular expression using the same rules as for the
+\fBregexp\fR Tcl command.
+If there is a match then \fBTcl_RegExpMatch\fR returns 1.
+If there is no match then \fBTcl_RegExpMatch\fR returns 0.
+If an error occurs in the matching process (e.g. \fIregexp\fR
+is not a valid regular expression) then \fBTcl_RegExpMatch\fR
+returns \-1 and leaves an error message in \fIinterp->result\fR.
+
+.SH KEYWORDS
+match, regular expression, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/SetRecLmt.3 b/vendor/x11iraf/obm/Tcl/doc/SetRecLmt.3
new file mode 100644
index 00000000..3010a86d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/SetRecLmt.3
@@ -0,0 +1,60 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/SetRecLmt.3,v 1.1 93/07/07 16:35:18 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_SetRecursionLimit tclc 7.0
+.BS
+.SH NAME
+Tcl_SetRecursionLimit \- set maximum allowable nesting depth in interpreter
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_SetRecursionLimit\fR(\fIinterp, depth\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *interp
+.AP Tcl_Interp *interp in
+Interpreter whose recursion limit is to be set.
+Must be greater than zero.
+.AP int depth in
+New limit for nested calls to \fBTcl_Eval\fR for \fIinterp\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+At any given time Tcl enforces a limit on the number of recursive
+calls that may be active for \fBTcl_Eval\fR and related procedures
+such as \fBTcl_GlobalEval\fR.
+Any call to \fBTcl_Eval\fR that exceeds this depth is aborted with
+an error.
+By default the recursion limit is 1000.
+.PP
+\fBTcl_SetRecursionLimit\fR may be used to change the maximum
+allowable nesting depth for an interpreter.
+The \fIdepth\fR argument specifies a new limit for \fIinterp\fR,
+and \fBTcl_SetRecursionLimit\fR returns the old limit.
+To read out the old limit without modifying it, invoke
+\fBTcl_SetRecursionDepth\fR with \fIdepth\fR equal to 0.
+
+.SH KEYWORDS
+nesting depth, recursion
diff --git a/vendor/x11iraf/obm/Tcl/doc/SetResult.3 b/vendor/x11iraf/obm/Tcl/doc/SetResult.3
new file mode 100644
index 00000000..94835acd
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/SetResult.3
@@ -0,0 +1,162 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/SetResult.3,v 1.12 93/04/03 15:05:59 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_SetResult tclc 7.0
+.BS
+.SH NAME
+Tcl_SetResult, Tcl_AppendResult, Tcl_AppendElement, Tcl_ResetResult \- manipulate Tcl result string
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+\fBTcl_SetResult\fR(\fIinterp, string, freeProc\fR)
+.sp
+\fBTcl_AppendResult(\fIinterp, string, string, ... , \fB(char *) NULL\fR)
+.sp
+.VS
+\fBTcl_AppendElement\fR(\fIinterp, string\fR)
+.VE
+.sp
+\fBTcl_ResetResult\fR(\fIinterp\fR)
+.sp
+\fBTcl_FreeResult\fR(\fIinterp\fR)
+.SH ARGUMENTS
+.AS Tcl_FreeProc freeProc
+.AP Tcl_Interp *interp out
+Interpreter whose result is to be modified.
+.AP char *string in
+String value to become result for \fIinterp\fR or to be
+appended to existing result.
+.AP Tcl_FreeProc freeProc in
+Address of procedure to call to release storage at
+\fIstring\fR, or \fBTCL_STATIC\fR, \fBTCL_DYNAMIC\fR, or
+\fBTCL_VOLATILE\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+The procedures described here are utilities for setting the
+result/error string in a Tcl interpreter.
+.PP
+\fBTcl_SetResult\fR
+arranges for \fIstring\fR to be the return string for the current Tcl
+command in \fIinterp\fR, replacing any existing result.
+If \fIfreeProc\fR is \fBTCL_STATIC\fR it means that \fIstring\fR
+refers to an area of static storage that is guaranteed not to be
+modified until at least the next call to \fBTcl_Eval\fR.
+If \fIfreeProc\fR
+is \fBTCL_DYNAMIC\fR it means that \fIstring\fR was allocated with a call
+to \fBmalloc()\fR and is now the property of the Tcl system.
+\fBTcl_SetResult\fR will arrange for the string's storage to be
+released by calling \fBfree()\fR when it is no longer needed.
+If \fIfreeProc\fR is \fBTCL_VOLATILE\fR it means that \fIstring\fR
+points to an area of memory that is likely to be overwritten when
+\fBTcl_SetResult\fR returns (e.g. it points to something in a stack frame).
+In this case \fBTcl_SetResult\fR will make a copy of the string in
+dynamically allocated storage and arrange for the copy to be the
+return string for the current Tcl command.
+.PP
+If \fIfreeProc\fR isn't one of the values \fBTCL_STATIC\fR,
+\fBTCL_DYNAMIC\fR, and \fBTCL_VOLATILE\fR, then it is the address
+of a procedure that Tcl should call to free the string.
+This allows applications to use non-standard storage allocators.
+When Tcl no longer needs the storage for the string, it will
+call \fIfreeProc\fR. \fIFreeProc\fR should have arguments and
+result that match the type \fBTcl_FreeProc\fR:
+.nf
+.RS
+
+typedef void Tcl_FreeProc(char *\fIblockPtr\fR);
+
+.RE
+.fi
+When \fIfreeProc\fR is called, its \fIblockPtr\fR will be set to
+the value of \fIstring\fR passed to \fBTcl_SetResult\fR.
+.PP
+If \fIstring\fR is \fBNULL\fR, then \fIfreeProc\fR is ignored
+and \fBTcl_SetResult\fR
+re-initializes \fIinterp\fR's result to point to the pre-allocated result
+area, with an empty string in the result area.
+.PP
+If \fBTcl_SetResult\fR is called at a time when \fIinterp\fR holds a
+result, \fBTcl_SetResult\fR does whatever is necessary to dispose
+of the old result (see the \fBTcl_Interp\fR manual entry for details
+on this).
+.PP
+\fBTcl_AppendResult\fR makes it easy to build up Tcl results in pieces.
+It takes each of its \fIstring\fR arguments and appends them in order
+to the current result associated with \fIinterp\fR.
+If the result is in its initialized empty state (e.g. a command procedure
+was just invoked or \fBTcl_ResetResult\fR was just called),
+then \fBTcl_AppendResult\fR sets the result to the concatenation of
+its \fIstring\fR arguments.
+\fBTcl_AppendResult\fR may be called repeatedly as additional pieces
+of the result are produced.
+\fBTcl_AppendResult\fR takes care of all the
+storage management issues associated with managing \fIinterp\fR's
+result, such as allocating a larger result area if necessary.
+Any number of \fIstring\fR arguments may be passed in a single
+call; the last argument in the list must be a NULL pointer.
+.PP
+\fBTcl_AppendElement\fR is similar to \fBTcl_AppendResult\fR in
+that it allows results to be built up in pieces.
+However, \fBTcl_AppendElement\fR takes only a single \fIstring\fR
+argument and it appends that argument to the current result
+as a proper Tcl list element.
+\fBTcl_AppendElement\fR adds backslashes or braces if necessary
+to ensure that \fIinterp\fR's result can be parsed as a list and that
+\fIstring\fR will be extracted as a single element.
+Under normal conditions, \fBTcl_AppendElement\fR will add a space
+character to \fIinterp\fR's result just before adding the new
+list element, so that the list elements in the result are properly
+separated.
+.VS
+However if the new list element is the first in a list or sub-list
+(i.e. \fIinterp\fR's current result is empty, or consists of the
+single character ``{'', or ends in the characters `` {'') then no
+space is added.
+.VE
+.PP
+\fBTcl_ResetResult\fR clears the result for \fIinterp\fR,
+freeing the memory associated with it if the current result was
+dynamically allocated.
+It leaves the result in its normal initialized state with
+\fIinterp->result\fR pointing to a static buffer containing
+\fBTCL_RESULT_SIZE\fR characters, of which the first character
+is zero.
+\fBTcl_ResetResult\fR also clears the error state managed by
+\fBTcl_AddErrorInfo\fR and \fBTcl_SetErrorCode\fR.
+.PP
+\fBTcl_FreeResult\fR is a macro that performs part of the work
+of \fBTcl_ResetResult\fR.
+It frees up the memory associated with \fIinterp\fR's result
+and sets \fIinterp->freeProc\fR to zero, but it doesn't
+change \fIinterp->result\fR or clear error state.
+\fBTcl_FreeResult\fR is most commonly used when a procedure
+is about to replace one result value with another.
+
+.SH "SEE ALSO"
+Tcl_AddErrorInfo, Tcl_SetErrorCode, Tcl_Interp
+
+.SH KEYWORDS
+append, command, element, list, result, return value, interpreter
diff --git a/vendor/x11iraf/obm/Tcl/doc/SetVar.3 b/vendor/x11iraf/obm/Tcl/doc/SetVar.3
new file mode 100644
index 00000000..087ebf8c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/SetVar.3
@@ -0,0 +1,166 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/SetVar.3,v 1.15 93/06/05 15:40:17 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_SetVar tclc 7.0
+.BS
+.SH NAME
+Tcl_SetVar, Tcl_SetVar2, Tcl_GetVar, Tcl_GetVar2, Tcl_UnsetVar, Tcl_UnsetVar2 \- manipulate Tcl variables
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+char *
+\fBTcl_SetVar\fR(\fIinterp, varName, newValue, flags\fR)
+.sp
+char *
+\fBTcl_SetVar2\fR(\fIinterp, name1, name2, newValue, flags\fR)
+.sp
+char *
+\fBTcl_GetVar\fR(\fIinterp, varName, flags\fR)
+.sp
+char *
+\fBTcl_GetVar2\fR(\fIinterp, name1, name2, flags\fR)
+.sp
+int
+\fBTcl_UnsetVar\fR(\fIinterp, varName, flags\fR)
+.sp
+int
+\fBTcl_UnsetVar2\fR(\fIinterp, name1, name2, flags\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp *newValue
+.AP Tcl_Interp *interp in
+Interpreter containing variable.
+.AP char *varName in
+Name of variable. May refer to a scalar variable or an element of
+an array variable.
+.AP char *newValue in
+New value for variable.
+.AP int flags in
+OR-ed combination of bits providing additional information for
+operation. See below for valid values.
+.AP char *name1 in
+Name of scalar variable, or name of array variable if \fIname2\fR
+is non-NULL.
+.AP char *name2 in
+If non-NULL, gives name of element within array and \fIname1\fR
+must refer to an array variable.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures may be used to create, modify, read, and delete
+Tcl variables from C code.
+\fBTcl_SetVar\fR and \fBTcl_SetVar2\fR will create a new variable
+or modify an existing one.
+Both of these procedures set the given variable to the value
+given by \fInewValue\fR, and they return a pointer to a
+copy of the variable's new value, which is stored in Tcl's
+variable structure.
+Tcl keeps a private copy of the variable's value, so the caller
+may change \fInewValue\fR after these procedures return without
+affecting the value of the variable.
+If an error occurs in setting the variable (e.g. an array
+variable is referenced without giving an index into the array),
+then NULL is returned.
+.PP
+The name of the variable may be specified in either of two ways.
+If \fBTcl_SetVar\fR is called, the variable name is given as
+a single string, \fIvarName\fR.
+If \fIvarName\fR contains an open parenthesis and ends with a
+close parenthesis, then the value between the parentheses is
+treated as an index (which can have any string value) and
+the characters before the first open
+parenthesis are treated as the name of an array variable.
+If \fIvarName\fR doesn't have parentheses as described above, then
+the entire string is treated as the name of a scalar variable.
+If \fBTcl_SetVar2\fR is called, then the array name and index
+have been separated by the caller into two separate strings,
+\fIname1\fR and \fIname2\fR respectively; if \fIname2\fR is
+zero it means that a scalar variable is being referenced.
+.PP
+The \fIflags\fR argument may be used to specify any of several
+options to the procedures.
+It consists of an OR-ed combination of any of the following
+bits:
+.IP TCL_GLOBAL_ONLY
+Under normal circumstances the procedures look up variables
+at the current level of procedure call for \fIinterp\fR, or
+at global level if there is no call active.
+However, if this bit is set in \fIflags\fR then the variable
+is looked up at global level even if there is a procedure
+call active.
+.IP TCL_LEAVE_ERR_MSG
+If an error is returned and this bit is set in \fIflags\fR, then
+an error message will be left in \fI\%interp->result\fR. If this
+flag bit isn't set then no error message is left (\fI\%interp->result\fR
+will not be modified).
+.IP TCL_APPEND_VALUE
+If this bit is set then \fInewValue\fR is appended to the current
+value, instead of replacing it.
+If the variable is currently undefined, then this bit is ignored.
+.IP TCL_LIST_ELEMENT
+If this bit is set, then \fInewValue\fR is converted to a valid
+Tcl list element before setting (or appending to) the variable.
+A separator space is appended before the new list element unless
+.VS
+the list element is going to be the first element in a list or
+sublist (i.e. the variable's current value is empty, or contains
+the single character ``{'', or ends in `` }'').
+.VE
+.PP
+\fBTcl_GetVar\fR and \fBTcl_GetVar2\fR return the current value
+of a variable.
+The arguments to these procedures are treated in the same way
+as the arguments to \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR.
+Under normal circumstances, the return value is a pointer
+to the variable's value (which is stored in Tcl's variable
+structure and will not change before the next call to \fBTcl_SetVar\fR
+or \fBTcl_SetVar2\fR).
+The only bits of \fIflags\fR that are used are TCL_GLOBAL_ONLY
+and TCL_LEAVE_ERR_MSG, both of
+which have
+the same meaning as for \fBTcl_SetVar\fR.
+If an error occurs in reading the variable (e.g. the variable
+doesn't exist or an array element is specified for a scalar
+variable), then NULL is returned.
+.PP
+\fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove
+a variable, so that future calls to \fBTcl_GetVar\fR or \fBTcl_GetVar2\fR
+for the variable will return an error.
+The arguments to these procedures are treated in the same way
+as the arguments to \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR.
+.VS
+If the variable is successfully removed then TCL_OK is returned.
+If the variable cannot be removed because it doesn't exist then
+TCL_ERROR is returned.
+.VE
+If an array element is specified, the given element is removed
+but the array remains.
+If an array name is specified without an index, then the entire
+array is removed.
+
+.SH "SEE ALSO"
+Tcl_TraceVar
+
+.SH KEYWORDS
+array, interpreter, scalar, set, unset, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/SplitList.3 b/vendor/x11iraf/obm/Tcl/doc/SplitList.3
new file mode 100644
index 00000000..c5964896
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/SplitList.3
@@ -0,0 +1,164 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/SplitList.3,v 1.11 93/04/01 09:25:34 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_SplitList tclc
+.BS
+.SH NAME
+Tcl_SplitList, Tcl_Merge, Tcl_ScanElement, Tcl_ConvertElement \- manipulate Tcl lists
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_SplitList\fR(\fIinterp, list, argcPtr, argvPtr\fR)
+.sp
+char *
+\fBTcl_Merge\fR(\fIargc, argv\fR)
+.sp
+int
+\fBTcl_ScanElement\fR(\fIsrc, flagsPtr\fR)
+.sp
+int
+\fBTcl_ConvertElement\fR(\fIsrc, dst, flags\fR)
+.SH ARGUMENTS
+.AS Tcl_Interp ***argvPtr
+.AP Tcl_Interp *interp out
+Interpreter to use for error reporting.
+.AP char *list in
+Pointer to a string with proper list structure.
+.AP int *argcPtr out
+Filled in with number of elements in \fIlist\fR.
+.AP char ***argvPtr out
+\fI*argvPtr\fR will be filled in with the address of an array of
+pointers to the strings that are the extracted elements of \fIlist\fR.
+There will be \fI*argcPtr\fR valid entries in the array, followed by
+a NULL entry.
+.AP int argc in
+Number of elements in \fIargv\fR.
+.AP char **argv in
+Array of strings to merge together into a single list.
+Each string will become a separate element of the list.
+.AP char *src in
+String that is to become an element of a list.
+.AP int *flagsPtr in
+Pointer to word to fill in with information about \fIsrc\fR.
+The value of *\fIflagsPtr\fR must be passed to \fBTcl_ConvertElement\fR.
+.AP char *dst in
+Place to copy converted list element. Must contain enough characters
+to hold converted string.
+.AP int flags in
+Information about \fIsrc\fR. Must be value returned by previous
+call to \fBTcl_ScanElement\fR, possibly OR-ed
+with \fBTCL_DONT_USE_BRACES\fR.
+.BE
+
+.SH DESCRIPTION
+.PP
+These procedures may be used to disassemble and reassemble Tcl lists.
+\fBTcl_SplitList\fR breaks a list up into its constituent elements,
+returning an array of pointers to the elements using
+\fIargcPtr\fR and \fIargvPtr\fR.
+While extracting the arguments, \fBTcl_SplitList\fR obeys the usual
+rules for backslash substitutions and braces. The area of
+memory pointed to by \fI*argvPtr\fR is dynamically allocated; in
+addition to the array of pointers, it
+also holds copies of all the list elements. It is the caller's
+responsibility to free up all of this storage by calling
+.DS
+\fBfree\fR((char *) \fI*argvPtr\fR)
+.DE
+when the list elements are no longer needed.
+.PP
+\fBTcl_SplitList\fR normally returns \fBTCL_OK\fR, which means the list was
+successfully parsed.
+If there was a syntax error in \fIlist\fR, then \fBTCL_ERROR\fR is returned
+and \fIinterp->result\fR will point to an error message describing the
+problem.
+If \fBTCL_ERROR\fR is returned then no memory is allocated and \fI*argvPtr\fR
+is not modified.
+.PP
+\fBTcl_Merge\fR is the inverse of \fBTcl_SplitList\fR: it
+takes a collection of strings given by \fIargc\fR
+and \fIargv\fR and generates a result string
+that has proper list structure.
+This means that commands like \fBindex\fR may be used to
+extract the original elements again.
+In addition, if the result of \fBTcl_Merge\fR is passed to \fBTcl_Eval\fR,
+it will be parsed into \fIargc\fR words whose values will
+be the same as the \fIargv\fR strings passed to \fBTcl_Merge\fR.
+\fBTcl_Merge\fR will modify the list elements with braces and/or
+backslashes in order to produce proper Tcl list structure.
+The result string is dynamically allocated
+using \fBmalloc()\fR; the caller must eventually release the space
+using \fBfree()\fR.
+.PP
+If the result of \fBTcl_Merge\fR is passed to \fBTcl_SplitList\fR,
+the elements returned by \fBTcl_SplitList\fR will be identical to
+those passed into \fBTcl_Merge\fR.
+However, the converse is not true: if \fBTcl_SplitList\fR
+is passed a given string, and the resulting \fIargc\fR and
+\fIargv\fR are passed to \fBTcl_Merge\fR, the resulting string
+may not be the same as the original string passed to \fBTcl_SplitList\fR.
+This is because \fBTcl_Merge\fR may use backslashes and braces
+differently than the original string.
+.PP
+\fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR are the
+procedures that do all of the real work of \fBTcl_Merge\fR.
+\fBTcl_ScanElement\fR scans its \fIsrc\fR argument
+and determines how to use backslashes and braces
+when converting it to a list element.
+It returns an overestimate of the number of characters
+required to represent \fIsrc\fR as a list element, and
+it stores information in \fI*flagsPtr\fR that is needed
+by \fBTcl_ConvertElement\fR.
+.PP
+\fBTcl_ConvertElement\fR is a companion procedure to \fBTcl_ScanElement\fR.
+It does the actual work of converting a string to a list element.
+Its \fIflags\fR argument must be the same as the value returned
+by \fBTcl_ScanElement\fR.
+\fBTcl_ConvertElement\fR writes a proper list element to memory
+starting at *\fIdst\fR and returns a count of the total number
+of characters written, which will be no more than the result
+returned by \fBTcl_ScanElement\fR.
+\fBTcl_ConvertElement\fR writes out only the actual list element
+without any leading or trailing spaces: it is up to the caller to
+include spaces between adjacent list elements.
+.PP
+\fBTcl_ConvertElement\fR uses one of two different approaches to
+handle the special characters in \fIsrc\fR. Wherever possible, it
+handles special characters by surrounding the string with braces.
+This produces clean-looking output, but can't be used in some situations,
+such as when \fIsrc\fR contains unmatched braces.
+In these situations, \fBTcl_ConvertElement\fR handles special
+characters by generating backslash sequences for them.
+The caller may insist on the second approach by OR-ing the
+flag value returned by \fBTcl_ScanElement\fR with
+\fBTCL_DONT_USE_BRACES\fR.
+Although this will produce an uglier result, it is useful in some
+special situations, such as when \fBTcl_ConvertElement\fR is being
+used to generate a portion of an argument for a Tcl command.
+In this case, surrounding \fIsrc\fR with curly braces would cause
+the command not to be parsed correctly.
+
+.SH KEYWORDS
+backslash, convert, element, list, merge, split, strings
diff --git a/vendor/x11iraf/obm/Tcl/doc/StrMatch.3 b/vendor/x11iraf/obm/Tcl/doc/StrMatch.3
new file mode 100644
index 00000000..d99c648f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/StrMatch.3
@@ -0,0 +1,52 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/StrMatch.3,v 1.7 93/04/01 09:25:35 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_StringMatch tclc
+.BS
+.SH NAME
+Tcl_StringMatch \- test whether a string matches a pattern
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_StringMatch\fR(\fIstring\fR, \fIpattern\fR)
+.SH ARGUMENTS
+.AP char *string in
+String to test.
+.AP char *pattern in
+Pattern to match against string. May contain special
+characters from the set *?\e[].
+.BE
+
+.SH DESCRIPTION
+.PP
+This utility procedure determines whether a string matches
+a given pattern. If it does, then \fBTcl_StringMatch\fR returns
+1. Otherwise \fBTcl_StringMatch\fR returns 0. The algorithm
+used for matching is the same algorithm used in the ``string match''
+Tcl command and is similar to the algorithm used by the C-shell
+for file name matching; see the Tcl manual entry for details.
+
+.SH KEYWORDS
+match, pattern, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/Tcl.n b/vendor/x11iraf/obm/Tcl/doc/Tcl.n
new file mode 100644
index 00000000..e6d85731
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/Tcl.n
@@ -0,0 +1,205 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/Tcl.n,v 1.118 93/07/28 14:13:25 ouster Exp $ SPRITE (Berkeley)
+'
+.so man.macros
+.de UL
+\\$1\l'|0\(ul'\\$2
+..
+.HS Tcl tcl
+.BS
+.SH NAME
+Tcl \- Summary of Tcl language syntax.
+.BE
+
+.SH DESCRIPTION
+.LP
+The following rules define the syntax and semantics of the Tcl language:
+.IP [1]
+A Tcl script is a string containing one or more commands.
+Semi-colons and newlines are command separators unless quoted as
+described below.
+Close brackets are command terminators during command substitution
+(see below) unless quoted.
+.IP [2]
+A command is evaluated in two steps.
+First, the Tcl interpreter breaks the command into \fIwords\fR
+and performs substitutions as described below.
+These substitutions are performed in the same way for all
+commands.
+The first word is used to locate a command procedure to
+carry out the command, then all of the words of the command are
+passed to the command procedure.
+The command procedure is free to interpret each of its words
+in any way it likes, such as an integer, variable name, list,
+or Tcl script.
+Different commands interpret their words differently.
+.IP [3]
+Words of a command are separated by white space (except for
+newlines, which are command separators).
+.IP [4]
+If the first character of a word is double-quote (``"'') then
+the word is terminated by the next double-quote character.
+If semi-colons, close brackets, or white space characters
+(including newlines) appear between the quotes then they are treated
+as ordinary characters and included in the word.
+Command substitution, variable substitution, and backslash substitution
+are performed on the characters between the quotes as described below.
+The double-quotes are not retained as part of the word.
+.IP [5]
+If the first character of a word is an open brace (``{'') then
+the word is terminated by the matching close brace (``}'').
+Braces nest within the word: for each additional open
+brace there must be an additional close brace (however,
+if an open brace or close brace within the word is
+quoted with a backslash then it is not counted in locating the
+matching close brace).
+No substitutions are performed on the characters between the
+braces except for backslash-newline substitutions described
+below, nor do semi-colons, newlines, close brackets,
+or white space receive any special interpretation.
+The word will consist of exactly the characters between the
+outer braces, not including the braces themselves.
+.IP [6]
+If a word contains an open bracket (``['') then Tcl performs
+\fIcommand substitution\fR.
+To do this it invokes the Tcl interpreter recursively to process
+the characters following the open bracket as a Tcl script.
+The script may contain any number of commands and must be terminated
+by a close bracket (``]'').
+The result of the script (i.e. the result of its last command) is
+substituted into the word in place of the brackets and all of the
+characters between them.
+There may be any number of command substitutions in a single word.
+Command substitution is not performed on words enclosed in braces.
+.IP [7]
+If a word contains a dollar-sign (``$'') then Tcl performs \fIvariable
+substitution\fR: the dollar-sign and the following characters are
+replaced in the word by the value of a variable.
+Variable substition may take any of the following forms:
+.RS
+.TP 15
+\fB$\fIname\fR
+\fIName\fR is the name of a scalar variable; the name is terminated
+by any character that isn't a letter, digit, or underscore.
+.TP 15
+\fB$\fIname\fB(\fIindex\fB)\fR
+\fIName\fR gives the name of an array variable and \fIindex\fR gives
+the name of an element within that array.
+\fIName\fR must contain only letters, digits, and underscores.
+Command substitutions, variable substitutions, and backslash
+substitutions are performed on the characters of \fIindex\fR.
+.TP 15
+\fB${\fIname\fB}\fR
+\fIName\fR is the name of a scalar variable. It may contain any
+characters whatsoever except for close braces.
+.RE
+.LP
+There may be any number of variable substitutions in a single word.
+Variable substitution is not performed on words enclosed in braces.
+.IP [8]
+If a backslash (``\e'') appears within a word then
+\fIbackslash substitution\fR occurs.
+.VS
+In all cases but those described below the backslash is dropped and
+the following character is treated as an ordinary
+character and included in the word.
+.VE
+This allows characters such as double quotes, close brackets,
+and dollar signs to be included in words without triggering
+special processing.
+The following table lists the backslash sequences that are
+handled specially, along with the value that replaces each sequence.
+.RS
+.VS
+.TP 6
+\e\fBa\fR
+Audible alert (bell) (0x7).
+.VE
+.TP 6
+\e\fBb\fR
+Backspace (0x8).
+.TP 6
+\e\fBf\fR
+Form feed (0xc).
+.TP 6
+\e\fBn\fR
+Newline (0xa).
+.TP 6
+\e\fBr\fR
+Carriage-return (0xd).
+.TP 6
+\e\fBt\fR
+Tab (0x9).
+.TP 6
+\e\fBv\fR
+Vertical tab (0xb).
+.TP 6
+\e\fB<newline>\fIwhiteSpace\fR\fR
+.VS
+A single space character replaces the backslash, newline, and all
+white space after the newline.
+This backslash sequence is unique in that it is replaced in a separate
+pre-pass before the command is actually parsed.
+This means that it will be replaced even when it occurs between
+braces, and the resulting space will be treated as a word separator
+if it isn't in braces or quotes.
+.VE
+.TP 6
+\e\e
+Backslash (``\e'').
+.TP 6
+\e\fIooo\fR
+The digits \fIooo\fR (one, two, or three of them) give the octal value of
+the character.
+.TP 6
+\e\fBx\fIhh\fR
+.VS
+The hexadecimal digits \fIhh\fR give the hexadecimal value of
+the character. Any number of digits may be present.
+.VE
+.RE
+.LP
+Backslash substitution is not performed on words enclosed in braces,
+except for backslash-newline as described above.
+.IP [9]
+If a hash character (``#'') appears at a point where Tcl is
+expecting the first character of the first word of a command,
+then the hash character and the characters that follow it, up
+through the next newline, are treated as a comment and ignored.
+The comment character only has significance when it appears
+at the beginning of a command.
+.IP [10]
+Each character is processed exactly once by the Tcl interpreter
+as part of creating the words of a command.
+For example, if variable substition occurs then no further
+substitions are performed on the value of the variable; the
+value is inserted into the word verbatim.
+If command substitution occurs then the nested command is
+processed entirely by the recursive call to the Tcl interpreter;
+no substitutions are perfomed before making the recursive
+call and no additional substitutions are performed on the result
+of the nested script.
+.IP [11]
+Substitutions do not affect the word boundaries of a command.
+For example, during variable substitution the entire value of
+the variable becomes part of a single word, even if the variable's
+value contains spaces.
diff --git a/vendor/x11iraf/obm/Tcl/doc/TildeSubst.3 b/vendor/x11iraf/obm/Tcl/doc/TildeSubst.3
new file mode 100644
index 00000000..1d1bdeda
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/TildeSubst.3
@@ -0,0 +1,85 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/TildeSubst.3,v 1.10 93/04/08 14:00:43 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_TildeSubst tclc 7.0
+.BS
+.SH NAME
+Tcl_TildeSubst \- replace tilde with home directory in a file name
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+char *
+.VS
+\fBTcl_TildeSubst\fR(\fIinterp\fR, \fIname\fR, \fIbufferPtr)
+.VE
+.SH ARGUMENTS
+.AS Tcl_DString *bufferPtr
+.AP Tcl_Interp *interp in
+Interpreter in which to report an error, if any.
+.AP char *name in
+File name, which may start with a ``~''.
+.AP Tcl_DString *bufferPtr
+.VS
+If needed, this dynamic string is used to store the new file name.
+At the time of the call it should be uninitialized or empty. The
+caller must eventually call \fBTcl_DStringFree\fR to free up
+anything stored here.
+.VE
+.BE
+
+.SH DESCRIPTION
+.PP
+This utility procedure does tilde substition. If \fIname\fR doesn't
+start with a ``~'' character, then the procedure returns \fIname\fR.
+If \fIname\fR does start with a tilde, then \fBTcl_TildeSubst\fR
+returns a new string identical to \fIname\fR except that the first
+element of \fIname\fR is replaced with the location of the home
+directory for the given user. The substitution is carried out in
+the same way that it would be done by \fIcsh\fR. If the tilde is
+followed immediately by a slash, then the \fB$HOME\fR environment
+variable is substituted. Otherwise the characters between the
+tilde and the next slash are taken as a user name, which is
+looked up in the password file; the user's home directory is
+retrieved from the password file and substituted.
+.PP
+If
+.VS
+\fBTcl_TildeSubst\fR has to do tilde substitution then it uses
+the dynamic string at \fI*bufferPtr\fR to hold the new string it
+generates. After \fBTcl_TildeSubst\fR returns, the caller must
+eventually invoke \fBTcl_DStringFree\fR to free up any information
+placed in \fI*bufferPtr\fR. The caller need not know whether or
+not \fBTcl_TildeSubst\fR actually used the string; \fBTcl_TildeSubst\fR
+initializes \fI*bufferPtr\fR even if it doesn't use it, so the call to
+\fBTcl_DStringFree\fR will be safe in either case.
+.VE
+.PP
+If an error occurs (e.g. because there was no user by the given
+name) then NULL is returned and an error message will be left
+at \fIinterp->result\fR. It is assumed that \fIinterp->result\fR
+has been initialized in the standard way when \fBTcl_TildeSubst\fR
+is invoked.
+
+.SH KEYWORDS
+file name, home directory, tilde, user
diff --git a/vendor/x11iraf/obm/Tcl/doc/TraceVar.3 b/vendor/x11iraf/obm/Tcl/doc/TraceVar.3
new file mode 100644
index 00000000..3ddfecff
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/TraceVar.3
@@ -0,0 +1,361 @@
+'\"
+'\" Copyright (c) 1989-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/TraceVar.3,v 1.14 93/05/03 15:53:18 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS Tcl_TraceVar tclc
+.BS
+.SH NAME
+Tcl_TraceVar, Tcl_TraceVar2, Tcl_UntraceVar, Tcl_UntraceVar2, Tcl_VarTraceInfo, Tcl_VarTraceInfo2 \- monitor accesses to a variable
+.SH SYNOPSIS
+.nf
+\fB#include <tcl.h>\fR
+.sp
+int
+\fBTcl_TraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR
+.sp
+int
+\fBTcl_TraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR
+.sp
+\fBTcl_UntraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR
+.sp
+\fBTcl_UntraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR
+.sp
+ClientData
+\fBTcl_VarTraceInfo(\fIinterp, varName, flags, proc, prevClientData\fB)\fR
+.sp
+ClientData
+\fBTcl_VarTraceInfo2(\fIinterp, name1, name2, flags, proc, prevClientData\fB)\fR
+.SH ARGUMENTS
+.AS Tcl_VarTraceProc prevClientData
+.AP Tcl_Interp *interp in
+Interpreter containing variable.
+.AP char *varName in
+Name of variable. May refer to a scalar variable, to
+an array variable with no index, or to an array variable
+with a parenthesized index.
+.AP int flags in
+OR-ed combination of the values TCL_TRACE_READS, TCL_TRACE_WRITES, and
+TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. Not all flags are used by all
+procedures. See below for more information.
+.AP Tcl_VarTraceProc *proc in
+Procedure to invoke whenever one of the traced operations occurs.
+.AP ClientData clientData in
+Arbitrary one-word value to pass to \fIproc\fR.
+.AP char *name1 in
+Name of scalar or array variable (without array index).
+.AP char *name2 in
+For a trace on an element of an array, gives the index of the
+element. For traces on scalar variables or on whole arrays,
+is NULL.
+.AP ClientData prevClientData in
+If non-NULL, gives last value returned by \fBTcl_VarTraceInfo\fR or
+\fBTcl_VarTraceInfo2\fR, so this call will return information about
+next trace. If NULL, this call will return information about first
+trace.
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTcl_TraceVar\fR allows a C procedure to monitor and control
+access to a Tcl variable, so that the C procedure is invoked
+whenever the variable is read or written or unset.
+If the trace is created successfully then \fBTcl_TraceVar\fR returns
+TCL_OK. If an error occurred (e.g. \fIvarName\fR specifies an element
+of an array, but the actual variable isn't an array) then TCL_ERROR
+is returned and an error message is left in \fIinterp->result\fR.
+.PP
+The \fIflags\fR argument to \fBTcl_TraceVar\fR indicates when the
+trace procedure is to be invoked and provides information
+for setting up the trace. It consists of an OR-ed combination
+of any of the following values:
+.TP
+\fBTCL_GLOBAL_ONLY\fR
+Normally, the variable will be looked up at the current level of
+procedure call; if this bit is set then the variable will be looked
+up at global level, ignoring any active procedures.
+.TP
+\fBTCL_TRACE_READS\fR
+Invoke \fIproc\fR whenever an attempt is made to read the variable.
+.TP
+\fBTCL_TRACE_WRITES\fR
+Invoke \fIproc\fR whenever an attempt is made to modify the variable.
+.TP
+\fBTCL_TRACE_UNSETS\fR
+Invoke \fIproc\fR whenever the variable is unset.
+A variable may be unset either explicitly by an \fBunset\fR command,
+or implicitly when a procedure returns (its local variables are
+automatically unset) or when the interpreter is deleted (all
+variables are automatically unset).
+.PP
+Whenever one of the specified operations occurs on the variable,
+\fIproc\fR will be invoked.
+It should have arguments and result that match the type
+\fBTcl_VarTraceProc\fR:
+.nf
+.RS
+typedef char *Tcl_VarTraceProc(
+.RS
+ClientData \fIclientData\fR,
+Tcl_Interp *\fIinterp\fR,
+char *\fIname1\fR,
+char *\fIname2\fR,
+int \fIflags\fR);
+.RE
+.RE
+.fi
+The \fIclientData\fP and \fIinterp\fP parameters will
+have the same values as those passed to \fBTcl_TraceVar\fR when the
+trace was created.
+\fIClientData\fR typically points to an application-specific
+data structure that describes what to do when \fIproc\fR
+is invoked.
+\fIName1\fR and \fIname2\fR give the name of the traced variable
+in the normal two-part form (see the description of \fBTcl_TraceVar2\fR
+below for details).
+\fIFlags\fR is an OR-ed combination of bits providing several
+pieces of information.
+One of the bits TCL_TRACE_READS, TCL_TRACE_WRITES, or TCL_TRACE_UNSETS
+will be set in \fIflags\fR to indicate which operation is being performed
+on the variable.
+The bit TCL_GLOBAL_ONLY will be set whenever the variable being
+accessed is a global one not accessible from the current level of
+procedure call: the trace procedure will need to pass this flag
+back to variable-related procedures like \fBTcl_GetVar\fR if it
+attempts to access the variable.
+The bit TCL_TRACE_DESTROYED will be set in \fIflags\fR if the trace is
+about to be destroyed; this information may be useful to \fIproc\fR
+so that it can clean up its own internal data structures (see
+the section TCL_TRACE_DESTROYED below for more details).
+Lastly, the bit TCL_INTERP_DESTROYED will be set if the entire
+interpreter is being destroyed.
+When this bit is set, \fIproc\fR must be especially careful in
+the things it does (see the section TCL_INTERP_DESTROYED below).
+The trace procedure's return value should normally be NULL; see
+ERROR RETURNS below for information on other possibilities.
+.PP
+\fBTcl_UntraceVar\fR may be used to remove a trace.
+If the variable specified by \fIinterp\fR, \fIvarName\fR, and \fIflags\fR
+has a trace set with \fIflags\fR, \fIproc\fR, and
+\fIclientData\fR, then the corresponding trace is removed.
+If no such trace exists, then the call to \fBTcl_UntraceVar\fR
+has no effect.
+The same bits are valid for \fIflags\fR as for calls to \fBTcl_TraceVars\fR.
+.PP
+\fBTcl_VarTraceInfo\fR may be used to retrieve information about
+traces set on a given variable.
+The return value from \fBTcl_VarTraceInfo\fR is the \fIclientData\fR
+associated with a particular trace.
+The trace must be on the variable specified by the \fIinterp\fR,
+\fIvarName\fR, and \fIflags\fR arguments (only the TCL_GLOBAL_ONLY
+bit from \fIflags\fR is used; other bits are ignored) and its trace procedure
+must the same as the \fIproc\fR argument.
+If the \fIprevClientData\fR argument is NULL then the return
+value corresponds to the first (most recently created) matching
+trace, or NULL if there are no matching traces.
+If the \fIprevClientData\fR argument isn't NULL, then it should
+be the return value from a previous call to \fBTcl_VarTraceInfo\fR.
+In this case, the new return value will correspond to the next
+matching trace after the one whose \fIclientData\fR matches
+\fIprevClientData\fR, or NULL if no trace matches \fIprevClientData\fR
+or if there are no more matching traces after it.
+This mechanism makes it possible to step through all of the
+traces for a given variable that have the same \fIproc\fR.
+
+.SH "TWO-PART NAMES"
+.PP
+The procedures \fBTcl_TraceVar2\fR, \fBTcl_UntraceVar2\fR, and
+\fBTcl_VarTraceInfo2\fR are identical to \fBTcl_TraceVar\fR,
+\fBTcl_UntraceVar\fR, and \fBTcl_VarTraceInfo\fR, respectively,
+except that the name of the variable has already been
+separated by the caller into two parts.
+\fIName1\fR gives the name of a scalar variable or array,
+and \fIname2\fR gives the name of an element within an
+array.
+If \fIname2\fR is NULL it means that either the variable is
+a scalar or the trace is to be set on the entire array rather
+than an individual element (see WHOLE-ARRAY TRACES below for
+more information).
+
+.SH "ACCESSING VARIABLES DURING TRACES"
+.PP
+During read and write traces, the
+trace procedure can read, write, or unset the traced
+variable using \fBTcl_GetVar2\fR, \fBTcl_SetVar2\fR, and
+other procedures.
+While \fIproc\fR is executing, traces are temporarily disabled
+for the variable, so that calls to \fBTcl_GetVar2\fR and
+\fBTcl_SetVar2\fR will not cause \fIproc\fR or other trace procedures
+to be invoked again.
+Disabling only occurs for the variable whose trace procedure
+is active; accesses to other variables will still be traced.
+.VS
+However, if a variable is unset during a read or write trace then unset
+traces will be invoked.
+.VE
+.PP
+During unset traces the variable has already been completely
+expunged.
+It is possible for the trace procedure to read or write the
+variable, but this will be a new version of the variable.
+Traces are not disabled during unset traces as they are for
+read and write traces, but existing traces have been removed
+from the variable before any trace procedures are invoked.
+If new traces are set by unset trace procedures, these traces
+will be invoked on accesses to the variable by the trace
+procedures.
+
+.SH "CALLBACK TIMING"
+.PP
+When read tracing has been specified for a variable, the trace
+procedure will be invoked whenever the variable's value is
+read. This includes \fBset\fR Tcl commands, \fB$\fR-notation
+in Tcl commands, and invocations of the \fBTcl_GetVar\fR
+and \fBTcl_GetVar2\fR procedures.
+\fIProc\fR is invoked just before the variable's value is
+returned.
+It may modify the value of the variable to affect what
+is returned by the traced access.
+.VS
+If it unsets the variable then the access will return an error
+just as if the variable never existed.
+.VE
+.PP
+When write tracing has been specified for a variable, the
+trace procedure will be invoked whenever the variable's value
+is modified. This includes \fBset\fR commands\fR,
+commands that modify variables as side effects (such as
+\fBcatch\fR and \fBscan\fR), and calls to the \fBTcl_SetVar\fR
+and \fBTcl_SetVar2\fR procedures).
+\fIProc\fR will be invoked after the variable's value has been
+modified, but before the new value of the variable has been
+returned.
+It may modify the value of the variable to override the change
+and to determine the value actually returned by the traced
+access.
+.VS
+If it deletes the variable then the traced access will return
+an empty string.
+.VE
+.PP
+When unset tracing has been specified, the trace procedure
+will be invoked whenever the variable is destroyed.
+The traces will be called after the variable has been
+completely unset.
+
+.SH "WHOLE-ARRAY TRACES"
+.PP
+If a call to \fBTcl_TraceVar\fR or \fBTcl_TraceVar2\fR specifies
+the name of an array variable without an index into the array,
+then the trace will be set on the array as a whole.
+This means that \fIproc\fR will be invoked whenever any
+element of the array is accessed in the ways specified by
+\fIflags\fR.
+When an array is unset, a whole-array trace will be invoked
+just once, with \fIname1\fR equal to the name of the array
+and \fIname2\fR NULL; it will not be invoked once for each
+element.
+
+.SH "MULTIPLE TRACES"
+.PP
+It is possible for multiple traces to exist on the same variable.
+When this happens, all of the trace procedures will be invoked on each
+access, in order from most-recently-created to least-recently-created.
+When there exist whole-array traces for an array as well as
+traces on individual elements, the whole-array traces are invoked
+before the individual-element traces.
+.VS
+If a read or write trace unsets the variable then all of the unset
+traces will be invoked but the remainder of the read and write traces
+will be skipped.
+.VE
+
+.SH "ERROR RETURNS"
+.PP
+Under normal conditions trace procedures should return NULL, indicating
+successful completion.
+If \fIproc\fR returns a non-NULL value it signifies that an
+error occurred.
+The return value must be a pointer to a static character string
+containing an error message.
+If a trace procedure returns an error, no further traces are
+invoked for the access and the traced access aborts with the
+given message.
+Trace procedures can use this facility to make variables
+read-only, for example (but note that the value of the variable
+will already have been modified before the trace procedure is
+called, so the trace procedure will have to restore the correct
+value).
+.PP
+The return value from \fIproc\fR is only used during read and
+write tracing.
+During unset traces, the return value is ignored and all relevant
+trace procedures will always be invoked.
+
+.SH "RESTRICTIONS"
+.PP
+A trace procedure can be called at any time, even when there
+is a partically-formed result in the interpreter's result area. If
+the trace procedure does anything that could damage this result (such
+as calling \fBTcl_Eval\fR) then it must save the original values of
+the interpreter's \fBresult\fR and \fBfreeProc\fR fields and restore
+them before it returns.
+
+.SH "UNDEFINED VARIABLES"
+.PP
+It is legal to set a trace on an undefined variable.
+The variable will still appear to be undefined until the
+first time its value is set.
+If an undefined variable is traced and then unset, the unset will fail
+with an error (``no such variable''), but the trace
+procedure will still be invoked.
+
+.SH "TCL_TRACE_DELETED FLAG"
+.PP
+In an unset callback to \fIproc\fR, the TCL_TRACE_DELETED bit
+is set in \fIflags\fR if the trace is being removed as part
+of the deletion.
+Traces on a variable are always removed whenever the variable
+is deleted; the only time TCL_TRACE_DELETED isn't set is for
+a whole-array trace invoked when only a single element of an
+array is unset.
+
+.SH "TCL_INTERP_DESTROYED"
+.PP
+When an interpreter is destroyed, unset traces are called for
+all of its variables.
+The TCL_INTERP_DESTROYED bit will be set in the \fIflags\fR
+argument passed to the trace procedures.
+Trace procedures must be extremely careful in what they do if
+the TCL_INTERP_DESTROYED bit is set.
+It is not safe for the procedures to invoke any Tcl procedures
+on the interpreter, since its state is partially deleted.
+All that trace procedures should do under these circumstances is
+to clean up and free their own internal data structures.
+
+.SH BUGS
+.PP
+Tcl doesn't do any error checking to prevent trace procedures
+from misusing the interpreter during traces with TCL_INTERP_DESTROYED
+set.
+
+.SH KEYWORDS
+clientData, trace, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/append.n b/vendor/x11iraf/obm/Tcl/doc/append.n
new file mode 100644
index 00000000..7015d5a1
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/append.n
@@ -0,0 +1,45 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/append.n,v 1.1 93/04/14 16:52:54 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS append tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+append \- Append to variable
+.SH SYNOPSIS
+\fBappend \fIvarName value \fR?\fIvalue value ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Append all of the \fIvalue\fR arguments to the current value
+of variable \fIvarName\fR. If \fIvarName\fR doesn't exist,
+it is given a value equal to the concatenation of all the
+\fIvalue\fR arguments.
+This command provides an efficient way to build up long
+variables incrementally.
+For example, ``\fBappend a $b\fR'' is much more efficient than
+``\fBset a $a$b\fR'' if \fB$a\fR is long.
+
+.SH KEYWORDS
+append, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/array.n b/vendor/x11iraf/obm/Tcl/doc/array.n
new file mode 100644
index 00000000..553a1cc9
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/array.n
@@ -0,0 +1,95 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/array.n,v 1.1 93/04/14 16:52:55 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS array tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+array \- Manipulate array variables
+.SH SYNOPSIS
+\fBarray \fIoption arrayName\fR ?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command performs one of several operations on the
+variable given by \fIarrayName\fR.
+\fIArrayName\fR must be the name of an existing array variable.
+The \fIoption\fR argument determines what action is carried
+out by the command.
+The legal \fIoptions\fR (which may be abbreviated) are:
+.TP
+\fBarray anymore \fIarrayName searchId\fR
+Returns 1 if there are any more elements left to be processed
+in an array search, 0 if all elements have already been
+returned.
+\fISearchId\fR indicates which search on \fIarrayName\fR to
+check, and must have been the return value from a previous
+invocation of \fBarray startsearch\fR.
+This option is particularly useful if an array has an element
+with an empty name, since the return value from
+\fBarray nextelement\fR won't indicate whether the search
+has been completed.
+.TP
+\fBarray donesearch \fIarrayName searchId\fR
+This command terminates an array search and destroys all the
+state associated with that search. \fISearchId\fR indicates
+which search on \fIarrayName\fR to destroy, and must have
+been the return value from a previous invocation of
+\fBarray startsearch\fR. Returns an empty string.
+.TP
+\fBarray names \fIarrayName\fR
+Returns a list containing the names of all of the elements in
+the array.
+If there are no elements in the array then an empty string is
+returned.
+.TP
+\fBarray nextelement \fIarrayName searchId\fR
+Returns the name of the next element in \fIarrayName\fR, or
+an empty string if all elements of \fIarrayName\fR have
+already been returned in this search. The \fIsearchId\fR
+argument identifies the search, and must have
+been the return value of an \fBarray startsearch\fR command.
+Warning: if elements are added to or deleted from the array,
+then all searches are automatically terminated just as if
+\fBarray donesearch\fR had been invoked; this will cause
+\fBarray nextelement\fR operations to fail for those searches.
+.TP
+\fBarray size \fIarrayName\fR
+Returns a decimal string giving the number of elements in the
+array.
+.TP
+\fBarray startsearch \fIarrayName\fR
+This command initializes an element-by-element search through the
+array given by \fIarrayName\fR, such that invocations of the
+\fBarray nextelement\fR command will return the names of the
+individual elements in the array.
+When the search has been completed, the \fBarray donesearch\fR
+command should be invoked.
+The return value is a
+search identifier that must be used in \fBarray nextelement\fR
+and \fBarray donesearch\fR commands; it allows multiple
+searches to be underway simultaneously for the same array.
+
+.SH KEYWORDS
+array, element names, search
diff --git a/vendor/x11iraf/obm/Tcl/doc/break.n b/vendor/x11iraf/obm/Tcl/doc/break.n
new file mode 100644
index 00000000..ba2f1088
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/break.n
@@ -0,0 +1,41 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/break.n,v 1.1 93/04/14 16:52:56 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS break tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+break \- Abort looping command
+.SH SYNOPSIS
+\fBbreak\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command may be invoked only inside the body of a looping command
+such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
+It returns a TCL_BREAK code to signal the innermost containing
+loop command to return immediately.
+
+.SH KEYWORDS
+abort, break, loop
diff --git a/vendor/x11iraf/obm/Tcl/doc/case.n b/vendor/x11iraf/obm/Tcl/doc/case.n
new file mode 100644
index 00000000..79114343
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/case.n
@@ -0,0 +1,72 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/case.n,v 1.3 93/06/17 11:29:59 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS case tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+case \- Evaluate one of several scripts, depending on a given value
+.SH SYNOPSIS
+\fBcase\fI string \fR?\fBin\fR? \fIpatList body \fR?\fIpatList body \fR...?
+.br
+\fBcase\fI string \fR?\fBin\fR? {\fIpatList body \fR?\fIpatList body \fR...?}
+.BE
+
+.SH DESCRIPTION
+.PP
+\fINote: the \fBcase\fI command is obsolete and is supported only
+for backward compatibility. At some point in the future it may be
+removed entirely. You should use the \fBswitch\fI command instead.\fR
+.PP
+The \fBcase\fR command matches \fIstring\fR against each of
+the \fIpatList\fR arguments in order.
+Each \fIpatList\fR argument is a list of one or
+more patterns. If any of these patterns matches \fIstring\fR then
+\fBcase\fR evaluates the following \fIbody\fR argument
+by passing it recursively to the Tcl interpreter and returns the result
+of that evaluation.
+Each \fIpatList\fR argument consists of a single
+pattern or list of patterns. Each pattern may contain any of the wild-cards
+described under \fBstring match\fR. If a \fIpatList\fR
+argument is \fBdefault\fR, the corresponding body will be evaluated
+if no \fIpatList\fR matches \fIstring\fR. If no \fIpatList\fR argument
+matches \fIstring\fR and no default is given, then the \fBcase\fR
+command returns an empty string.
+.PP
+Two syntaxes are provided for the \fIpatList\fR and \fIbody\fR arguments.
+The first uses a separate argument for each of the patterns and commands;
+this form is convenient if substitutions are desired on some of the
+patterns or commands.
+The second form places all of the patterns and commands together into
+a single argument; the argument must have proper list structure, with
+the elements of the list being the patterns and commands.
+The second form makes it easy to construct multi-line case commands,
+since the braces around the whole list make it unnecessary to include a
+backslash at the end of each line.
+Since the \fIpatList\fR arguments are in braces in the second form,
+no command or variable substitutions are performed on them; this makes
+the behavior of the second form different than the first form in some
+cases.
+
+.SH KEYWORDS
+case, match, regular expression
diff --git a/vendor/x11iraf/obm/Tcl/doc/catch.n b/vendor/x11iraf/obm/Tcl/doc/catch.n
new file mode 100644
index 00000000..735aba0d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/catch.n
@@ -0,0 +1,50 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/catch.n,v 1.1 93/04/14 16:52:57 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS catch tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+catch \- Evaluate script and trap exceptional returns
+.SH SYNOPSIS
+\fBcatch\fI script \fR?\fIvarName\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fBcatch\fR command may be used to prevent errors from aborting
+command interpretation. \fBCatch\fR calls the Tcl interpreter recursively
+to execute \fIscript\fR, and always returns a TCL_OK code, regardless of
+any errors that might occur while executing \fIscript\fR. The return
+value from \fBcatch\fR is a decimal string giving the
+code returned by the Tcl interpreter after executing \fIscript\fR.
+This will be \fB0\fR (TCL_OK) if there were no errors in \fIscript\fR;
+otherwise
+it will have a non-zero value corresponding to one of the exceptional
+return codes (see tcl.h for the definitions of code values). If the
+\fIvarName\fR argument is given, then it gives the name of a variable;
+\fBcatch\fR will set the variable to the string returned
+from \fIscript\fR (either a result or an error message).
+
+.SH KEYWORDS
+catch, error
diff --git a/vendor/x11iraf/obm/Tcl/doc/cd.n b/vendor/x11iraf/obm/Tcl/doc/cd.n
new file mode 100644
index 00000000..cfc4401a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/cd.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/cd.n,v 1.1 93/04/14 16:52:58 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS cd tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+cd \- Change working directory
+.SH SYNOPSIS
+\fBcd \fR?\fIdirName\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Change the current working directory to \fIdirName\fR, or to the
+home directory (as specified in the HOME environment variable) if
+\fIdirName\fR is not given.
+If \fIdirName\fR starts with a tilde, then tilde-expansion is
+done as described for \fBTcl_TildeSubst\fR.
+Returns an empty string.
+
+.SH KEYWORDS
+working directory
diff --git a/vendor/x11iraf/obm/Tcl/doc/close.n b/vendor/x11iraf/obm/Tcl/doc/close.n
new file mode 100644
index 00000000..dbd0dc0e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/close.n
@@ -0,0 +1,46 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/close.n,v 1.1 93/04/16 17:23:28 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS close tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+close \- Close an open file
+.SH SYNOPSIS
+\fBclose \fIfileId\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Closes the file given by \fIfileId\fR.
+\fIFileId\fR must be the return value from a previous invocation
+of the \fBopen\fR command; after this command, it should not be
+used anymore.
+If \fIfileId\fR refers to a command pipeline instead of a file,
+then \fBclose\fR waits for the children to complete.
+The normal result of this command is an empty string, but errors
+are returned if there are problems in closing the file or waiting
+for children to complete.
+
+.SH KEYWORDS
+close, file
diff --git a/vendor/x11iraf/obm/Tcl/doc/concat.n b/vendor/x11iraf/obm/Tcl/doc/concat.n
new file mode 100644
index 00000000..8b50e327
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/concat.n
@@ -0,0 +1,57 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/concat.n,v 1.2 93/10/28 16:19:07 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS concat tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+concat \- Join lists together
+.SH SYNOPSIS
+.VS
+\fBconcat\fI \fR?\fIarg arg ...\fR?
+.VE
+.BE
+
+.SH DESCRIPTION
+.PP
+This command treats each argument as a list and concatenates them
+into a single list.
+It also eliminates leading and trailing spaces in the \fIarg\fR's
+and adds a single separator space between \fIarg\fR's.
+It permits any number of arguments. For example,
+the command
+.DS
+\fBconcat a b {c d e} {f {g h}}\fR
+.DE
+will return
+.DS
+\fBa b c d e f {g h}\fR
+.DE
+as its result.
+.PP
+.VS
+If no \fIarg\fRs are supplied, the result is an empty string.
+.VE
+
+.SH KEYWORDS
+concatenate, join, lists
diff --git a/vendor/x11iraf/obm/Tcl/doc/continue.n b/vendor/x11iraf/obm/Tcl/doc/continue.n
new file mode 100644
index 00000000..90adf49e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/continue.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/continue.n,v 1.1 93/04/16 17:23:30 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS continue tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+continue \- Skip to the next iteration of a loop
+.SH SYNOPSIS
+\fBcontinue\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command may be invoked only inside the body of a looping command
+such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
+It returns a TCL_CONTINUE code
+to signal the innermost containing loop command to skip the
+remainder of the loop's body
+but continue with the next iteration of the loop.
+
+.SH KEYWORDS
+continue, iteration, loop
diff --git a/vendor/x11iraf/obm/Tcl/doc/eof.n b/vendor/x11iraf/obm/Tcl/doc/eof.n
new file mode 100644
index 00000000..ef6e7660
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/eof.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/eof.n,v 1.1 93/04/16 17:23:31 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS eof tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+eof \- Check for end-of-file condition on open file
+.SH SYNOPSIS
+\fBeof \fIfileId\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns 1 if an end-of-file condition has occurred on \fIfileId\fR,
+0 otherwise.
+\fIFileId\fR must have been the return
+value from a previous call to \fBopen\fR, or it may be \fBstdin\fR,
+\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O
+channels.
+
+.SH KEYWORDS
+end, file
diff --git a/vendor/x11iraf/obm/Tcl/doc/error.n b/vendor/x11iraf/obm/Tcl/doc/error.n
new file mode 100644
index 00000000..0c901153
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/error.n
@@ -0,0 +1,71 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/error.n,v 1.1 93/04/16 17:23:32 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS error tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+error \- Generate an error
+.SH SYNOPSIS
+\fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns a TCL_ERROR code, which causes command interpretation to be
+unwound. \fIMessage\fR is a string that is returned to the application
+to indicate what went wrong.
+.PP
+If the \fIinfo\fR argument is provided and is non-empty,
+it is used to initialize the global variable \fBerrorInfo\fR.
+\fBerrorInfo\fR is used to accumulate a stack trace of what
+was in progress when an error occurred; as nested commands unwind,
+the Tcl interpreter adds information to \fBerrorInfo\fR. If the
+\fIinfo\fR argument is present, it is used to initialize
+\fBerrorInfo\fR and the first increment of unwind information
+will not be added by the Tcl interpreter. In other
+words, the command containing the \fBerror\fR command will not appear
+in \fBerrorInfo\fR; in its place will be \fIinfo\fR.
+This feature is most useful in conjunction with the \fBcatch\fR command:
+if a caught error cannot be handled successfully, \fIinfo\fR can be used
+to return a stack trace reflecting the original point of occurrence
+of the error:
+.DS
+\fBcatch {...} errMsg
+set savedInfo $errorInfo
+\&...
+error $errMsg $savedInfo\fR
+.DE
+.PP
+If the \fIcode\fR argument is present, then its value is stored
+in the \fBerrorCode\fR global variable. This variable is intended
+to hold a machine-readable description of the error in cases where
+such information is available; see the section BUILT-IN VARIABLES
+below for information on the proper format for the variable.
+If the \fIcode\fR argument is not
+present, then \fBerrorCode\fR is automatically reset to
+``NONE'' by the Tcl interpreter as part of processing the
+error generated by the command.
+
+.SH KEYWORDS
+error, errorCode, errorInfo
diff --git a/vendor/x11iraf/obm/Tcl/doc/eval.n b/vendor/x11iraf/obm/Tcl/doc/eval.n
new file mode 100644
index 00000000..7c38ab4c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/eval.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/eval.n,v 1.1 93/05/10 17:10:16 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS eval tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+eval \- Evaluate a Tcl script
+.SH SYNOPSIS
+\fBeval \fIarg \fR?\fIarg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBEval\fR takes one or more arguments, which together comprise a Tcl
+script containing one or more commands.
+\fBEval\fR concatenates all its arguments in the same
+fashion as the \fBconcat\fR command, passes the concatenated string to the
+Tcl interpreter recursively, and returns the result of that
+evaluation (or any error generated by it).
+
+.SH KEYWORDS
+concatenate, evaluate, script
diff --git a/vendor/x11iraf/obm/Tcl/doc/exec.n b/vendor/x11iraf/obm/Tcl/doc/exec.n
new file mode 100644
index 00000000..fa900616
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/exec.n
@@ -0,0 +1,198 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/exec.n,v 1.6 93/07/23 15:13:34 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS exec tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+exec \- Invoke subprocess(es)
+.SH SYNOPSIS
+\fBexec \fR?\fIswitches\fR? \fIarg \fR?\fIarg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command treats its arguments as the specification
+of one or more subprocesses to execute.
+The arguments take the form of a standard shell pipeline
+where each \fIarg\fR becomes one word of a command, and
+each distinct command becomes a subprocess.
+.PP
+If the initial arguments to \fBexec\fR start with \fB\-\fR then
+.VS
+they are treated as command-line switches and are not part
+of the pipeline specification. The following switches are
+currently supported:
+.TP 13
+\fB\-keepnewline
+Retains a trailing newline in the pipeline's output.
+Normally a trailing newline will be deleted.
+.TP 13
+\fB\-\|\-\fR
+Marks the end of switches. The argument following this one will
+be treated as the first \fIarg\fR even if it starts with a \fB\-.
+.VE
+.PP
+If an \fIarg\fR (or pair of \fIarg\fR's) has one of the forms
+described below then it is used by \fBexec\fR to control the
+flow of input and output among the subprocess(es).
+Such arguments will not be passed to the subprocess(es). In forms
+.VS
+such as ``< \fIfileName\fR'' \fIfileName\fR may either be in a
+separate argument from ``<'' or in the same argument with no
+intervening space (i.e. ``<\fIfileName\fR'').
+.VE
+.TP 15
+|\fR
+Separates distinct commands in the pipeline. The standard output
+of the preceding command will be piped into the standard input
+of the next command.
+.TP 15
+|&\fR
+Separates distinct commands in the pipeline. Both standard output
+and standard error of the preceding command will be piped into
+the standard input of the next command.
+This form of redirection overrides forms such as 2> and >&.
+.TP 15
+<\0\fIfileName\fR
+The file named by \fIfileName\fR is opened and used as the standard
+input for the first command in the pipeline.
+.TP 15
+<@\0\fIfileId\fR
+.VS
+\fIFileId\fR must be the identifier for an open file, such as the return
+value from a previous call to \fBopen\fR.
+It is used as the standard input for the first command in the pipeline.
+\fIFileId\fR must have been opened for reading.
+.VE
+.TP 15
+<<\0\fIvalue\fR
+\fIValue\fR is passed to the first command as its standard input.
+.TP 15
+>\0\fIfileName\fR
+Standard output from the last command is redirected to the file named
+\fIfileName\fR, overwriting its previous contents.
+.TP 15
+2>\0\fIfileName\fR
+.VS
+Standard error from all commands in the pipeline is redirected to the
+file named \fIfileName\fR, overwriting its previous contents.
+.TP 15
+>&\0\fIfileName\fR
+Both standard output from the last command and standard error from all
+commands are redirected to the file named \fIfileName\fR, overwriting
+its previous contents.
+.VE
+.TP 15
+>>\0\fIfileName\fR
+Standard output from the last command is
+redirected to the file named \fIfileName\fR, appending to it rather
+than overwriting it.
+.TP 15
+2>>\0\fIfileName\fR
+.VS
+Standard error from all commands in the pipeline is
+redirected to the file named \fIfileName\fR, appending to it rather
+than overwriting it.
+.TP 15
+>>&\0\fIfileName\fR
+Both standard output from the last command and standard error from
+all commands are redirected to the file named \fIfileName\fR,
+appending to it rather than overwriting it.
+.TP 15
+>@\0\fIfileId\fR
+\fIFileId\fR must be the identifier for an open file, such as the return
+value from a previous call to \fBopen\fR.
+Standard output from the last command is redirected to \fIfileId\fR's
+file, which must have been opened for writing.
+.TP 15
+2>@\0\fIfileId\fR
+\fIFileId\fR must be the identifier for an open file, such as the return
+value from a previous call to \fBopen\fR.
+Standard error from all commands in the pipeline is
+redirected to \fIfileId\fR's file.
+The file must have been opened for writing.
+.TP 15
+>&@\0\fIfileId\fR
+\fIFileId\fR must be the identifier for an open file, such as the return
+value from a previous call to \fBopen\fR.
+Both standard output from the last command and standard error from
+all commands are redirected to \fIfileId\fR's file.
+The file must have been opened for writing.
+.VE
+.PP
+If standard output has not been redirected then the \fBexec\fR
+command returns the standard output from the last command
+in the pipeline.
+If any of the commands in the pipeline exit abnormally or
+are killed or suspended, then \fBexec\fR will return an error
+and the error message will include the pipeline's output followed by
+error messages describing the abnormal terminations; the
+\fBerrorCode\fR variable will contain additional information
+about the last abnormal termination encountered.
+If any of the commands writes to its standard error file and that
+standard error isn't redirected,
+then \fBexec\fR will return an error; the error message
+will include the pipeline's standard output, followed by messages
+about abnormal terminations (if any), followed by the standard error
+output.
+.PP
+If the last character of the result or error message
+is a newline then that character is normally deleted
+from the result or error message.
+This is consistent with other Tcl return values, which don't
+normally end with newlines.
+.VS
+However, if \fB\-keepnewline\fR is specified then the trailing
+newline is retained.
+.VE
+.PP
+If standard input isn't redirected with ``<'' or ``<<''
+or ``<@'' then the standard input for the first command in the
+pipeline is taken from the application's current standard input.
+.PP
+If the last \fIarg\fR is ``&'' then the pipeline will be
+executed in background.
+.VS
+In this case the \fBexec\fR command will return a list whose
+elements are the process identifiers for all of the subprocesses
+in the pipeline.
+.VE
+The standard output from the last command in the pipeline will
+go to the application's standard output if it hasn't been
+redirected, and error output from all of
+the commands in the pipeline will go to the application's
+standard error file unless redirected.
+.PP
+The first word in each command is taken as the command name;
+tilde-substitution is performed on it, and if the result contains
+no slashes then the directories
+in the PATH environment variable are searched for
+an executable by the given name.
+If the name contains a slash then it must refer to an executable
+reachable from the current directory.
+No ``glob'' expansion or other shell-like substitutions
+are performed on the arguments to commands.
+
+.SH KEYWORDS
+execute, pipeline, redirection, subprocess
diff --git a/vendor/x11iraf/obm/Tcl/doc/exit.n b/vendor/x11iraf/obm/Tcl/doc/exit.n
new file mode 100644
index 00000000..d25a524a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/exit.n
@@ -0,0 +1,41 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/exit.n,v 1.2 93/06/17 13:31:30 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS exit tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+exit \- End the application
+.SH SYNOPSIS
+\fBexit \fR?\fIreturnCode\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Terminate the process, returning \fIreturnCode\fR to the
+system as the exit status.
+If \fIreturnCode\fR isn't specified then it defaults
+to 0.
+
+.SH KEYWORDS
+exit, process
diff --git a/vendor/x11iraf/obm/Tcl/doc/expr.n b/vendor/x11iraf/obm/Tcl/doc/expr.n
new file mode 100644
index 00000000..957d8cc0
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/expr.n
@@ -0,0 +1,302 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/expr.n,v 1.5 93/09/02 16:41:26 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS expr tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+expr \- Evalue an expression
+.SH SYNOPSIS
+\fBexpr \fIarg \fR?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+.VS
+Concatenates \fIarg\fR's (adding separator spaces between them),
+evaluates the result as a Tcl expression, and returns the value.
+.VE
+The operators permitted in Tcl expressions are a subset of
+the operators permitted in C expressions, and they have the
+same meaning and precedence as the corresponding C operators.
+Expressions almost always yield numeric results
+(integer or floating-point values).
+For example, the expression
+.DS
+\fBexpr 8.2 + 6\fR
+.DE
+evaluates to 14.2.
+Tcl expressions differ from C expressions in the way that
+operands are specified. Also, Tcl expressions support
+non-numeric operands and string comparisons.
+.SH OPERANDS
+.PP
+A Tcl expression consists of a combination of operands, operators,
+and parentheses.
+White space may be used between the operands and operators and
+parentheses; it is ignored by the expression processor.
+Where possible, operands are interpreted as integer values.
+Integer values may be specified in decimal (the normal case), in octal (if the
+first character of the operand is \fB0\fR), or in hexadecimal (if the first
+two characters of the operand are \fB0x\fR).
+If an operand does not have one of the integer formats given
+above, then it is treated as a floating-point number if that is
+possible. Floating-point numbers may be specified in any of the
+ways accepted by an ANSI-compliant C compiler (except that the
+``f'', ``F'', ``l'', and ``L'' suffixes will not be permitted in
+most installations). For example, all of the
+following are valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16.
+If no numeric interpretation is possible, then an operand is left
+as a string (and only a limited set of operators may be applied to
+it).
+.PP
+Operands may be specified in any of the following ways:
+.IP [1]
+As an numeric value, either integer or floating-point.
+.IP [2]
+As a Tcl variable, using standard \fB$\fR notation.
+The variable's value will be used as the operand.
+.IP [3]
+As a string enclosed in double-quotes.
+The expression parser will perform backslash, variable, and
+command substitutions on the information between the quotes,
+and use the resulting value as the operand
+.IP [4]
+As a string enclosed in braces.
+The characters between the open brace and matching close brace
+will be used as the operand without any substitutions.
+.IP [5]
+As a Tcl command enclosed in brackets.
+The command will be executed and its result will be used as
+the operand.
+.IP [6]
+.VS
+As a mathematical function whose arguments have any of the above
+forms for operands, such as ``\fBsin($x)\fR''. See below for a list of defined
+functions.
+.VE
+.LP
+Where substitutions occur above (e.g. inside quoted strings), they
+are performed by the expression processor.
+However, an additional layer of substitution may already have
+been performed by the command parser before the expression
+processor was called.
+As discussed below, it is usually best to enclose expressions
+in braces to prevent the command parser from performing substitutions
+on the contents.
+.PP
+For some examples of simple expressions, suppose the variable
+\fBa\fR has the value 3 and
+the variable \fBb\fR has the value 6.
+Then the command on the left side of each of the lines below
+will produce the value on the right side of the line:
+.DS
+.ta 6c
+\fBexpr 3.1 + $a 6.1
+expr 2 + "$a.$b" 5.6
+expr 4*[llength "6 2"] 8
+expr {{word one} < "word $a"} 0\fR
+.DE
+.SH OPERATORS
+.PP
+The valid operators are listed below, grouped in decreasing order
+of precedence:
+.TP 20
+\fB\-\0\0~\0\0!\fR
+Unary minus, bit-wise NOT, logical NOT. None of these operands
+may be applied to string operands, and bit-wise NOT may be
+applied only to integers.
+.TP 20
+\fB*\0\0/\0\0%\fR
+Multiply, divide, remainder. None of these operands may be
+applied to string operands, and remainder may be applied only
+to integers.
+.VS
+The remainder will always have the same sign as the divisor and
+an absolute value smaller than the divisor.
+.VE
+.TP 20
+\fB+\0\0\-\fR
+Add and subtract. Valid for any numeric operands.
+.TP 20
+\fB<<\0\0>>\fR
+Left and right shift. Valid for integer operands only.
+.TP 20
+\fB<\0\0>\0\0<=\0\0>=\fR
+Boolean less, greater, less than or equal, and greater than or equal.
+Each operator produces 1 if the condition is true, 0 otherwise.
+These operators may be applied to strings as well as numeric operands,
+in which case string comparison is used.
+.TP 20
+\fB==\0\0!=\fR
+Boolean equal and not equal. Each operator produces a zero/one result.
+Valid for all operand types.
+.TP 20
+\fB&\fR
+Bit-wise AND. Valid for integer operands only.
+.TP 20
+\fB^\fR
+Bit-wise exclusive OR. Valid for integer operands only.
+.TP 20
+\fB|\fR
+Bit-wise OR. Valid for integer operands only.
+.TP 20
+\fB&&\fR
+Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise.
+Valid for numeric operands only (integers or floating-point).
+.TP 20
+\fB||\fR
+Logical OR. Produces a 0 result if both operands are zero, 1 otherwise.
+Valid for numeric operands only (integers or floating-point).
+.TP 20
+\fIx\fB?\fIy\fB:\fIz\fR
+If-then-else, as in C. If \fIx\fR
+evaluates to non-zero, then the result is the value of \fIy\fR.
+Otherwise the result is the value of \fIz\fR.
+The \fIx\fR operand must have a numeric value.
+.LP
+See the C manual for more details on the results
+produced by each operator.
+All of the binary operators group left-to-right within the same
+precedence level. For example, the command
+.DS
+\fBexpr 4*2 < 7\fR
+.DE
+returns 0.
+.PP
+The \fB&&\fP, \fB||\fP, and \fB?:\fP operators have ``lazy
+evaluation'', just as in C,
+which means that operands are not evaluated if they are
+not needed to determine the outcome. For example, in the command
+.DS
+\fBexpr {$v ? [a] : [b]}\fR
+.DE
+only one of \fB[a]\fR or \fB[b]\fR will actually be evaluated,
+depending on the value of \fB$v\fP. Note, however, that this is
+only true if the entire expression is enclosed in braces; otherwise
+the Tcl parser will evaluate both \fB[a]\fR and \fB[b]\fR before
+invoking the \fBexpr\fR command.
+.SH "MATH FUNCTIONS"
+.PP
+.VS
+Tcl supports the following mathematical functions in expressions:
+.DS
+.ta 3c 6c 9c
+\fBacos\fR \fBcos\fR \fBhypot\fR \fBsinh\fR
+\fBasin\fR \fBcosh\fR \fBlog\fR \fBsqrt\fR
+\fBatan\fR \fBexp\fR \fBlog10\fR \fBtan\fR
+\fBatan2\fR \fBfloor\fR \fBpow\fR \fBtanh\fR
+\fBceil\fR \fBfmod\fR \fBsin\fR
+.DE
+Each of these functions invokes the math library function of the same
+name; see the manual entries for the library functions for details
+on what they do. Tcl also implements the following functions for
+conversion between integers and floating-point numbers:
+.TP
+\fBabs(\fIarg\fB)\fI
+Returns the absolute value of \fIarg\fR. \fIArg\fR may be either
+integer or floating-point, and the result is returned in the same form.
+.TP
+\fBdouble(\fIarg\fB)\fR
+If \fIarg\fR is a floating value, returns \fIarg\fR, otherwise converts
+\fIarg\fR to floating and returns the converted value.
+.TP
+\fBint(\fIarg\fB)\fR
+If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts
+\fIarg\fR to integer by truncation and returns the converted value.
+.TP
+\fBround(\fIarg\fB)\fR
+If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts
+\fIarg\fR to integer by rounding and returns the converted value.
+.PP
+In addition to these predifined functions, applications may
+define additional functions using \fBTcl_CreateMathFunc\fR().
+.VE
+.SH "TYPES, OVERFLOW, AND PRECISION"
+.PP
+All internal computations involving integers are done with the C type
+\fIlong\fP, and all internal computations involving floating-point are
+done with the C type \fIdouble\fP.
+When converting a string to floating-point, exponent overflow is
+detected and results in a Tcl error.
+For conversion to integer from string, detection of overflow depends
+on the behavior of some routines in the local C library, so it should
+be regarded as unreliable.
+In any case, integer overflow and underflow are generally not detected
+reliably for intermediate results. Floating-point overflow and underflow
+are detected to the degree supported by the hardware, which is generally
+pretty reliable.
+.PP
+Conversion among internal representations for integer, floating-point,
+and string operands is done automatically as needed.
+For arithmetic computations, integers are used until some
+floating-point number is introduced, after which floating-point is used.
+For example,
+.DS
+\fBexpr 5 / 4\fR
+.DE
+returns 1, while
+.DS
+\fBexpr 5 / 4.0\fR
+\fBexpr 5 / ( [string length "abcd"] + 0.0 )
+.DE
+both return 1.25.
+.VS
+Floating-point values are always returned with a ``.''
+or an ``e'' so that they will not look like integer values. For
+example,
+.DS
+\fBexpr 20.0/5.0\fR
+.DE
+returns ``4.0'', not ``4''. The global variable \fBtcl_precision\fR
+determines the the number of significant digits that are retained
+when floating values are converted to strings (except that trailing
+zeroes are omitted). If \fBtcl_precision\fR
+is unset then 6 digits of precision are used.
+To retain all of the significant bits of an IEEE floating-point
+number set \fBtcl_precision\fR to 17; if a value is converted to
+string with 17 digits of precision and then converted back to binary
+for some later calculation, the resulting binary value is guaranteed
+to be identical to the original one.
+.VE
+
+.SH "STRING OPERATIONS"
+.PP
+String values may be used as operands of the comparison operators,
+although the expression evaluator tries to do comparisons as integer
+or floating-point when it can.
+If one of the operands of a comparison is a string and the other
+has a numeric value, the numeric operand is converted back to
+a string using the C \fIsprintf\fP format specifier
+\fB%d\fR for integers and \fB%g\fR for floating-point values.
+For example, the commands
+.DS
+\fBexpr {"0x03" > "2"}\fR
+\fBexpr {"0y" < "0x12"}\fR
+.DE
+both return 1. The first comparison is done using integer
+comparison, and the second is done using string comparison after
+the second operand is converted to the string ``18''.
+
+.SH KEYWORDS
+arithmetic, boolean, compare, expression
diff --git a/vendor/x11iraf/obm/Tcl/doc/file.n b/vendor/x11iraf/obm/Tcl/doc/file.n
new file mode 100644
index 00000000..2423daea
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/file.n
@@ -0,0 +1,146 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/file.n,v 1.1 93/05/03 17:09:38 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS file tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+file \- Manipulate file names and attributes
+.SH SYNOPSIS
+\fBfile \fIoption\fR \fIname\fR ?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command provides several operations on a file's name or attributes.
+\fIName\fR is the name of a file;
+if it starts with a tilde, then tilde substitution is done before
+executing the command (see the manual entry for \fBTcl_TildeSubst\fR
+for details).
+\fIOption\fR indicates what to do with the file name. Any unique
+abbreviation for \fIoption\fR is acceptable. The valid options are:
+.TP
+\fBfile \fBatime \fIname\fR
+Returns a decimal string giving the time at which file \fIname\fR
+was last accessed. The time is measured in the standard POSIX
+fashion as seconds from a fixed starting time (often January 1, 1970).
+If the file doesn't exist or its access time cannot be queried then an
+error is generated.
+.TP
+\fBfile \fBdirname \fIname\fR
+Returns all of the characters in \fIname\fR up to but not including
+the last slash character. If there are no slashes in \fIname\fR
+then returns ``.''. If the last slash in \fIname\fR is its first
+character, then return ``/''.
+.TP
+\fBfile \fBexecutable \fIname\fR
+Returns \fB1\fR if file \fIname\fR is executable by
+the current user, \fB0\fR otherwise.
+.TP
+\fBfile \fBexists \fIname\fR
+Returns \fB1\fR if file \fIname\fR exists and the current user has
+search privileges for the directories leading to it, \fB0\fR otherwise.
+.TP
+\fBfile \fBextension \fIname\fR
+Returns all of the characters in \fIname\fR after and including the
+last dot in \fIname\fR. If there is no dot in \fIname\fR then returns
+the empty string.
+.TP
+\fBfile \fBisdirectory \fIname\fR
+Returns \fB1\fR if file \fIname\fR is a directory,
+\fB0\fR otherwise.
+.TP
+\fBfile \fBisfile \fIname\fR
+Returns \fB1\fR if file \fIname\fR is a regular file,
+\fB0\fR otherwise.
+.TP
+\fBfile lstat \fIname varName\fR
+Same as \fBstat\fR option (see below) except uses the \fIlstat\fR
+kernel call instead of \fIstat\fR. This means that if \fIname\fR
+refers to a symbolic link the information returned in \fIvarName\fR
+is for the link rather than the file it refers to. On systems that
+don't support symbolic links this option behaves exactly the same
+as the \fBstat\fR option.
+.TP
+\fBfile \fBmtime \fIname\fR
+Returns a decimal string giving the time at which file \fIname\fR
+was last modified. The time is measured in the standard POSIX
+fashion as seconds from a fixed starting time (often January 1, 1970).
+If the file doesn't exist or its modified time cannot be queried then an
+error is generated.
+.TP
+\fBfile \fBowned \fIname\fR
+Returns \fB1\fR if file \fIname\fR is owned by the current user,
+\fB0\fR otherwise.
+.TP
+\fBfile \fBreadable \fIname\fR
+Returns \fB1\fR if file \fIname\fR is readable by
+the current user, \fB0\fR otherwise.
+.TP
+\fBfile readlink \fIname\fR
+Returns the value of the symbolic link given by \fIname\fR (i.e. the
+name of the file it points to). If
+\fIname\fR isn't a symbolic link or its value cannot be read, then
+an error is returned. On systems that don't support symbolic links
+this option is undefined.
+.TP
+\fBfile \fBrootname \fIname\fR
+Returns all of the characters in \fIname\fR up to but not including
+the last ``.'' character in the name. If \fIname\fR doesn't contain
+a dot, then returns \fIname\fR.
+.TP
+\fBfile \fBsize \fIname\fR
+Returns a decimal string giving the size of file \fIname\fR in bytes.
+If the file doesn't exist or its size cannot be queried then an
+error is generated.
+.TP
+\fBfile \fBstat \fIname varName\fR
+Invokes the \fBstat\fR kernel call on \fIname\fR, and uses the
+variable given by \fIvarName\fR to hold information returned from
+the kernel call.
+\fIVarName\fR is treated as an array variable,
+and the following elements of that variable are set: \fBatime\fR,
+\fBctime\fR, \fBdev\fR, \fBgid\fR, \fBino\fR, \fBmode\fR, \fBmtime\fR,
+\fBnlink\fR, \fBsize\fR, \fBtype\fR, \fBuid\fR.
+Each element except \fBtype\fR is a decimal string with the value of
+the corresponding field from the \fBstat\fR return structure; see the
+manual entry for \fBstat\fR for details on the meanings of the values.
+The \fBtype\fR element gives the type of the file in the same form
+returned by the command \fBfile type\fR.
+This command returns an empty string.
+.TP
+\fBfile \fBtail \fIname\fR
+Returns all of the characters in \fIname\fR after the last slash.
+If \fIname\fR contains no slashes then returns \fIname\fR.
+.TP
+\fBfile \fBtype \fIname\fR
+Returns a string giving the type of file \fIname\fR, which will be
+one of \fBfile\fR, \fBdirectory\fR, \fBcharacterSpecial\fR,
+\fBblockSpecial\fR, \fBfifo\fR, \fBlink\fR, or \fBsocket\fR.
+.TP
+\fBfile \fBwritable \fIname\fR
+Returns \fB1\fR if file \fIname\fR is writable by
+the current user, \fB0\fR otherwise.
+
+.SH KEYWORDS
+attributes, directory, file, name, stat
diff --git a/vendor/x11iraf/obm/Tcl/doc/flush.n b/vendor/x11iraf/obm/Tcl/doc/flush.n
new file mode 100644
index 00000000..bc668349
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/flush.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/flush.n,v 1.1 93/05/03 17:09:40 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS flush tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+flush \- Flush buffered output for a file
+.SH SYNOPSIS
+\fBflush \fIfileId\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Flushes any output that has been buffered for \fIfileId\fR.
+\fIFileId\fR must have been the return
+value from a previous call to \fBopen\fR, or it may be
+\fBstdout\fR or \fBstderr\fR to access one of the standard I/O streams;
+it must refer to a file that was opened for writing.
+The command returns an empty string.
+
+.SH KEYWORDS
+buffer, file, flush, output
diff --git a/vendor/x11iraf/obm/Tcl/doc/for.n b/vendor/x11iraf/obm/Tcl/doc/for.n
new file mode 100644
index 00000000..45915c6c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/for.n
@@ -0,0 +1,57 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/for.n,v 1.1 93/05/03 17:09:41 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS for tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+for \- ``For'' loop
+.SH SYNOPSIS
+\fBfor \fIstart test next body\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBFor\fR is a looping command, similar in structure to the C
+\fBfor\fR statement. The \fIstart\fR, \fInext\fR, and
+\fIbody\fR arguments must be Tcl command strings, and \fItest\fR
+is an expression string.
+The \fBfor\fR command first invokes the Tcl interpreter to
+execute \fIstart\fR. Then it repeatedly evaluates \fItest\fR as
+an expression; if the result is non-zero it invokes the Tcl
+interpreter on \fIbody\fR, then invokes the Tcl interpreter on \fInext\fR,
+then repeats the loop. The command terminates when \fItest\fR evaluates
+to 0. If a \fBcontinue\fR command is invoked within \fIbody\fR then
+any remaining commands in the current execution of \fIbody\fR are skipped;
+processing continues by invoking the Tcl interpreter on \fInext\fR, then
+evaluating \fItest\fR, and so on. If a \fBbreak\fR command is invoked
+within \fIbody\fR
+or \fInext\fR,
+then the \fBfor\fR command will
+return immediately.
+The operation of \fBbreak\fR and \fBcontinue\fR are similar to the
+corresponding statements in C.
+\fBFor\fR returns an empty string.
+
+.SH KEYWORDS
+for, iteration, looping
diff --git a/vendor/x11iraf/obm/Tcl/doc/foreach.n b/vendor/x11iraf/obm/Tcl/doc/foreach.n
new file mode 100644
index 00000000..63fe0063
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/foreach.n
@@ -0,0 +1,47 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/foreach.n,v 1.1 93/05/03 17:09:42 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS foreach tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+foreach \- Iterate over all elements in a list
+.SH SYNOPSIS
+\fBforeach \fIvarname list body\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+In this command \fIvarname\fR is the name of a variable, \fIlist\fR
+is a list of values to assign to \fIvarname\fR, and \fIbody\fR is a
+Tcl script.
+For each element of \fIlist\fR (in order
+from left to right), \fBforeach\fR assigns the contents of the
+field to \fIvarname\fR as if the \fBlindex\fR command had been used
+to extract the field, then calls the Tcl interpreter to execute
+\fIbody\fR. The \fBbreak\fR and \fBcontinue\fR statements may be
+invoked inside \fIbody\fR, with the same effect as in the \fBfor\fR
+command. \fBForeach\fR returns an empty string.
+
+.SH KEYWORDS
+foreach, iteration, list, looping
diff --git a/vendor/x11iraf/obm/Tcl/doc/format.n b/vendor/x11iraf/obm/Tcl/doc/format.n
new file mode 100644
index 00000000..69f66d2d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/format.n
@@ -0,0 +1,233 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/format.n,v 1.4 93/08/05 13:56:19 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS format tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+format \- Format a string in the style of sprintf
+.SH SYNOPSIS
+\fBformat \fIformatString \fR?\fIarg arg ...\fR?
+.BE
+
+.SH INTRODUCTION
+.PP
+This command generates a formatted string in the same way as the
+ANSI C \fBsprintf\fR procedure (it uses \fBsprintf\fR in its
+implementation).
+\fIFormatString\fR indicates how to format the result, using
+\fB%\fR conversion specifiers as in \fBsprintf\fR, and the additional
+arguments, if any, provide values to be substituted into the result.
+The return value from \fBformat\fR is the formatted string.
+
+.SH "DETAILS ON FORMATTING"
+.PP
+The command operates by scanning \fIformatString\fR from left to right.
+Each character from the format string is appended to the result
+string unless it is a percent sign.
+If the character is a \fB%\fR then it is not copied to the result string.
+Instead, the characters following the \fB%\fR character are treated as
+a conversion specifier.
+The conversion specifier controls the conversion of the next successive
+\fIarg\fR to a particular format and the result is appended to
+the result string in place of the conversion specifier.
+If there are multiple conversion specifiers in the format string,
+then each one controls the conversion of one additional \fIarg\fR.
+The \fBformat\fR command must be given enough \fIarg\fRs to meet the needs
+of all of the conversion specifiers in \fIformatString\fR.
+.PP
+Each conversion specifier may contain up to six different parts:
+.VS
+an XPG3 position specifier,
+.VE
+a set of flags, a minimum field width, a precision, a length modifier,
+and a conversion character.
+Any of these fields may be omitted except for the conversion character.
+The fields that are present must appear in the order given above.
+The paragraphs below discuss each of these fields in turn.
+.PP
+.VS
+If the \fB%\fR is followed by a decimal number and a \fB$\fR, as in
+``\fB%2$d\fR'', then the value to convert is not taken from the
+next sequential argument.
+Instead, it is taken from the argument indicated by the number,
+where 1 corresponds to the first \fIarg\fR.
+If the conversion specifier requires multiple arguments because
+of \fB*\fR characters in the specifier then
+successive arguments are used, starting with the argument
+given by the number.
+This follows the XPG3 conventions for positional specifiers.
+If there are any positional specifiers in \fIformatString\fR
+then all of the specifiers must be positional.
+.VE
+.PP
+The second portion of a conversion specifier may contain any of the
+following flag characters, in any order:
+.TP 10
+\fB\-\fR
+Specifies that the converted argument should be left-justified
+in its field (numbers are normally right-justified with leading
+spaces if needed).
+.TP 10
+\fB+\fR
+Specifies that a number should always be printed with a sign,
+even if positive.
+.TP 10
+\fIspace\fR
+Specifies that a space should be added to the beginning of the
+number if the first character isn't a sign.
+.TP 10
+\fB0\fR
+Specifies that the number should be padded on the left with
+zeroes instead of spaces.
+.TP 10
+\fB#\fR
+Requests an alternate output form. For \fBo\fR and \fBO\fR
+conversions it guarantees that the first digit is always \fB0\fR.
+For \fBx\fR or \fBX\fR conversions, \fB0x\fR or \fB0X\fR (respectively)
+will be added to the beginning of the result unless it is zero.
+For all floating-point conversions (\fBe\fR, \fBE\fR, \fBf\fR,
+\fBg\fR, and \fBG\fR) it guarantees that the result always
+has a decimal point.
+For \fBg\fR and \fBG\fR conversions it specifies that
+trailing zeroes should not be removed.
+.PP
+The third portion of a conversion specifier is a number giving a
+minimum field width for this conversion.
+It is typically used to make columns line up in tabular printouts.
+If the converted argument contains fewer characters than the
+minimum field width then it will be padded so that it is as wide
+as the minimum field width.
+Padding normally occurs by adding extra spaces on the left of the
+converted argument, but the \fB0\fR and \fB\-\fR flags
+may be used to specify padding with zeroes on the left or with
+spaces on the right, respectively.
+If the minimum field width is specified as \fB*\fR rather than
+a number, then the next argument to the \fBformat\fR command
+determines the minimum field width; it must be a numeric string.
+.PP
+The fourth portion of a conversion specifier is a precision,
+which consists of a period followed by a number.
+The number is used in different ways for different conversions.
+For \fBe\fR, \fBE\fR, and \fBf\fR conversions it specifies the number
+of digits to appear to the right of the decimal point.
+For \fBg\fR and \fBG\fR conversions it specifies the total number
+of digits to appear, including those on both sides of the decimal
+point (however, trailing zeroes after the decimal point will still
+be omitted unless the \fB#\fR flag has been specified).
+For integer conversions, it specifies a mimimum number of digits
+to print (leading zeroes will be added if necessary).
+For \fBs\fR conversions it specifies the maximum number of characters to be
+printed; if the string is longer than this then the trailing characters will be dropped.
+If the precision is specified with \fB*\fR rather than a number
+then the next argument to the \fBformat\fR command determines the precision;
+it must be a numeric string.
+.PP
+The fourth part of a conversion specifier is a length modifier,
+which must be \fBh\fR or \fBl\fR.
+If it is \fBh\fR it specifies that the numeric value should be
+truncated to a 16-bit value before converting.
+This option is rarely useful.
+The \fBl\fR modifier is ignored.
+.PP
+The last thing in a conversion specifier is an alphabetic character
+that determines what kind of conversion to perform.
+The following conversion characters are currently supported:
+.TP 10
+\fBd\fR
+Convert integer to signed decimal string.
+.TP 10
+\fBu\fR
+Convert integer to unsigned decimal string.
+.TP 10
+\fBi\fR
+Convert integer to signed decimal string; the integer may either be
+in decimal, in octal (with a leading \fB0\fR) or in hexadecimal
+(with a leading \fB0x\fR).
+.TP 10
+\fBo\fR
+Convert integer to unsigned octal string.
+.TP 10
+\fBx\fR or \fBX\fR
+Convert integer to unsigned hexadecimal string, using digits
+``0123456789abcdef'' for \fBx\fR and ``0123456789ABCDEF'' for \fBX\fR).
+.TP 10
+\fBc\fR
+Convert integer to the 8-bit character it represents.
+.TP 10
+\fBs\fR
+No conversion; just insert string.
+.TP 10
+\fBf\fR
+Convert floating-point number to signed decimal string of
+the form \fIxx.yyy\fR, where the number of \fIy\fR's is determined by
+the precision (default: 6).
+If the precision is 0 then no decimal point is output.
+.TP 10
+\fBe\fR or \fBe\fR
+Convert floating-point number to scientific notation in the
+form \fIx.yyy\fBe\(+-\fIzz\fR, where the number of \fIy\fR's is determined
+by the precision (default: 6).
+If the precision is 0 then no decimal point is output.
+If the \fBE\fR form is used then \fBE\fR is
+printed instead of \fBe\fR.
+.TP 10
+\fBg\fR or \fBG\fR
+If the exponent is less than \-4 or greater than or equal to the
+precision, then convert floating-point number as for \fB%e\fR or
+\fB%E\fR.
+Otherwise convert as for \fB%f\fR.
+Trailing zeroes and a trailing decimal point are omitted.
+.TP 10
+\fB%\fR
+No conversion: just insert \fB%\fR.
+.LP
+For the numerical conversions the argument being converted must
+be an integer or floating-point string; format converts the argument
+to binary and then converts it back to a string according to
+the conversion specifier.
+
+.SH "DIFFERENCES FROM ANSI SPRINTF"
+.PP
+.VS
+The behavior of the format command is the same as the
+ANSI C \fBsprintf\fR procedure except for the following
+differences:
+.IP [1]
+\fB%p\fR and \fB%n\fR specifiers are not currently supported.
+.VE
+.IP [2]
+For \fB%c\fR conversions the argument must be a decimal string,
+which will then be converted to the corresponding character value.
+.IP [3]
+.VS
+The \fBl\fR modifier is ignored; integer values are always converted
+as if there were no modifier present and real values are always
+converted as if the \fBl\fR modifier were present (i.e. type
+\fBdouble\fR is used for the internal representation).
+If the \fBh\fR modifier is specified then integer values are truncated
+to \fBshort\fR before conversion.
+.VE
+
+.SH KEYWORDS
+conversion specifier, format, sprintf, string, substitution
diff --git a/vendor/x11iraf/obm/Tcl/doc/gets.n b/vendor/x11iraf/obm/Tcl/doc/gets.n
new file mode 100644
index 00000000..da0bd3a0
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/gets.n
@@ -0,0 +1,61 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/gets.n,v 1.2 93/10/04 16:01:09 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS gets tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+gets \- Read a line from a file
+.SH SYNOPSIS
+\fBgets \fIfileId\fR ?\fIvarName\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command reads the next line from the file given by \fIfileId\fR
+and discards the terminating newline character.
+If \fIvarName\fR is specified then the line is placed in the variable
+by that name and the return value is a count of the number of characters
+read (not including the newline).
+If the end of the file is reached before reading
+any characters then \-1 is returned and \fIvarName\fR is set to an
+empty string.
+If \fIvarName\fR is not specified then the return value will be
+the line (minus the newline character) or an empty string if
+the end of the file is reached before reading any characters.
+An empty string will also be returned if a line contains no characters
+except the newline, so \fBeof\fR may have to be used to determine
+what really happened.
+If the last character in the file is not a newline character then
+\fBgets\fR behaves as if there were an additional newline character
+at the end of the file.
+\fIFileId\fR must be \fBstdin\fR or the return value from a previous
+call to \fBopen\fR; it must refer to a file that was opened
+for reading.
+.VS
+Any existing end-of-file or error condition on the file is cleared at
+the beginning of the \fBgets\fR command.
+.VE
+
+.SH KEYWORDS
+file, line, read
diff --git a/vendor/x11iraf/obm/Tcl/doc/glob.n b/vendor/x11iraf/obm/Tcl/doc/glob.n
new file mode 100644
index 00000000..3b358e2d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/glob.n
@@ -0,0 +1,92 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/glob.n,v 1.3 93/06/17 15:50:54 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS glob tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+glob \- Return names of files that match patterns
+.SH SYNOPSIS
+\fBglob \fR?\fIswitches\fR? \fIpattern \fR?\fIpattern ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command performs file name ``globbing'' in a fashion similar to
+the csh shell. It returns a list of the files whose names match any
+of the \fIpattern\fR arguments.
+.LP
+If the initial arguments to \fBglob\fR start with \fB\-\fR then
+.VS
+they are treated as switches. The following switches are
+currently supported:
+.TP 15
+\fB\-nocomplain\fR
+Allows an empty list to be returned without error; without this
+switch an error is returned if the result list would be empty.
+.TP 15
+\fB\-\|\-\fR
+Marks the end of switches. The argument following this one will
+be treated as a \fIpattern\fR even if it starts with a \fB\-.
+.VE
+.PP
+The \fIpattern\fR arguments may contain any of the following
+special characters:
+.TP 10
+\fB?\fR
+Matches any single character.
+.TP 10
+\fB*\fR
+Matches any sequence of zero or more characters.
+.TP 10
+\fB[\fIchars\fB]\fR
+Matches any single character in \fIchars\fR. If \fIchars\fR
+contains a sequence of the form \fIa\fB\-\fIb\fR then any
+character between \fIa\fR and \fIb\fR (inclusive) will match.
+.TP 10
+\fB\e\fIx\fR
+Matches the character \fIx\fR.
+.TP 10
+\fB{\fIa\fB,\fIb\fB,\fI...\fR}
+Matches any of the strings \fIa\fR, \fIb\fR, etc.
+.LP
+As with csh, a ``.'' at the beginning of a file's name or just
+after a ``/'' must be matched explicitly or with a {} construct.
+In addition, all ``/'' characters must be matched explicitly.
+.LP
+If the first character in a \fIpattern\fR is ``~'' then it refers
+to the home directory for the user whose name follows the ``~''.
+If the ``~'' is followed immediately by ``/'' then the value of
+the HOME environment variable is used.
+.LP
+The \fBglob\fR command differs from csh globbing in two ways.
+First, it does not sort its result list (use the \fBlsort\fR
+command if you want the list sorted).
+.VS
+Second, \fBglob\fR only returns the names of files that actually
+exist; in csh no check for existence is made unless a pattern
+contains a ?, *, or [] construct.
+.VE
+
+.SH KEYWORDS
+exist, file, glob, pattern
diff --git a/vendor/x11iraf/obm/Tcl/doc/global.n b/vendor/x11iraf/obm/Tcl/doc/global.n
new file mode 100644
index 00000000..4f7d7bd6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/global.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/global.n,v 1.1 93/05/03 17:09:46 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS global tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+global \- Access global variables
+.SH SYNOPSIS
+\fBglobal \fIvarname \fR?\fIvarname ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command is ignored unless a Tcl procedure is being interpreted.
+If so then it declares the given \fIvarname\fR's to be global variables
+rather than local ones. For the duration of the current procedure
+(and only while executing in the current procedure), any reference to
+any of the \fIvarname\fRs will refer to the global variable by the same
+name.
+
+.SH KEYWORDS
+global, procedure, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/history.n b/vendor/x11iraf/obm/Tcl/doc/history.n
new file mode 100644
index 00000000..933b51b6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/history.n
@@ -0,0 +1,181 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/history.n,v 1.1 93/05/03 17:09:47 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS history tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+history \- Manipulate the history list
+.SH SYNOPSIS
+\fBhistory \fR?\fIoption\fR? ?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fBhistory\fR command performs one of several operations related to
+recently-executed commands recorded in a history list. Each of
+these recorded commands is referred to as an ``event''. When
+specifying an event to the \fBhistory\fR command, the following
+forms may be used:
+.IP [1]
+A number: if positive, it refers to the event with
+that number (all events are numbered starting at 1). If the number
+is negative, it selects an event relative to the current event
+(\fB\-1\fR refers to the previous event, \fB\-2\fR to the one before that, and
+so on).
+.IP [2]
+A string: selects the most recent event that matches the string.
+An event is considered to match the string either if the string is
+the same as the first characters of the event, or if the string
+matches the event in the sense of the \fBstring match\fR command.
+.LP
+The \fBhistory\fR command can take any of the following forms:
+.TP
+\fBhistory\fR
+Same
+as \fBhistory info\fR, described below.
+.TP
+\fBhistory add\fI command \fR?\fBexec\fR?
+Adds the \fIcommand\fR argument to the history list as a new event. If
+\fBexec\fR is specified (or abbreviated) then the command is also
+executed and its result is returned. If \fBexec\fR isn't specified
+then an empty string is returned as result.
+.TP
+\fBhistory change\fI newValue\fR ?\fIevent\fR?
+Replaces the value recorded for an event with \fInewValue\fR. \fIEvent\fR
+specifies the event to replace, and
+defaults to the \fIcurrent\fR event (not event \fB\-1\fR). This command
+is intended for use in commands that implement new forms of history
+substitution and wish to replace the current event (which invokes the
+substitution) with the command created through substitution. The return
+value is an empty string.
+.TP
+\fBhistory event\fR ?\fIevent\fR?
+Returns the value of the event given by \fIevent\fR. \fIEvent\fR
+defaults to \fB\-1\fR. This command causes history revision to occur:
+see below for details.
+.TP
+\fBhistory info \fR?\fIcount\fR?
+Returns a formatted string (intended for humans to read) giving
+the event number and contents for each of the events in the history
+list except the current event. If \fIcount\fR is specified
+then only the most recent \fIcount\fR events are returned.
+.TP
+\fBhistory keep \fIcount\fR
+This command may be used to change the size of the history list to
+\fIcount\fR events. Initially, 20 events are retained in the history
+list. This command returns an empty string.
+.TP
+\fBhistory nextid\fR
+Returns the number of the next event to be recorded
+in the history list. It is useful for things like printing the
+event number in command-line prompts.
+.TP
+\fBhistory redo \fR?\fIevent\fR?
+Re-executes the command indicated by \fIevent\fR and return its result.
+\fIEvent\fR defaults to \fB\-1\fR. This command results in history
+revision: see below for details.
+.TP
+\fBhistory substitute \fIold new \fR?\fIevent\fR?
+Retrieves the command given by \fIevent\fR
+(\fB\-1\fR by default), replace any occurrences of \fIold\fR by
+\fInew\fR in the command (only simple character equality is supported;
+no wild cards), execute the resulting command, and return the result
+of that execution. This command results in history
+revision: see below for details.
+.TP
+\fBhistory words \fIselector\fR ?\fIevent\fR?
+Retrieves from the command given by \fIevent\fR (\fB\-1\fR by default)
+the words given by \fIselector\fR, and return those words in a string
+separated by spaces. The \fBselector\fR argument has three forms.
+If it is a single number then it selects the word given by that
+number (\fB0\fR for the command name, \fB1\fR for its first argument,
+and so on). If it consists of two numbers separated by a dash,
+then it selects all the arguments between those two. Otherwise
+\fBselector\fR is treated as a pattern; all words matching that
+pattern (in the sense of \fBstring match\fR) are returned. In
+the numeric forms \fB$\fR may be used
+to select the last word of a command.
+For example, suppose the most recent command in the history list is
+.RS
+.DS
+\fBformat {%s is %d years old} Alice [expr $ageInMonths/12]\fR
+.DE
+Below are some history commands and the results they would produce:
+.DS
+.ta 4c
+.fi
+.UL Command " "
+.UL Result
+.nf
+
+\fBhistory words $ [expr $ageInMonths/12]\fR
+\fBhistory words 1-2 {%s is %d years old} Alice\fR
+\fBhistory words *a*o* {%s is %d years old} [expr $ageInMonths/12]\fR
+.DE
+\fBHistory words\fR results in history revision: see below for details.
+.RE
+.SH "HISTORY REVISION"
+.PP
+The history options \fBevent\fR, \fBredo\fR, \fBsubstitute\fR,
+and \fBwords\fR result in ``history revision''.
+When one of these options is invoked then the current event
+is modified to eliminate the history command and replace it with
+the result of the history command.
+For example, suppose that the most recent command in the history
+list is
+.DS
+\fBset a [expr $b+2]\fR
+.DE
+and suppose that the next command invoked is one of the ones on
+the left side of the table below. The command actually recorded in
+the history event will be the corresponding one on the right side
+of the table.
+.ne 1.5c
+.DS
+.ta 4c
+.fi
+.UL "Command Typed" " "
+.UL "Command Recorded"
+.nf
+
+\fBhistory redo set a [expr $b+2]\fR
+\fBhistory s a b set b [expr $b+2]\fR
+\fBset c [history w 2] set c [expr $b+2]\fR
+.DE
+History revision is needed because event specifiers like \fB\-1\fR
+are only valid at a particular time: once more events have been
+added to the history list a different event specifier would be
+needed.
+History revision occurs even when \fBhistory\fR is invoked
+indirectly from the current event (e.g. a user types a command
+that invokes a Tcl procedure that invokes \fBhistory\fR): the
+top-level command whose execution eventually resulted in a
+\fBhistory\fR command is replaced.
+If you wish to invoke commands like \fBhistory words\fR without
+history revision, you can use \fBhistory event\fR to save the
+current history event and then use \fBhistory change\fR to
+restore it later.
+
+.SH KEYWORDS
+event, history, record, revision
diff --git a/vendor/x11iraf/obm/Tcl/doc/if.n b/vendor/x11iraf/obm/Tcl/doc/if.n
new file mode 100644
index 00000000..d15b90a5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/if.n
@@ -0,0 +1,58 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/if.n,v 1.1 93/05/03 17:34:01 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS if tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+if \- Execute scripts conditionally
+.SH SYNOPSIS
+\fBif \fIexpr1 \fR?\fBthen\fR? \fIbody1 \fBelseif \fIexpr2 \fR?\fBthen\fR? \fIbody2\fR \fBelseif\fR ... \fR?\fBelse\fR? ?\fIbodyN\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fIif\fR command evaluates \fIexpr1\fR as an expression (in the
+same way that \fBexpr\fR evaluates its argument). The value of the
+expression must be a boolean
+.VS
+(a numeric value, where 0 is false and
+anything is true, or a string value such as \fBtrue\fR or \fByes\fR
+for true and \fBfalse\fR or \fBno\fR for false);
+.VE
+if it is true then \fIbody1\fR is executed by passing it to the
+Tcl interpreter.
+Otherwise \fIexpr2\fR is evaluated as an expression and if it is true
+then \fBbody2\fR is executed, and so on.
+If none of the expressions evaluates to true then \fIbodyN\fR is
+executed.
+The \fBthen\fR and \fBelse\fR arguments are optional
+``noise words'' to make the command easier to read.
+There may be any number of \fBelseif\fR clauses, including zero.
+\fIBodyN\fR may also be omitted as long as \fBelse\fR is omitted too.
+The return value from the command is the result of the body script
+that was executed, or an empty string
+if none of the expressions was non-zero and there was no \fIbodyN\fR.
+
+.SH KEYWORDS
+boolean, conditional, else, false, if, true
diff --git a/vendor/x11iraf/obm/Tcl/doc/incr.n b/vendor/x11iraf/obm/Tcl/doc/incr.n
new file mode 100644
index 00000000..a5340105
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/incr.n
@@ -0,0 +1,44 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/incr.n,v 1.1 93/05/03 17:34:02 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS incr tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+incr \- Increment the value of a variable
+.SH SYNOPSIS
+\fBincr \fIvarName \fR?\fIincrement\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Increments the value stored in the variable whose name is \fIvarName\fR.
+The value of the variable must be an integer.
+If \fIincrement\fR is supplied then its value (which must be an
+integer) is added to the value of variable \fIvarName\fR; otherwise
+1 is added to \fIvarName\fR.
+The new value is stored as a decimal string in variable \fIvarName\fR
+and also returned as result.
+
+.SH KEYWORDS
+add, increment, variable, value
diff --git a/vendor/x11iraf/obm/Tcl/doc/info.n b/vendor/x11iraf/obm/Tcl/doc/info.n
new file mode 100644
index 00000000..2806aa4a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/info.n
@@ -0,0 +1,162 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/info.n,v 1.2 93/06/18 13:58:33 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS info tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+info \- Return information about the state of the Tcl interpreter
+.SH SYNOPSIS
+\fBinfo \fIoption \fR?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command provides information about various internals of the Tcl
+interpreter.
+The legal \fIoption\fR's (which may be abbreviated) are:
+.TP
+\fBinfo args \fIprocname\fR
+Returns a list containing the names of the arguments to procedure
+\fIprocname\fR, in order. \fIProcname\fR must be the name of a
+Tcl command procedure.
+.TP
+\fBinfo body \fIprocname\fR
+Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be
+the name of a Tcl command procedure.
+.TP
+\fBinfo cmdcount\fR
+Returns a count of the total number of commands that have been invoked
+in this interpreter.
+.TP
+\fBinfo commands \fR?\fIpattern\fR?
+If \fIpattern\fR isn't specified, returns a list of names of all the
+Tcl commands, including both the built-in commands written in C and
+the command procedures defined using the \fBproc\fR command.
+If \fIpattern\fR is specified, only those names matching \fIpattern\fR
+are returned. Matching is determined using the same rules as for
+\fBstring match\fR.
+.TP
+\fBinfo complete \fIcommand\fR
+Returns 1 if \fIcommand\fR is a complete Tcl command in the sense of
+having no unclosed quotes, braces, brackets or array element names,
+If the command doesn't appear to be complete then 0 is returned.
+This command is typically used in line-oriented input environments
+to allow users to type in commands that span multiple lines; if the
+command isn't complete, the script can delay evaluating it until additional
+lines have been typed to complete the command.
+.TP
+\fBinfo default \fIprocname arg varname\fR
+\fIProcname\fR must be the name of a Tcl command procedure and \fIarg\fR
+must be the name of an argument to that procedure. If \fIarg\fR
+doesn't have a default value then the command returns \fB0\fR.
+Otherwise it returns \fB1\fR and places the default value of \fIarg\fR
+into variable \fIvarname\fR.
+.TP
+\fBinfo exists \fIvarName\fR
+Returns \fB1\fR if the variable named \fIvarName\fR exists in the
+current context (either as a global or local variable), returns \fB0\fR
+otherwise.
+.TP
+\fBinfo globals \fR?\fIpattern\fR?
+If \fIpattern\fR isn't specified, returns a list of all the names
+of currently-defined global variables.
+If \fIpattern\fR is specified, only those names matching \fIpattern\fR
+are returned. Matching is determined using the same rules as for
+\fBstring match\fR.
+.TP
+\fBinfo level\fR ?\fInumber\fR?
+If \fInumber\fR is not specified, this command returns a number
+giving the stack level of the invoking procedure, or 0 if the
+command is invoked at top-level. If \fInumber\fR is specified,
+then the result is a list consisting of the name and arguments for the
+procedure call at level \fInumber\fR on the stack. If \fInumber\fR
+is positive then it selects a particular stack level (1 refers
+to the top-most active procedure, 2 to the procedure it called, and
+so on); otherwise it gives a level relative to the current level
+(0 refers to the current procedure, -1 to its caller, and so on).
+See the \fBuplevel\fR command for more information on what stack
+levels mean.
+.TP
+\fBinfo library\fR
+Returns the name of the library directory in which standard Tcl
+scripts are stored.
+The default value for the library is compiled into Tcl, but it
+may be overridden by setting the TCL_LIBRARY environment variable.
+If there is no TCL_LIBRARY variable and no compiled-in value then
+and error is generated.
+See the \fBlibrary\fR manual entry for details of the facilities
+provided by the Tcl script library.
+Normally each application will have its own application-specific
+script library in addition to the Tcl script library; I suggest that
+each application set a global variable with a name like
+\fB$\fIapp\fB_library\fR (where \fIapp\fR is the application's name)
+to hold the location of that application's library directory.
+.TP
+\fBinfo locals \fR?\fIpattern\fR?
+If \fIpattern\fR isn't specified, returns a list of all the names
+of currently-defined local variables, including arguments to the
+current procedure, if any.
+Variables defined with the \fBglobal\fR and \fBupvar\fR commands
+will not be returned.
+If \fIpattern\fR is specified, only those names matching \fIpattern\fR
+are returned. Matching is determined using the same rules as for
+\fBstring match\fR.
+.TP
+\fBinfo patchlevel\fR
+.VS
+Returns a decimal integer giving the current patch level for Tcl.
+The patch level is incremented for each new release or patch, and
+it uniquely identifies an official version of Tcl.
+.VE
+.TP
+\fBinfo procs \fR?\fIpattern\fR?
+If \fIpattern\fR isn't specified, returns a list of all the
+names of Tcl command procedures.
+If \fIpattern\fR is specified, only those names matching \fIpattern\fR
+are returned. Matching is determined using the same rules as for
+\fBstring match\fR.
+.TP
+\fBinfo script\fR
+If a Tcl script file is currently being evaluated (i.e. there is a
+call to \fBTcl_EvalFile\fR active or there is an active invocation
+of the \fBsource\fR command), then this command returns the name
+of the innermost file being processed. Otherwise the command returns an
+empty string.
+.TP
+\fBinfo tclversion\fR
+Returns the version number for this version of Tcl in the form \fIx.y\fR,
+where changes to \fIx\fR represent major changes with probable
+incompatibilities and changes to \fIy\fR represent small enhancements and
+bug fixes that retain backward compatibility.
+.TP
+\fBinfo vars\fR ?\fIpattern\fR?
+If \fIpattern\fR isn't specified,
+returns a list of all the names of currently-visible variables, including
+both locals and currently-visible globals.
+If \fIpattern\fR is specified, only those names matching \fIpattern\fR
+are returned. Matching is determined using the same rules as for
+\fBstring match\fR.
+
+.SH KEYWORDS
+command, information, interpreter, level, procedure, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/join.n b/vendor/x11iraf/obm/Tcl/doc/join.n
new file mode 100644
index 00000000..d98b0c77
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/join.n
@@ -0,0 +1,42 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/join.n,v 1.1 93/05/03 17:34:03 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS join tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+join \- Create a string by joining together list elements
+.SH SYNOPSIS
+\fBjoin \fIlist \fR?\fIjoinString\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fIlist\fR argument must be a valid Tcl list.
+This command returns the string
+formed by joining all of the elements of \fIlist\fR together with
+\fIjoinString\fR separating each adjacent pair of elements.
+The \fIjoinString\fR argument defaults to a space character.
+
+.SH KEYWORDS
+element, join, list, separator
diff --git a/vendor/x11iraf/obm/Tcl/doc/lappend.n b/vendor/x11iraf/obm/Tcl/doc/lappend.n
new file mode 100644
index 00000000..02c6bcc3
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lappend.n
@@ -0,0 +1,48 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lappend.n,v 1.1 93/05/03 17:34:04 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lappend tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lappend \- Append list elements onto a variable
+.SH SYNOPSIS
+\fBlappend \fIvarName value \fR?\fIvalue value ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command treats the variable given by \fIvarName\fR as a list
+and appends each of the \fIvalue\fR arguments to that list as a separate
+element, with spaces between elements.
+If \fIvarName\fR doesn't exist, it is created as a list with elements
+given by the \fIvalue\fR arguments.
+\fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs
+are appended as list elements rather than raw text.
+This command provides a relatively efficient way to build up
+large lists. For example, ``\fBlappend a $b\fR'' is much
+more efficient than ``\fBset a [concat $a [list $b]]\fR'' when
+\fB$a\fR is long.
+
+.SH KEYWORDS
+append, element, list, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/library.n b/vendor/x11iraf/obm/Tcl/doc/library.n
new file mode 100644
index 00000000..619ac1f5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/library.n
@@ -0,0 +1,239 @@
+'\"
+'\" Copyright (c) 1991-1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/library.n,v 1.11 93/08/28 16:05:59 ouster Exp $ SPRITE (Berkeley)
+'
+.so man.macros
+.de UL
+\\$1\l'|0\(ul'\\$2
+..
+.HS library tcl
+.BS
+.SH NAME
+library \- standard library of Tcl procedures
+.SH SYNOPSIS
+.nf
+\fBauto_execok \fIcmd\fR
+\fBauto_load \fIcmd\fR
+\fBauto_mkindex \fIdir pattern pattern ...\fR
+\fBauto_reset\fR
+\fBparray \fIarrayName\fR
+\fBunknown \fIcmd \fR?\fIarg arg ...\fR?
+.fi
+.BE
+
+.SH INTRODUCTION
+.PP
+Tcl includes a library of Tcl procedures for commonly-needed functions.
+The procedures defined in the Tcl library are generic ones suitable
+for use by many different applications.
+The location of the Tcl library is returned by the \fBinfo library\fR
+command.
+In addition to the Tcl library, each application will normally have
+its own library of support procedures as well; the location of this
+library is normally given by the value of the \fB$\fIapp\fB_library\fR
+global variable, where \fIapp\fR is the name of the application.
+For example, the location of the Tk library is kept in the variable
+\fB$tk_library\fR.
+.PP
+To access the procedures in the Tcl library, an application should
+source the file \fBinit.tcl\fR in the library, for example with
+the Tcl command
+.DS
+\fBsource [info library]/init.tcl
+.DE
+This will define the \fBunknown\fR procedure and arrange for the
+other procedures to be loaded on-demand using the auto-load
+mechanism defined below.
+
+.SH "COMMAND PROCEDURES"
+.PP
+The following procedures are provided in the Tcl library:
+.TP
+\fBauto_execok \fIcmd\fR
+Determines whether there is an executable file by the name \fIcmd\fR.
+This command examines the directories in the current search path
+(given by the PATH enviornment variable) to see if there is an
+executable file named \fIcmd\fR in any of those directories.
+If so, it returns 1; if not it returns 0. \fBAuto_exec\fR
+remembers information about previous searches in an array
+named \fBauto_execs\fR; this avoids the path search in
+future calls for the same \fIcmd\fR. The command \fBauto_reset\fR
+may be used to force \fBauto_execok\fR to forget its cached
+information.
+.TP
+\fBauto_load \fIcmd\fR
+This command attempts to load the definition for a Tcl command named
+\fIcmd\fR.
+To do this, it searches an \fIauto-load path\fR, which is a list of
+one or more directories.
+The auto-load path is given by the global variable \fB$auto_path\fR
+if it exists.
+If there is no \fB$auto_path\fR variable, then the TCLLIBPATH environment
+variable is used, if it exists.
+Otherwise the auto-load path consists of just the Tcl library directory.
+Within each directory in the auto-load path there must be a file
+\fBtclIndex\fR that describes one
+.VS
+or more commands defined in that directory
+and a script to evaluate to load each of the commands.
+The \fBtclIndex\fR file should be generated with the
+\fBauto_mkindex\fR command.
+If \fIcmd\fR is found in an index file, then the appropriate
+script is evaluated to create the command.
+.VE
+The \fBauto_load\fR command returns 1 if \fIcmd\fR was successfully
+created.
+The command returns 0 if there was no index entry for \fIcmd\fR
+or if the script didn't actually define \fIcmd\fR (e.g. because
+index information is out of date).
+If an error occurs while processing the script, then that error
+is returned.
+\fBAuto_load\fR only reads the index information once and saves it
+in the array \fBauto_index\fR; future calls to \fBauto_load\fR
+check for \fIcmd\fR in the array rather than re-reading the index
+files.
+The cached index information may be deleted with the command
+\fBauto_reset\fR.
+This will force the next \fBauto_load\fR command to reload the
+index database from disk.
+.TP
+\fBauto_mkindex \fIdir pattern pattern ...\fR
+.VS
+Generates an index suitable for use by \fBauto_load\fR.
+The command searches \fIdir\fR for all files whose names match
+any of the \fIpattern\fR arguments
+.VE
+(matching is done with the \fBglob\fR command),
+generates an index of all the Tcl command
+procedures defined in all the matching files, and stores the
+index information in a file named \fBtclIndex\fR in \fIdir\fR.
+For example, the command
+.RS
+.DS
+\fBauto_mkindex foo *.tcl\fR
+.DE
+.LP
+will read all the \fB.tcl\fR files in subdirectory \fBfoo\fR
+and generate a new index file \fBfoo/tclIndex\fR.
+.PP
+\fBAuto_mkindex\fR parses the Tcl scripts in a relatively
+unsophisticated way: if any line contains the word \fBproc\fR
+as its first characters then it is assumed to be a procedure
+definition and the next word of the line is taken as the
+procedure's name.
+Procedure definitions that don't appear in this way (e.g. they
+have spaces before the \fBproc\fR) will not be indexed.
+.RE
+.TP
+\fBauto_reset\fR
+Destroys all the information cached by \fBauto_execok\fR and
+\fBauto_load\fR.
+This information will be re-read from disk the next time it is
+needed.
+\fBAuto_reset\fR also deletes any procedures listed in the auto-load
+index, so that fresh copies of them will be loaded the next time
+that they're used.
+.TP
+\fBparray \fIarrayName\fR
+Prints on standard output the names and values of all the elements
+in the array \fIarrayName\fR.
+\fBArrayName\fR must be an array accessible to the caller of \fBparray\fR.
+It may be either local or global.
+.TP
+\fBunknown \fIcmd \fR?\fIarg arg ...\fR?
+This procedure is invoked automatically by the Tcl interpreter
+whenever the name of a command doesn't exist.
+The \fBunknown\fR procedure receives as its arguments the
+name and arguments of the missing command.
+.VS
+\fBUnknown\fR first calls \fBauto_load\fR to load the command.
+.VE
+If this succeeds, then it executes the original command with its
+original arguments.
+If the auto-load fails then \fBunknown\fR calls \fBauto_execok\fR
+to see if there is an executable file by the name \fIcmd\fR.
+If so, it invokes the Tcl \fBexec\fR command
+with \fIcmd\fR and all the \fIargs\fR as arguments.
+If \fIcmd\fR can't be auto-executed, \fBunknown\fR checks to
+see if the command was invoked at top-level and outside of any
+script. If so, then \fBunknown\fR takes takes two additional steps.
+First, it sees if \fIcmd\fR has one of the following three forms:
+\fB!!\fR, \fB!\fIevent\fR, or \fB^\fIold\fB^\fInew\fR?\fB^\fR?.
+If so, then \fBunknown\fR carries out history substitution
+in the same way that \fBcsh\fR would for these constructs.
+Second, and last, \fBunknown\fR checks to see if \fIcmd\fR is
+a unique abbreviation for an existing Tcl command.
+If so, it expands the command name and executes the command with
+the original arguments.
+If none of the above efforts has been able to execute
+the command, \fBunknown\fR generates an error return.
+If the global variable \fBauto_noload\fR is defined, then the auto-load
+step is skipped.
+If the global variable \fBauto_noexec\fR is defined then the
+auto-exec step is skipped.
+Under normal circumstances the return value from \fBunknown\fR
+is the return value from the command that was eventually
+executed.
+
+.SH "VARIABLES"
+.PP
+The following global variables are defined or used by the procedures in
+the Tcl library:
+.TP
+\fBauto_execs\fR
+Used by \fBauto_execok\fR to record information about whether
+particular commands exist as executable files.
+.TP
+\fBauto_index\fR
+Used by \fBauto_load\fR to save the index information read from
+disk.
+.TP
+\fBauto_noexec\fR
+If set to any value, then \fBunknown\fR will not attempt to auto-exec
+any commands.
+.TP
+\fBauto_noload\fR
+If set to any value, then \fBunknown\fR will not attempt to auto-load
+any commands.
+.TP
+\fBauto_path\fR
+If set, then it must contain a valid Tcl list giving directories to
+search during auto-load operations.
+.TP
+\fBenv(TCL_LIBRARY)\fR
+If set, then it specifies the location of the directory containing
+library scripts (the value of this variable will be returned by
+the command \fBinfo library\fR). If this variable isn't set then
+a default value is used.
+.TP
+\fBenv(TCLLIBPATH)\fR
+If set, then it must contain a valid Tcl list giving directories to
+search during auto-load operations.
+This variable is only used if \fBauto_path\fR is not defined.
+.TP
+\fBunknown_active\fR
+This variable is set by \fBunknown\fR to indicate that it is active.
+It is used to detect errors where \fBunknown\fR recurses on itself
+infinitely.
+The variable is unset before \fBunknown\fR returns.
+
+.SH KEYWORDS
+auto-exec, auto-load, library, unknown
diff --git a/vendor/x11iraf/obm/Tcl/doc/lindex.n b/vendor/x11iraf/obm/Tcl/doc/lindex.n
new file mode 100644
index 00000000..60bd0a81
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lindex.n
@@ -0,0 +1,46 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lindex.n,v 1.1 93/05/03 17:34:05 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lindex tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lindex \- Retrieve an element from a list
+.SH SYNOPSIS
+\fBlindex \fIlist index\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command treats \fIlist\fR as a Tcl list and returns the
+\fIindex\fR'th element from it (0 refers to the first element of the list).
+In extracting the element, \fIlindex\fR observes the same rules
+concerning braces and quotes and backslashes as the Tcl command
+interpreter; however, variable
+substitution and command substitution do not occur.
+If \fIindex\fR is negative or greater than or equal to the number
+of elements in \fIvalue\fR, then an empty
+string is returned.
+
+.SH KEYWORDS
+element, index, list
diff --git a/vendor/x11iraf/obm/Tcl/doc/linsert.n b/vendor/x11iraf/obm/Tcl/doc/linsert.n
new file mode 100644
index 00000000..1cb7e5e7
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/linsert.n
@@ -0,0 +1,45 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/linsert.n,v 1.1 93/05/03 17:34:05 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS linsert tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+linsert \- Insert elements into a list
+.SH SYNOPSIS
+\fBlinsert \fIlist index element \fR?\fIelement element ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command produces a new list from \fIlist\fR by inserting all
+of the \fIelement\fR arguments just before the \fIindex\fRth
+element of \fIlist\fR. Each \fIelement\fR argument will become
+a separate element of the new list. If \fIindex\fR is less than
+or equal to zero, then the new elements are inserted at the
+beginning of the list. If \fIindex\fR is greater than or equal
+to the number of elements in the list, then the new elements are
+appended to the list.
+
+.SH KEYWORDS
+element, insert, list
diff --git a/vendor/x11iraf/obm/Tcl/doc/list.n b/vendor/x11iraf/obm/Tcl/doc/list.n
new file mode 100644
index 00000000..40992062
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/list.n
@@ -0,0 +1,62 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/list.n,v 1.2 93/10/28 16:19:11 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS list tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+list \- Create a list
+.SH SYNOPSIS
+.VS
+\fBlist \fR?\fIarg arg ...\fR?
+.VE
+.BE
+
+.SH DESCRIPTION
+.PP
+This command returns a list comprised of all the \fIarg\fRs,
+.VS
+or an empty string if no \fIarg\fRs are specified.
+.VE
+Braces and backslashes get added as necessary, so that the \fBindex\fR command
+may be used on the result to re-extract the original arguments, and also
+so that \fBeval\fR may be used to execute the resulting list, with
+\fIarg1\fR comprising the command's name and the other \fIarg\fRs comprising
+its arguments. \fBList\fR produces slightly different results than
+\fBconcat\fR: \fBconcat\fR removes one level of grouping before forming
+the list, while \fBlist\fR works directly from the original arguments.
+For example, the command
+.DS
+\fBlist a b {c d e} {f {g h}}
+.DE
+will return
+.DS
+\fBa b {c d e} {f {g h}}
+.DE
+while \fBconcat\fR with the same arguments will return
+.DS
+\fBa b c d e f {g h}\fR
+.DE
+
+.SH KEYWORDS
+element, list
diff --git a/vendor/x11iraf/obm/Tcl/doc/llength.n b/vendor/x11iraf/obm/Tcl/doc/llength.n
new file mode 100644
index 00000000..aecba66a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/llength.n
@@ -0,0 +1,39 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/llength.n,v 1.1 93/05/03 17:34:07 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS llength tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+llength \- Count the number of elements in a list
+.SH SYNOPSIS
+\fBllength \fIlist\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Treats \fIlist\fR as a list and returns a decimal string giving
+the number of elements in it.
+
+.SH KEYWORDS
+element, list, length
diff --git a/vendor/x11iraf/obm/Tcl/doc/lrange.n b/vendor/x11iraf/obm/Tcl/doc/lrange.n
new file mode 100644
index 00000000..b963906d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lrange.n
@@ -0,0 +1,51 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lrange.n,v 1.1 93/05/03 17:34:07 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lrange tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lrange \- Return one or more adjacent elements from a list
+.SH SYNOPSIS
+\fBlrange \fIlist first last
+.BE
+
+.SH DESCRIPTION
+.PP
+\fIList\fR must be a valid Tcl list. This command will
+return a new list consisting of elements
+\fIfirst\fR through \fIlast\fR, inclusive.
+\fILast\fR may be \fBend\fR (or any
+abbreviation of it) to refer to the last element of the list.
+If \fIfirst\fR is less than zero, it is treated as if it were zero.
+If \fIlast\fR is greater than or equal to the number of elements
+in the list, then it is treated as if it were \fBend\fR.
+If \fIfirst\fR is greater than \fIlast\fR then an empty string
+is returned.
+Note: ``\fBlrange \fIlist first first\fR'' does not always produce the
+same result as ``\fBlindex \fIlist first\fR'' (although it often does
+for simple fields that aren't enclosed in braces); it does, however,
+produce exactly the same results as ``\fBlist [lindex \fIlist first\fB]\fR''
+
+.SH KEYWORDS
+element, list, range, sublist
diff --git a/vendor/x11iraf/obm/Tcl/doc/lreplace.n b/vendor/x11iraf/obm/Tcl/doc/lreplace.n
new file mode 100644
index 00000000..c7d96f58
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lreplace.n
@@ -0,0 +1,55 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lreplace.n,v 1.1 93/05/03 17:34:08 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lreplace tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lreplace \- Replace elements in a list with new elements
+.SH SYNOPSIS
+\fBlreplace \fIlist first last \fR?\fIelement element ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBLreplace\fR returns a new list formed by replacing one or more elements of
+\fIlist\fR with the \fIelement\fR arguments.
+\fIFirst\fR gives the index in \fIlist\fR of the first element
+to be replaced.
+If \fIfirst\fR is less than zero then it refers to the first
+element of \fIlist\fR; the element indicated by \fIfirst\fR
+must exist in the list.
+\fILast\fR gives the index in \fIlist\fR of the last element
+to be replaced; it must be greater than or equal to \fIfirst\fR.
+\fILast\fR may be \fBend\fR (or any abbreviation of it) to indicate
+that all elements between \fIfirst\fR and the end of the list should
+be replaced.
+The \fIelement\fR arguments specify zero or more new arguments to
+be added to the list in place of those that were deleted.
+Each \fIelement\fR argument will become a separate element of
+the list.
+If no \fIelement\fR arguments are specified, then the elements
+between \fIfirst\fR and \fIlast\fR are simply deleted.
+
+.SH KEYWORDS
+element, list, replace
diff --git a/vendor/x11iraf/obm/Tcl/doc/lsearch.n b/vendor/x11iraf/obm/Tcl/doc/lsearch.n
new file mode 100644
index 00000000..af87eb7f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lsearch.n
@@ -0,0 +1,60 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lsearch.n,v 1.2 93/05/07 14:27:07 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lsearch tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lsearch \- See if a list contains a particular element
+.SH SYNOPSIS
+\fBlsearch \fR?\fImode\fR? \fIlist pattern\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command searches the elements of \fIlist\fR to see if one
+of them matches \fIpattern\fR.
+If so, the command returns the index of the first matching
+element.
+If not, the command returns \fB\-1\fR.
+.VS
+The \fImode\fR argument indicates how the elements of the list are to
+be matched against \fIpattern\fR and it must have one of the following
+values:
+.TP
+\fB\-exact\fR
+The list element must contain exactly the same string as \fIpattern\fR.
+.TP
+\fB\-glob\fR
+\fIPattern\fR is a glob-style pattern which is matched against each list
+element using the same rules as the \fBstring match\fR command.
+.TP
+\fB\-regexp\fR
+\fIPattern\fR is treated as a regular expression and matched against
+each list element using the same rules as the \fBregexp\fR command.
+.PP
+If \fImode\fR is omitted then it defaults to \fB\-glob\fR.
+.VE
+
+.SH KEYWORDS
+list, match, pattern, regular expression, search, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/lsort.n b/vendor/x11iraf/obm/Tcl/doc/lsort.n
new file mode 100644
index 00000000..a9985d14
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/lsort.n
@@ -0,0 +1,72 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/lsort.n,v 1.2 93/05/07 16:48:45 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS lsort tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+lsort \- Sort the elements of a list
+.SH SYNOPSIS
+\fBlsort \fR?\fIswitches\fR? \fIlist\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command sorts the elements of \fIlist\fR, returning a new
+list in sorted order. By default ASCII sorting is used with
+the result returned in increasing order.
+.VS
+However, any of the
+following switches may be specified before \fIlist\fR to
+control the sorting process (unique abbreviations are accepted):
+.TP 20
+\fB\-ascii\fR
+Use string comparison with ASCII collation order. This is
+the default.
+.TP 20
+\fB\-integer\fR
+Convert list elements to integers and use integer comparison.
+.TP 20
+\fB\-real\fR
+Convert list elements to floating-point values and use floating
+comparison.
+.TP 20
+\fB\-command\0\fIcommand\fR
+Use \fIcommand\fR as a comparison command.
+To compare two elements, evaluate a Tcl script consisting of
+\fIcommand\fR with the two elements appended as additional
+arguments. The script should return an integer less than,
+equal to, or greater than zero if the first element is to
+be considered less than, equal to, or greater than the second,
+respectively.
+.TP 20
+\fB\-increasing\fR
+Sort the list in increasing order (``smallest'' items first).
+This is the default.
+.TP 20
+\fB\-decreasing\fR
+Sort the list in decreasing order (``largest'' items first).
+.VE
+
+.SH KEYWORDS
+element, list, order, sort
diff --git a/vendor/x11iraf/obm/Tcl/doc/man.macros b/vendor/x11iraf/obm/Tcl/doc/man.macros
new file mode 100644
index 00000000..f45afa8e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/man.macros
@@ -0,0 +1,182 @@
+.\" The definitions below are for supplemental macros used in Tcl/Tk
+.\" manual entries.
+.\"
+.\" .HS name section [date [version]]
+.\" Replacement for .TH in other man pages. See below for valid
+.\" section names.
+.\"
+.\" .AP type name in/out [indent]
+.\" Start paragraph describing an argument to a library procedure.
+.\" type is type of argument (int, etc.), in/out is either "in", "out",
+.\" or "in/out" to describe whether procedure reads or modifies arg,
+.\" and indent is equivalent to second arg of .IP (shouldn't ever be
+.\" needed; use .AS below instead)
+.\"
+.\" .AS [type [name]]
+.\" Give maximum sizes of arguments for setting tab stops. Type and
+.\" name are examples of largest possible arguments that will be passed
+.\" to .AP later. If args are omitted, default tab stops are used.
+.\"
+.\" .BS
+.\" Start box enclosure. From here until next .BE, everything will be
+.\" enclosed in one large box.
+.\"
+.\" .BE
+.\" End of box enclosure.
+.\"
+.\" .VS
+.\" Begin vertical sidebar, for use in marking newly-changed parts
+.\" of man pages.
+.\"
+.\" .VE
+.\" End of vertical sidebar.
+.\"
+.\" .DS
+.\" Begin an indented unfilled display.
+.\"
+.\" .DE
+.\" End of indented unfilled display.
+.\"
+'\" # Heading for Tcl/Tk man pages
+.de HS
+.ds ^3 \\0
+.if !"\\$3"" .ds ^3 \\$3
+.if '\\$2'cmds' .TH \\$1 1 \\*(^3 \\$4
+.if '\\$2'lib' .TH \\$1 3 \\*(^3 \\$4
+.if '\\$2'tcl' .TH \\$1 n \\*(^3 Tcl "Tcl Built-In Commands"
+.if '\\$2'tk' .TH \\$1 n \\*(^3 Tk "Tk Commands"
+.if '\\$2'tclc' .TH \\$1 3 \\*(^3 Tcl "Tcl Library Procedures"
+.if '\\$2'tkc' .TH \\$1 3 \\*(^3 Tk "Tk Library Procedures"
+.if '\\$2'tclcmds' .TH \\$1 1 \\*(^3 Tk "Tcl Applications"
+.if '\\$2'tkcmds' .TH \\$1 1 \\*(^3 Tk "Tk Applications"
+.if t .wh -1.3i ^B
+.nr ^l \\n(.l
+.ad b
+..
+'\" # Start an argument description
+.de AP
+.ie !"\\$4"" .TP \\$4
+.el \{\
+. ie !"\\$2"" .TP \\n()Cu
+. el .TP 15
+.\}
+.ie !"\\$3"" \{\
+.ta \\n()Au \\n()Bu
+\&\\$1 \\fI\\$2\\fP (\\$3)
+.\".b
+.\}
+.el \{\
+.br
+.ie !"\\$2"" \{\
+\&\\$1 \\fI\\$2\\fP
+.\}
+.el \{\
+\&\\fI\\$1\\fP
+.\}
+.\}
+..
+'\" # define tabbing values for .AP
+.de AS
+.nr )A 10n
+.if !"\\$1"" .nr )A \\w'\\$1'u+3n
+.nr )B \\n()Au+15n
+.\"
+.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
+.nr )C \\n()Bu+\\w'(in/out)'u+2n
+..
+'\" # BS - start boxed text
+'\" # ^y = starting y location
+'\" # ^b = 1
+.de BS
+.br
+.mk ^y
+.nr ^b 1u
+.if n .nf
+.if n .ti 0
+.if n \l'\\n(.lu\(ul'
+.if n .fi
+..
+'\" # BE - end boxed text (draw box now)
+.de BE
+.nf
+.ti 0
+.mk ^t
+.ie n \l'\\n(^lu\(ul'
+.el \{\
+.\" Draw four-sided box normally, but don't draw top of
+.\" box if the box started on an earlier page.
+.ie !\\n(^b-1 \{\
+\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
+.\}
+.el \}\
+\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
+.\}
+.\}
+.fi
+.br
+.nr ^b 0
+..
+'\" # VS - start vertical sidebar
+'\" # ^Y = starting y location
+'\" # ^v = 1 (for troff; for nroff this doesn't matter)
+.de VS
+.mk ^Y
+.ie n 'mc \s12\(br\s0
+.el .nr ^v 1u
+..
+'\" # VE - end of vertical sidebar
+.de VE
+.ie n 'mc
+.el \{\
+.ev 2
+.nf
+.ti 0
+.mk ^t
+\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
+.sp -1
+.fi
+.ev
+.\}
+.nr ^v 0
+..
+'\" # Special macro to handle page bottom: finish off current
+'\" # box/sidebar if in box/sidebar mode, then invoked standard
+'\" # page bottom macro.
+.de ^B
+.ev 2
+'ti 0
+'nf
+.mk ^t
+.if \\n(^b \{\
+.\" Draw three-sided box if this is the box's first page,
+.\" draw two sides but no top otherwise.
+.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
+.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
+.\}
+.if \\n(^v \{\
+.nr ^x \\n(^tu+1v-\\n(^Yu
+\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
+.\}
+.bp
+'fi
+.ev
+.if \\n(^b \{\
+.mk ^y
+.nr ^b 2
+.\}
+.if \\n(^v \{\
+.mk ^Y
+.\}
+..
+'\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+'\" # DE - end display
+.de DE
+.fi
+.RE
+.sp .5
+..
diff --git a/vendor/x11iraf/obm/Tcl/doc/open.n b/vendor/x11iraf/obm/Tcl/doc/open.n
new file mode 100644
index 00000000..8bd39ae1
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/open.n
@@ -0,0 +1,138 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/open.n,v 1.1 93/05/10 17:10:32 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS open tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+open \- Open a file
+.SH SYNOPSIS
+.VS
+\fBopen \fIfileName\fR ?\fIaccess\fR? ?\fIpermissions\fR?
+.VE
+.BE
+
+.SH DESCRIPTION
+.PP
+This command opens a file and returns an identifier
+that may be used in future invocations
+of commands like \fBread\fR, \fBputs\fR, and \fBclose\fR.
+\fIFileName\fR gives the name of the file to open; if it starts with
+a tilde then tilde substitution is performed as described for
+\fBTcl_TildeSubst\fR.
+If the first character of \fIfileName\fR is ``|'' then the
+remaining characters of \fIfileName\fR are treated as a command
+pipeline to invoke, in the same style as for \fBexec\fR.
+In this case, the identifier returned by \fBopen\fR may be used
+to write to the command's input pipe or read from its output pipe.
+.PP
+The \fIaccess\fR argument indicates the way in which the file
+(or command pipeline) is to be accessed.
+.VS
+It may take two forms, either a string in the form that would be
+passed to the \fBfopen\fR library procedure or a list of POSIX
+access flags.
+It defaults to ``\fBr\fR''.
+In the first form \fIaccess\fR may have any of the following values:
+.VE
+.TP 15
+\fBr\fR
+Open the file for reading only; the file must already exist.
+.TP 15
+\fBr+\fR
+Open the file for both reading and writing; the file must
+already exist.
+.TP 15
+\fBw\fR
+Open the file for writing only. Truncate it if it exists. If it doesn't
+exist, create a new file.
+.TP 15
+\fBw+\fR
+Open the file for reading and writing. Truncate it if it exists.
+If it doesn't exist, create a new file.
+.TP 15
+\fBa\fR
+Open the file for writing only. The file must already exist, and the file
+is positioned so that new data is appended to the file.
+.TP 15
+\fBa+\fR
+Open the file for reading and writing. If the file doesn't exist,
+create a new empty file.
+Set the initial access position to the end of the file.
+.PP
+In the second form, \fIaccess\fR consists of a list of any of the
+.VS
+following flags, all of which have the standard POSIX meanings.
+One of the flags must be either \fBRDONLY\fR, \fBWRONLY\fR or \fBRDWR\fR.
+.TP 15
+\fBRDONLY\fR
+Open the file for reading only.
+.TP 15
+\fBWRONLY\fR
+Open the file for writing only.
+.TP 15
+\fBRDWR\fR
+Open the file for both reading and writing.
+.TP 15
+\fBAPPEND\fR
+Set the file pointer to the end of the file prior to each write.
+.TP 15
+\fBCREAT\fR
+Create the file if it doesn't already exist (without this flag it
+is an error for the file not to exist).
+.TP 15
+\fBEXCL\fR
+If \fBCREAT\fR is specified also, an error is returned if the
+file already exists.
+.TP 15
+\fBNOCTTY\fR
+If the file is a terminal device, this flag prevents the file from
+becoming the controlling terminal of the process.
+.TP 15
+\fBNONBLOCK\fR
+Prevents the process from blocking while opening the file.
+For details refer to your system documentation on the \fBopen\fR system
+call's \fBO_NONBLOCK\fR flag.
+.TP 15
+\fBTRUNC\fR
+If the file exists it is truncated to zero length.
+.PP
+If a new file is created as part of opening it, \fIpermissions\fR
+(an integer) is used to set the permissions for the new file in
+conjunction with the process's file mode creation mask.
+\fIPermissions\fR defaults to 0666.
+.VE
+.PP
+If a file is opened for both reading and writing then \fBseek\fR
+must be invoked between a read and a write, or vice versa (this
+restriction does not apply to command pipelines opened with \fBopen\fR).
+When \fIfileName\fR specifies a command pipeline and a write-only access
+is used, then standard output from the pipeline is directed to the
+current standard output unless overridden by the command.
+When \fIfileName\fR specifies a command pipeline and a read-only access
+is used, then standard input from the pipeline is taken from the
+current standard input unless overridden by the command.
+
+.SH KEYWORDS
+access mode, append, controlling terminal, create, file,
+non-blocking, open, permissions, pipeline, process
diff --git a/vendor/x11iraf/obm/Tcl/doc/pid.n b/vendor/x11iraf/obm/Tcl/doc/pid.n
new file mode 100644
index 00000000..ff671c5d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/pid.n
@@ -0,0 +1,47 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/pid.n,v 1.1 93/05/15 16:19:40 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS pid tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+pid \- Retrieve process id(s)
+.SH SYNOPSIS
+\fBpid \fR?\fIfileId\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+If the \fIfileId\fR argument is given then it should normally
+refer to a process pipeline created with the \fBopen\fR command.
+In this case the \fBpid\fR command will return a list whose elements
+are the process identifiers of all the processes in the pipeline,
+in order.
+The list will be empty if \fIfileId\fR refers to an open file
+that isn't a process pipeline.
+If no \fIfileId\fR argument is given then \fBpid\fR returns the process
+identifier of the current process.
+All process identifiers are returned as decimal strings.
+
+.SH KEYWORDS
+file, pipeline, process identifier
diff --git a/vendor/x11iraf/obm/Tcl/doc/proc.n b/vendor/x11iraf/obm/Tcl/doc/proc.n
new file mode 100644
index 00000000..14061205
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/proc.n
@@ -0,0 +1,80 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/proc.n,v 1.1 93/05/10 17:10:18 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS proc tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+proc \- Create a Tcl procedure
+.SH SYNOPSIS
+\fBproc \fIname args body\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fBproc\fR command creates a new Tcl procedure named
+\fIname\fR, replacing
+any existing command or procedure there may have been by that name.
+Whenever the new command is invoked, the contents of \fIbody\fR will
+be executed by the Tcl interpreter.
+\fIArgs\fR specifies the formal arguments to the
+procedure. It consists of a list, possibly empty, each of whose
+elements specifies
+one argument. Each argument specifier is also a list with either
+one or two fields. If there is only a single field in the specifier
+then it is the name of the argument; if there are two fields, then
+the first is the argument name and the second is its default value.
+.PP
+When \fIname\fR is invoked a local variable
+will be created for each of the formal arguments to the procedure; its
+value will be the value of corresponding argument in the invoking command
+or the argument's default value.
+Arguments with default values need not be
+specified in a procedure invocation. However, there must be enough
+actual arguments for all the
+formal arguments that don't have defaults, and there must not be any extra
+actual arguments. There is one special case to permit procedures with
+variable numbers of arguments. If the last formal argument has the name
+\fBargs\fR, then a call to the procedure may contain more actual arguments
+than the procedure has formals. In this case, all of the actual arguments
+starting at the one that would be assigned to \fBargs\fR are combined into
+a list (as if the \fBlist\fR command had been used); this combined value
+is assigned to the local variable \fBargs\fR.
+.PP
+When \fIbody\fR is being executed, variable names normally refer to
+local variables, which are created automatically when referenced and
+deleted when the procedure returns. One local variable is automatically
+created for each of the procedure's arguments.
+Global variables can only be accessed by invoking
+the \fBglobal\fR command or the \fBupvar\fR command.
+.PP
+The \fBproc\fR command returns an empty string. When a procedure is
+invoked, the procedure's return value is the value specified in a
+\fBreturn\fR command. If the procedure doesn't execute an explicit
+\fBreturn\fR, then its return value is the value of the last command
+executed in the procedure's body.
+If an error occurs while executing the procedure
+body, then the procedure-as-a-whole will return that same error.
+
+.SH KEYWORDS
+argument, procedure
diff --git a/vendor/x11iraf/obm/Tcl/doc/puts.n b/vendor/x11iraf/obm/Tcl/doc/puts.n
new file mode 100644
index 00000000..294d4172
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/puts.n
@@ -0,0 +1,50 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/puts.n,v 1.1 93/05/10 17:10:19 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS puts tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+puts \- Write to a file
+.SH SYNOPSIS
+\fBputs \fR?\fB\-nonewline\fR? ?\fIfileId\fR? \fIstring\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Writes the characters given by \fIstring\fR to the file given
+by \fIfileId\fR.
+\fIFileId\fR must have been the return
+value from a previous call to \fBopen\fR, or it may be
+\fBstdout\fR or \fBstderr\fR to refer to one of the standard I/O
+channels; it must refer to a file that was opened for
+writing.
+If no \fIfileId\fR is specified then it defaults to \fBstdout\fR.
+\fBPuts\fR normally outputs a newline character after \fIstring\fR,
+but this feature may be suppressed by specifying the \fB\-nonewline\fR
+switch.
+Output to files is buffered internally by Tcl; the \fBflush\fR
+command may be used to force buffered characters to be output.
+
+.SH KEYWORDS
+file, newline, output, write
diff --git a/vendor/x11iraf/obm/Tcl/doc/pwd.n b/vendor/x11iraf/obm/Tcl/doc/pwd.n
new file mode 100644
index 00000000..b4eb5575
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/pwd.n
@@ -0,0 +1,38 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/pwd.n,v 1.1 93/05/10 17:10:19 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS pwd tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+pwd \- Return the current working directory
+.SH SYNOPSIS
+\fBpwd\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns the path name of the current working directory.
+
+.SH KEYWORDS
+working directory
diff --git a/vendor/x11iraf/obm/Tcl/doc/read.n b/vendor/x11iraf/obm/Tcl/doc/read.n
new file mode 100644
index 00000000..3507e0e2
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/read.n
@@ -0,0 +1,54 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/read.n,v 1.2 93/10/04 16:01:04 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS read tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+read \- Read from a file
+.SH SYNOPSIS
+\fBread \fR?\fB\-nonewline\fR? \fIfileId\fR
+.br
+\fBread \fIfileId numBytes\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+In the first form, all of the remaining bytes are read from the file
+given by \fIfileId\fR; they are returned as the result of the command.
+If the \fB\-nonewline\fR switch is specified then the last
+character of the file is discarded if it is a newline.
+In the second form, the extra argument specifies how many bytes to read;
+exactly this many bytes will be read and returned, unless there are fewer than
+\fInumBytes\fR bytes left in the file; in this case, all the remaining
+bytes are returned.
+\fIFileId\fR must be \fBstdin\fR or the return
+value from a previous call to \fBopen\fR; it must
+refer to a file that was opened for reading.
+.VS
+Any existing end-of-file or error condition on the file is cleared at
+the beginning of the \fBread\fR command.
+.VE
+
+.SH KEYWORDS
+file, read
diff --git a/vendor/x11iraf/obm/Tcl/doc/regexp.n b/vendor/x11iraf/obm/Tcl/doc/regexp.n
new file mode 100644
index 00000000..b3a5d71f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/regexp.n
@@ -0,0 +1,160 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/regexp.n,v 1.4 93/08/03 16:37:28 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS regexp tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+regexp \- Match a regular expression against a string
+.SH SYNOPSIS
+\fBregexp \fR?\fIswitches\fR? \fIexp string \fR?\fImatchVar\fR? ?\fIsubMatchVar subMatchVar ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Determines whether the regular expression \fIexp\fR matches part or
+all of \fIstring\fR and returns 1 if it does, 0 if it doesn't.
+.LP
+If additional arguments are specified after \fIstring\fR then they
+are treated as the names of variables in which to return
+information about which part(s) of \fIstring\fR matched \fIexp\fR.
+\fIMatchVar\fR will be set to the range of \fIstring\fR that
+matched all of \fIexp\fR. The first \fIsubMatchVar\fR will contain
+the characters in \fIstring\fR that matched the leftmost parenthesized
+subexpression within \fIexp\fR, the next \fIsubMatchVar\fR will
+contain the characters that matched the next parenthesized
+subexpression to the right in \fIexp\fR, and so on.
+.LP
+If the initial arguments to \fBregexp\fR start with \fB\-\fR then
+.VS
+they are treated as switches. The following switches are
+currently supported:
+.TP 10
+\fB\-nocase\fR
+Causes upper-case characters in \fIstring\fR to be treated as
+lower case during the matching process.
+.TP 10
+\fB\-indices\fR
+Changes what is stored in the \fIsubMatchVar\fRs.
+Instead of storing the matching characters from \fBstring\fR,
+each variable
+will contain a list of two decimal strings giving the indices
+in \fIstring\fR of the first and last characters in the matching
+range of characters.
+.TP 10
+\fB\-\|\-\fR
+Marks the end of switches. The argument following this one will
+be treated as \fIexp\fR even if it starts with a \fB\-.
+.VE
+.LP
+If there are more \fIsubMatchVar\fR's than parenthesized
+subexpressions within \fIexp\fR, or if a particular subexpression
+in \fIexp\fR doesn't match the string (e.g. because it was in a
+portion of the expression that wasn't matched), then the corresponding
+\fIsubMatchVar\fR will be set to ``\fB\-1 \-1\fR'' if \fB\-indices\fR
+has been specified or to an empty string otherwise.
+
+.SH "REGULAR EXPRESSIONS"
+.PP
+Regular expressions are implemented using Henry Spencer's package
+(thanks, Henry!),
+and much of the description of regular expressions below is copied verbatim
+from his manual entry.
+.PP
+A regular expression is zero or more \fIbranches\fR, separated by ``|''.
+It matches anything that matches one of the branches.
+.PP
+A branch is zero or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed by ``*'', ``+'', or ``?''.
+An atom followed by ``*'' matches a sequence of 0 or more matches of the atom.
+An atom followed by ``+'' matches a sequence of 1 or more matches of the atom.
+An atom followed by ``?'' matches a match of the atom, or the null string.
+.PP
+An atom is a regular expression in parentheses (matching a match for the
+regular expression), a \fIrange\fR (see below), ``.''
+(matching any single character), ``^'' (matching the null string at the
+beginning of the input string), ``$'' (matching the null string at the
+end of the input string), a ``\e'' followed by a single character (matching
+that character), or a single character with no other significance
+(matching that character).
+.PP
+A \fIrange\fR is a sequence of characters enclosed in ``[]''.
+It normally matches any single character from the sequence.
+If the sequence begins with ``^'',
+it matches any single character \fInot\fR from the rest of the sequence.
+If two characters in the sequence are separated by ``\-'', this is shorthand
+for the full list of ASCII characters between them
+(e.g. ``[0-9]'' matches any decimal digit).
+To include a literal ``]'' in the sequence, make it the first character
+(following a possible ``^'').
+To include a literal ``\-'', make it the first or last character.
+
+.SH "CHOOSING AMONG ALTERNATIVE MATCHES"
+.PP
+In general there may be more than one way to match a regular expression
+to an input string. For example, consider the command
+.DS
+\fBregexp (a*)b* aabaaabb x y
+.DE
+Considering only the rules given so far, \fBx\fR and \fBy\fR could
+end up with the values \fBaabb\fR and \fBaa\fR, \fBaaab\fR and \fBaaa\fR,
+\fBab\fR and \fBa\fR, or any of several other combinations.
+To resolve this potential ambiguity \fBregexp\fR chooses among
+alternatives using the rule ``first then longest''.
+In other words, it consders the possible matches in order working
+from left to right across the input string and the pattern, and it
+attempts to match longer pieces of the input string before shorter
+ones. More specifically, the following rules apply in decreasing
+order of priority:
+.IP [1]
+If a regular expression could match two different parts of an input string
+then it will match the one that begins earliest.
+.IP [2]
+If a regular expression contains \fB|\fR operators then the leftmost
+matching sub-expression is chosen.
+.IP [3]
+In \fB*\fR, \fB+\fR, and \fB?\fR constructs, longer matches are chosen
+in preference to shorter ones.
+.IP [4]
+In sequences of expression components the components are considered
+from left to right.
+.LP
+In the example from above, \fB(a*)b*\fR matches \fBaab\fR: the \fB(a*)\fR
+portion of the pattern is matched first and it consumes the leading
+\fBaa\fR; then the \fBb*\fR portion of the pattern consumes the
+next \fBb\fR. Or, consider the following example:
+.DS
+\fBregexp (ab|a)(b*)c abc x y z
+.DE
+After this command \fBx\fR will be \fBabc\fR, \fBy\fR will be
+\fBab\fR, and \fBz\fR will be an empty string.
+Rule 4 specifies that \fB(ab|a)\fR gets first shot at the input
+string and Rule 2 specifies that the \fBab\fR sub-expression
+is checked before the \fBa\fR sub-expression.
+Thus the \fBb\fR has already been claimed before the \fB(b*)\fR
+component is checked and \fB(b*)\fR must match an empty string.
+
+.SH KEYWORDS
+match, regular expression, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/regsub.n b/vendor/x11iraf/obm/Tcl/doc/regsub.n
new file mode 100644
index 00000000..0a3e704c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/regsub.n
@@ -0,0 +1,88 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/regsub.n,v 1.2 93/06/17 13:31:43 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS regsub tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+regsub \- Perform substitutions based on regular expression pattern matching
+.SH SYNOPSIS
+\fBregsub \fR?\fIswitches\fR? \fIexp string subSpec varName\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+This command matches the regular expression \fIexp\fR against
+\fIstring\fR,
+.VS
+and it copies \fIstring\fR to the variable whose name is
+given by \fIvarName\fR.
+The command returns 1 if there is a match and 0 if there isn't.
+If there is a match, then while copying \fIstring\fR to \fIvarName\fR
+the portion of \fIstring\fR that
+.VE
+matched \fIexp\fR is replaced with \fIsubSpec\fR.
+If \fIsubSpec\fR contains a ``&'' or ``\e0'', then it is replaced
+in the substitution with the portion of \fIstring\fR that
+matched \fIexp\fR.
+If \fIsubSpec\fR contains a ``\e\fIn\fR'', where \fIn\fR is a digit
+between 1 and 9, then it is replaced in the substitution with
+the portion of \fIstring\fR that matched the \fIn\fR-th
+parenthesized subexpression of \fIexp\fR.
+Additional backslashes may be used in \fIsubSpec\fR to prevent special
+interpretation of ``&'' or ``\e0'' or ``\e\fIn\fR'' or
+backslash.
+The use of backslashes in \fIsubSpec\fR tends to interact badly
+with the Tcl parser's use of backslashes, so it's generally
+safest to enclose \fIsubSpec\fR in braces if it includes
+backslashes.
+.LP
+If the initial arguments to \fBregexp\fR start with \fB\-\fR then
+.VS
+they are treated as switches. The following switches are
+currently supported:
+.TP 10
+\fB\-all\fR
+All ranges in \fIstring\fR that match \fIexp\fR are found and
+substitution is performed for each of these ranges.
+Without this switch only the first
+matching range is found and substituted.
+If \fB\-all\fR is specified, then ``&'' and ``\e\fIn\fR''
+sequences are handled for each substitution using the information
+from the corresponding match.
+.TP 10
+\fB\-nocase\fR
+Upper-case characters in \fIstring\fR will be converted to lower-case
+before matching against \fIexp\fR; however, substitutions specified
+by \fIsubSpec\fR use the original unconverted form of \fIstring\fR.
+.TP 10
+\fB\-\|\-\fR
+Marks the end of switches. The argument following this one will
+be treated as \fIexp\fR even if it starts with a \fB\-.
+.VE
+.PP
+See the manual entry for \fBregexp\fR for details on the interpretation
+of regular expressions.
+
+.SH KEYWORDS
+match, pattern, regular expression, substitute
diff --git a/vendor/x11iraf/obm/Tcl/doc/rename.n b/vendor/x11iraf/obm/Tcl/doc/rename.n
new file mode 100644
index 00000000..490f52b0
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/rename.n
@@ -0,0 +1,41 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/rename.n,v 1.1 93/06/07 16:48:22 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS rename tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+rename \- Rename or delete a command
+.SH SYNOPSIS
+\fBrename \fIoldName newName\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Rename the command that used to be called \fIoldName\fR so that it
+is now called \fInewName\fR. If \fInewName\fR is an empty string
+then \fIoldName\fR is deleted. The \fBrename\fR command
+returns an empty string as result.
+
+.SH KEYWORDS
+command, delete, rename
diff --git a/vendor/x11iraf/obm/Tcl/doc/return.n b/vendor/x11iraf/obm/Tcl/doc/return.n
new file mode 100644
index 00000000..cb80b61d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/return.n
@@ -0,0 +1,104 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/return.n,v 1.8 93/08/03 16:15:41 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS return tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+return \- Return from a procedure
+.SH SYNOPSIS
+\fBreturn \fR?\fB\-code \fIcode\fR? ?\fB\-errorinfo \fIinfo\fR? ?\fB\-errorcode\fI code\fR? ?\fIstring\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Return immediately from the current procedure
+(or top-level command or \fBsource\fR command),
+with \fIstring\fR as the return value. If \fIstring\fR is not specified then
+an empty string will be returned as result.
+
+.SH "EXCEPTIONAL RETURNS"
+.PP
+In the usual case where the \fB\-code\fR option isn't
+.VS
+specified the procedure will return normally (its completion
+code will be TCL_OK).
+However, the \fB\-code\fR option may be used to generate an
+exceptional return from the procedure.
+\fICode\fR may have any of the following values:
+.TP 10
+\fBok\fR
+Normal return: same as if the option is omitted.
+.TP 10
+\fBerror\fR
+Error return: same as if the \fBerror\fR command were used to
+terminate the procedure, except for handling of \fBerrorInfo\fR
+and \fBerrorCode\fR variables (see below).
+.TP 10
+\fBreturn\fR
+The current procedure will return with a completion code of
+TCL_RETURN, so that the procedure that invoked it will return
+also.
+.TP 10
+\fBbreak\fR
+The current procedure will return with a completion code of
+TCL_BREAK, which will terminate the innermost nested loop in
+the code that invoked the current procedure.
+.TP 10
+\fBcontinue\fR
+The current procedure will return with a completion code of
+TCL_CONTINUE, which will terminate the current iteration of
+the innermost nested loop in the code that invoked the current
+procedure.
+.TP 10
+\fIvalue\fR
+\fIValue\fR must be an integer; it will be returned as the
+completion code for the current procedure.
+.LP
+The \fB\-code\fR option is rarely used.
+It is provided so that procedures that implement
+new control structures can reflect exceptional conditions back to
+their callers.
+.PP
+Two additional options, \fB\-errorinfo\fR and \fB\-errorcode\fR,
+may be used to provide additional information during error
+returns.
+These options are ignored unless \fIcode\fR is \fBerror\fR.
+.PP
+The \fB\-errorinfo\fR option specifies an initial stack
+trace for the \fBerrorInfo\fR variable; if it is not specified then
+the stack trace left in \fBerrorInfo\fR will include the call to
+the procedure and higher levels on the stack but it will not include
+any information about the context of the error within the procedure.
+Typically the \fIinfo\fR value is supplied from the value left
+in \fBerrorInfo\fR after a \fBcatch\fR command trapped an error within
+the procedure.
+.PP
+If the \fB\-errorcode\fR option is specified then \fIcode\fR provides
+a value for the \fBerrorCode\fR variable.
+If the option is not specified then \fBerrorCode\fR will
+default to \fBNONE\fR.
+.VE
+
+.SH KEYWORDS
+break, continue, error, procedure, return
diff --git a/vendor/x11iraf/obm/Tcl/doc/scan.n b/vendor/x11iraf/obm/Tcl/doc/scan.n
new file mode 100644
index 00000000..b2b15209
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/scan.n
@@ -0,0 +1,149 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/scan.n,v 1.3 93/08/04 17:18:42 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS scan tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+scan \- Parse string using conversion specifiers in the style of sscanf
+.SH SYNOPSIS
+\fBscan \fIstring format varName \fR?\fIvarName ...\fR?
+.BE
+
+.SH INTRODUCTION
+.PP
+This command parses fields from an input string in the same fashion
+as the ANSI C \fBsscanf\fR procedure and returns a count of the number
+of fields sucessfully parsed.
+\fIString\fR gives the input to be parsed and \fIformat\fR indicates
+how to parse it, using \fB%\fR conversion specifiers as in \fBsscanf\fR.
+Each \fIvarName\fR gives the name of a variable; when a field is
+scanned from \fIstring\fR the result is converted back into a string
+and assigned to the corresponding variable.
+
+.SH "DETAILS ON SCANNING"
+.PP
+\fBScan\fR operates by scanning \fIstring\fR and \fIformatString\fR together.
+If the next character in \fIformatString\fR is a blank or tab then it
+is ignored.
+Otherwise, if it isn't a \fB%\fR character then it
+must match the next non-white-space character of \fIstring\fR.
+When a \fB%\fR is encountered in \fIformatString\fR, it indicates
+the start of a conversion specifier.
+A conversion specifier contains three fields after the \fB%\fR:
+a \fB*\fR, which indicates that the converted value is to be discarded
+instead of assigned to a variable; a number indicating a maximum field
+width; and a conversion character.
+All of these fields are optional except for the conversion character.
+.PP
+When \fBscan\fR finds a conversion specifier in \fIformatString\fR, it
+first skips any white-space characters in \fIstring\fR.
+Then it converts the next input characters according to the
+conversion specifier and stores the result in the variable given
+by the next argument to \fBscan\fR.
+The following conversion characters are supported:
+.TP 10
+\fBd\fR
+The input field must be a decimal integer.
+It is read in and the value is stored in the variable as a decimal string.
+.TP 10
+\fBo\fR
+The input field must be an octal integer. It is read in and the
+value is stored in the variable as a decimal string.
+.TP 10
+\fBx\fR
+The input field must be a hexadecimal integer. It is read in
+and the value is stored in the variable as a decimal string.
+.TP 10
+\fBc\fR
+A single character is read in and its binary value is stored in
+the variable as a decimal string.
+Initial white space is not skipped in this case, so the input
+field may be a white-space character.
+This conversion is different from the ANSI standard in that the
+input field always consists of a single character and no field
+width may be specified.
+.TP 10
+\fBs\fR
+The input field consists of all the characters up to the next
+white-space character; the characters are copied to the variable.
+.TP 10
+\fBe\fR or \fBf\fR or \fBg\fR
+The input field must be a floating-point number consisting
+of an optional sign, a string of decimal digits possibly con
+taining a decimal point, and an optional exponent consisting
+of an \fBe\fR or \fBE\fR followed by an optional sign and a string of
+decimal digits.
+It is read in and stored in the variable as a floating-point string.
+.TP 10
+\fB[\fIchars\fB]
+The input field consists of any number of characters in
+\fIchars\fR.
+The matching string is stored in the variable.
+If the first character between the brackets is a \fB]\fR then
+it is treated as part of \fIchars\fR rather than the closing
+bracket for the set.
+.TP 10
+\fB[^\fIchars\fB]
+The input field consists of any number of characters not in
+\fIchars\fR.
+The matching string is stored in the variable.
+If the character immediately following the \fB^\fR is a \fB]\fR then it is
+treated as part of the set rather than the closing bracket for
+the set.
+.LP
+The number of characters read from the input for a conversion is the
+largest number that makes sense for that particular conversion (e.g.
+as many decimal digits as possible for \fB%d\fR, as
+many octal digits as possible for \fB%o\fR, and so on).
+The input field for a given conversion terminates either when a
+white-space character is encountered or when the maximum field
+width has been reached, whichever comes first.
+If a \fB*\fR is present in the conversion specifier
+then no variable is assigned and the next scan argument is not consumed.
+
+.SH "DIFFERENCES FROM ANSI SSCANF"
+.PP
+The behavior of the \fBscan\fR command is the same as the behavior of
+the ANSI C \fBsscanf\fR procedure except for the following differences:
+.IP [1]
+.VS
+\fB%p\fR and \fB%n\fR conversion specifiers are not currently
+supported.
+.VE
+.IP [2]
+For \fB%c\fR conversions a single character value is
+converted to a decimal string, which is then assigned to the
+corresponding \fIvarName\fR;
+no field width may be specified for this conversion.
+.IP [3]
+.VS
+The \fBl\fR, \fBh\fR, and \fBL\fR modifiers are ignored; integer
+values are always converted as if there were no modifier present
+and real values are always converted as if the \fBl\fR modifier
+were present (i.e. type \fBdouble\fR is used for the internal
+representation).
+.VE
+
+.SH KEYWORDS
+conversion specifier, parse, scan
diff --git a/vendor/x11iraf/obm/Tcl/doc/seek.n b/vendor/x11iraf/obm/Tcl/doc/seek.n
new file mode 100644
index 00000000..832d8a65
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/seek.n
@@ -0,0 +1,64 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/seek.n,v 1.1 93/06/07 16:48:27 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS seek tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+seek \- Change the access position for an open file
+.SH SYNOPSIS
+\fBseek \fIfileId offset \fR?\fIorigin\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Change the current access position for \fIfileId\fR.
+\fIFileId\fR must have been the return
+value from a previous call to \fBopen\fR, or it may be \fBstdin\fR,
+\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O
+channels.
+The \fIoffset\fR and \fIorigin\fR arguments specify the position at
+which the next read or write will occur for \fIfileId\fR.
+\fIOffset\fR must be an integer (which may be negative) and \fIorigin\fR
+must be one of the following:
+.TP
+\fBstart\fR
+The new access position will be \fIoffset\fR bytes from the start
+of the file.
+.TP
+\fBcurrent\fR
+The new access position will be \fIoffset\fR bytes from the current
+access position; a negative \fIoffset\fR moves the access position
+backwards in the file.
+.TP
+\fBend\fR
+The new access position will be \fIoffset\fR bytes from the end of
+the file. A negative \fIoffset\fR places the access position before
+the end-of-file, and a positive \fIoffset\fR places the access position
+after the end-of-file.
+.LP
+The \fIorigin\fR argument defaults to \fBstart\fR.
+This command returns an empty string.
+
+.SH KEYWORDS
+access position, file, seek
diff --git a/vendor/x11iraf/obm/Tcl/doc/set.n b/vendor/x11iraf/obm/Tcl/doc/set.n
new file mode 100644
index 00000000..1fda124e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/set.n
@@ -0,0 +1,51 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/set.n,v 1.1 93/06/07 16:48:27 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS set tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+set \- Read and write variables
+.SH SYNOPSIS
+\fBset \fIvarName \fR?\fIvalue\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns the value of variable \fIvarName\fR.
+If \fIvalue\fR is specified, then set
+the value of \fIvarName\fR to \fIvalue\fR, creating a new variable
+if one doesn't already exist, and return its value.
+If \fIvarName\fR contains an open parenthesis and ends with a
+close parenthesis, then it refers to an array element: the characters
+before the first open parenthesis are the name of the array, and the characters
+between the parentheses are the index within the array.
+Otherwise \fIvarName\fR refers to a scalar variable.
+If no procedure is active, then \fIvarName\fR refers to a global
+variable.
+If a procedure is active, then \fIvarName\fR refers to a parameter
+or local variable of the procedure unless the \fIglobal\fR command
+has been invoked to declare \fIvarName\fR to be global.
+
+.SH KEYWORDS
+read, write, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/source.n b/vendor/x11iraf/obm/Tcl/doc/source.n
new file mode 100644
index 00000000..124d8049
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/source.n
@@ -0,0 +1,47 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/source.n,v 1.1 93/06/07 16:48:28 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS source tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+source \- Evaluate a file as a Tcl script
+.SH SYNOPSIS
+\fBsource \fIfileName\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Read file \fIfileName\fR and pass the contents to the Tcl interpreter
+as a script to evaluate in the normal fashion. The return
+value from \fBsource\fR is the return value of the last command executed
+from the file. If an error occurs in evaluating the contents of the
+file then the \fBsource\fR command will return that error.
+If a \fBreturn\fR command is invoked from within the file then the remainder of
+the file will be skipped and the \fBsource\fR command will return
+normally with the result from the \fBreturn\fR command.
+If \fIfileName\fR starts with a tilde, then it is tilde-substituted
+as described in the \fBTcl_TildeSubst\fR manual entry.
+
+.SH KEYWORDS
+file, script
diff --git a/vendor/x11iraf/obm/Tcl/doc/split.n b/vendor/x11iraf/obm/Tcl/doc/split.n
new file mode 100644
index 00000000..cd1f1dc3
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/split.n
@@ -0,0 +1,57 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/split.n,v 1.1 93/06/16 16:48:25 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS split tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+split \- Split a string into a proper Tcl list
+.SH SYNOPSIS
+\fBsplit \fIstring \fR?\fIsplitChars\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns a list created by splitting \fIstring\fR at each character
+that is in the \fIsplitChars\fR argument.
+Each element of the result list will consist of the
+characters from \fIstring\fR that lie between instances of the
+characters in \fIsplitChars\fR.
+Empty list elements will be generated if \fIstring\fR contains
+adjacent characters in \fIsplitChars\fR, or if the first or last
+character of \fIstring\fR is in \fIsplitChars\fR.
+If \fIsplitChars\fR is an empty string then each character of
+\fIstring\fR becomes a separate element of the result list.
+\fISplitChars\fR defaults to the standard white-space characters.
+For example,
+.DS
+\fBsplit "comp.unix.misc" .\fR
+.DE
+returns \fB"comp unix misc"\fR and
+.DS
+\fBsplit "Hello world" {}\fR
+.DE
+returns \fB"H e l l o { } w o r l d"\fR.
+
+.SH KEYWORDS
+list, split, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/string.n b/vendor/x11iraf/obm/Tcl/doc/string.n
new file mode 100644
index 00000000..defd385a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/string.n
@@ -0,0 +1,131 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/string.n,v 1.1 93/06/16 16:48:24 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS string tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+string \- Manipulate strings
+.SH SYNOPSIS
+\fBstring \fIoption arg \fR?\fIarg ...?\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Performs one of several string operations, depending on \fIoption\fR.
+The legal \fIoption\fRs (which may be abbreviated) are:
+.TP
+\fBstring compare \fIstring1 string2\fR
+Perform a character-by-character comparison of strings \fIstring1\fR and
+\fIstring2\fR in the same way as the C \fBstrcmp\fR procedure. Return
+\-1, 0, or 1, depending on whether \fIstring1\fR is lexicographically
+less than, equal to, or greater than \fIstring2\fR.
+.TP
+\fBstring first \fIstring1 string2\fR
+Search \fIstring2\fR for a sequence of characters that exactly match
+the characters in \fIstring1\fR. If found, return the index of the
+first character in the first such match within \fIstring2\fR. If not
+found, return \-1.
+.TP
+\fBstring index \fIstring charIndex\fR
+Returns the \fIcharIndex\fR'th character of the \fIstring\fR
+argument. A \fIcharIndex\fR of 0 corresponds to the first
+character of the string.
+If \fIcharIndex\fR is less than 0 or greater than
+or equal to the length of the string then an empty string is
+returned.
+.TP
+\fBstring last \fIstring1 string2\fR
+Search \fIstring2\fR for a sequence of characters that exactly match
+the characters in \fIstring1\fR. If found, return the index of the
+first character in the last such match within \fIstring2\fR. If there
+is no match, then return \-1.
+.TP
+\fBstring length \fIstring\fR
+Returns a decimal string giving the number of characters in \fIstring\fR.
+.TP
+\fBstring match \fIpattern\fR \fIstring\fR
+See if \fIpattern\fR matches \fIstring\fR; return 1 if it does, 0
+if it doesn't. Matching is done in a fashion similar to that
+used by the C-shell. For the two strings to match, their contents
+must be identical except that the following special sequences
+may appear in \fIpattern\fR:
+.RS
+.IP \fB*\fR 10
+Matches any sequence of characters in \fIstring\fR,
+including a null string.
+.IP \fB?\fR 10
+Matches any single character in \fIstring\fR.
+.IP \fB[\fIchars\fB]\fR 10
+Matches any character in the set given by \fIchars\fR. If a sequence
+of the form
+\fIx\fB\-\fIy\fR appears in \fIchars\fR, then any character
+between \fIx\fR and \fIy\fR, inclusive, will match.
+.IP \fB\e\fIx\fR 10
+Matches the single character \fIx\fR. This provides a way of
+avoiding the special interpretation of the characters
+\fB*?[]\e\fR in \fIpattern\fR.
+.RE
+.TP
+\fBstring range \fIstring first last\fR
+Returns a range of consecutive characters from \fIstring\fR, starting
+with the character whose index is \fIfirst\fR and ending with the
+character whose index is \fIlast\fR. An index of 0 refers to the
+first character of the string. \fILast\fR may be \fBend\fR (or any
+abbreviation of it) to refer to the last character of the string.
+If \fIfirst\fR is less than zero then it is treated as if it were zero, and
+if \fIlast\fR is greater than or equal to the length of the string then
+it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than
+\fIlast\fR then an empty string is returned.
+.TP
+\fBstring tolower \fIstring\fR
+Returns a value equal to \fIstring\fR except that all upper case
+letters have been converted to lower case.
+.TP
+\fBstring toupper \fIstring\fR
+Returns a value equal to \fIstring\fR except that all lower case
+letters have been converted to upper case.
+.TP
+\fBstring trim \fIstring\fR ?\fIchars\fR?
+Returns a value equal to \fIstring\fR except that any leading
+or trailing characters from the set given by \fIchars\fR are
+removed.
+If \fIchars\fR is not specified then white space is removed
+(spaces, tabs, newlines, and carriage returns).
+.TP
+\fBstring trimleft \fIstring\fR ?\fIchars\fR?
+Returns a value equal to \fIstring\fR except that any
+leading characters from the set given by \fIchars\fR are
+removed.
+If \fIchars\fR is not specified then white space is removed
+(spaces, tabs, newlines, and carriage returns).
+.TP
+\fBstring trimright \fIstring\fR ?\fIchars\fR?
+Returns a value equal to \fIstring\fR except that any
+trailing characters from the set given by \fIchars\fR are
+removed.
+If \fIchars\fR is not specified then white space is removed
+(spaces, tabs, newlines, and carriage returns).
+
+.SH KEYWORDS
+case conversion, compare, index, match, pattern, string
diff --git a/vendor/x11iraf/obm/Tcl/doc/switch.n b/vendor/x11iraf/obm/Tcl/doc/switch.n
new file mode 100644
index 00000000..a8a5d1d9
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/switch.n
@@ -0,0 +1,122 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/switch.n,v 1.2 93/06/17 13:31:26 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS switch tcl 7.0
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+switch \- Evaluate one of several scripts, depending on a given value
+.SH SYNOPSIS
+\fBswitch\fI \fR?\fIoptions\fR?\fI string \fIpattern body \fR?\fIpattern body \fR...?
+.br
+\fBswitch\fI \fR?\fIoptions\fR?\fI string \fR{\fIpattern body \fR?\fIpattern body \fR...?}
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fBswitch\fR command matches its \fIstring\fR argument against each of
+the \fIpattern\fR arguments in order.
+As soon as it finds a \fIpattern\fR that matches \fIstring\fR it
+evaluates the following \fIbody\fR argument by passing it recursively
+to the Tcl interpreter and returns the result of that evaluation.
+If the last \fIpattern\fR argument is \fBdefault\fR then it matches
+anything.
+If no \fIpattern\fR argument
+matches \fIstring\fR and no default is given, then the \fBswitch\fR
+command returns an empty string.
+.PP
+If the initial arguments to \fBswitch\fR start with \fB\-\fR then
+they are treated as options. The following options are
+currently supported:
+.TP 10
+\fB\-exact\fR
+Use exact matching when comparing \fIstring\fR to a pattern. This
+is the default.
+.TP 10
+\fB\-glob\fR
+When matching \fIstring\fR to the patterns, use glob-style matching
+(i.e. the same as implemented by the \fBstring match\fR command).
+.TP 10
+\fB\-regexp\fR
+When matching \fIstring\fR to the patterns, use regular
+expression matching
+(i.e. the same as implemented by the \fBregexp\fR command).
+.TP 10
+\fB\-\|\-\fR
+Marks the end of options. The argument following this one will
+be treated as \fIstring\fR even if it starts with a \fB\-.
+.PP
+Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
+The first uses a separate argument for each of the patterns and commands;
+this form is convenient if substitutions are desired on some of the
+patterns or commands.
+The second form places all of the patterns and commands together into
+a single argument; the argument must have proper list structure, with
+the elements of the list being the patterns and commands.
+The second form makes it easy to construct multi-line switch commands,
+since the braces around the whole list make it unnecessary to include a
+backslash at the end of each line.
+Since the \fIpattern\fR arguments are in braces in the second form,
+no command or variable substitutions are performed on them; this makes
+the behavior of the second form different than the first form in some
+cases.
+.PP
+If a \fIbody\fR is specified as ``\fB\-\fR'' it means that the \fIbody\fR
+for the next pattern should also be used as the body for this
+pattern (if the next pattern also has a body of ``\fB\-\fR''
+then the body after that is used, and so on).
+This feature makes it possible to share a single \fIbody\fR among
+several patterns.
+.PP
+Below are some examples of \fBswitch\fR commands:
+.DS
+\fBswitch\0abc\0a\0\-\0b\0{format 1}\0abc\0{format 2}\0default\0{format 3}
+.DE
+will return \fB2\fR,
+.DS
+.ta .5c 1c
+\fBswitch\0\-regexp\0aaab {
+ ^a.*b$\0\-
+ b\0{format 1}
+ a*\0{format 2}
+ default\0{format 3}
+}
+.DE
+will return \fB1\fR, and
+.DS
+.ta .5c 1c
+\fBswitch\0xyz {
+ a
+ \-
+ b
+ {format 1}
+ a*
+ {format 2}
+ default
+ {format 3}
+}
+.DE
+will return \fB3\fR.
+
+.SH KEYWORDS
+switch, match, regular expression
diff --git a/vendor/x11iraf/obm/Tcl/doc/tclsh.1 b/vendor/x11iraf/obm/Tcl/doc/tclsh.1
new file mode 100644
index 00000000..ba88be43
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/tclsh.1
@@ -0,0 +1,103 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/tclsh.1,v 1.4 93/08/26 15:06:04 ouster Exp $ SPRITE (Berkeley)
+'/"
+.so man.macros
+.HS tclsh tclcmds
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+tclsh \- Simple shell containing Tcl interpreter
+.SH SYNOPSIS
+\fBtclsh\fR ?\fIfileName arg arg ...\fR?\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+\fBTclsh\fR is a shell-like application that reads Tcl commands
+from its standard input or from a file and evaluates them.
+If invoked with no arguments then it runs interactively, reading
+Tcl commands from standard input and printing command results and
+error messages to standard output.
+It runs until the \fBexit\fR command is invoked or until it
+reaches end-of-file on its standard input.
+If there exists a file \fB.tclshrc\fR in the home directory of
+the user, \fBtclsh\fR evaluates the file as a Tcl script
+just before reading the first command from standard input.
+
+.SH "SCRIPT FILES"
+.PP
+If \fBtclsh\fR is invoked with arguments then the first argument
+is the name of a script file and any additional arguments
+are made available to the script as variables (see below).
+Instead of reading commands from standard input \fBtclsh\fR will
+read Tcl commands from the named file; \fBtclsh\fR will exit
+when it reaches the end of the file.
+There is no automatic evaluation of \fB.tclshrc\fR in this
+case, but the script file can always \fBsource\fR it if desired.
+.PP
+If you create a Tcl script in a file whose first line is
+.DS
+\fB#!/usr/local/bin/tclsh
+.DE
+then you can invoke the script file directly from your shell if
+you mark the file as executable.
+This assumes that \fBtclsh\fR has been installed in the default
+location in /usr/local/bin; if it's installed somewhere else
+then you'll have to modify the above line to match.
+
+.SH "VARIABLES"
+.PP
+\fBTclsh\fR sets the following Tcl variables:
+.TP 15
+\fBargc\fR
+Contains a count of the number of \fIarg\fR arguments (0 if none),
+not including the name of the script file.
+.TP 15
+\fBargv\fR
+Contains a Tcl list whose elements are the \fIarg\fR arguments,
+in order, or an empty string if there are no \fIarg\fR arguments.
+.TP 15
+\fBargv0\fR
+Contains \fIfileName\fR if it was specified.
+Otherwise, contains the name by which \fBtclsh\fR was invoked.
+.TP 15
+\fBtcl_interactive\fR
+Contains 1 if \fBtclsh\fR is running interactively (no
+\fIfileName\fR was specified and standard input is a terminal-like
+device), 0 otherwise.
+.LP
+
+.SH PROMPTS
+.PP
+When \fBtclsh\fR is invoked interactively it normally prompts for each
+command with ``\fB% \fR''. You can change the prompt by setting the
+variables \fBtcl_prompt1\fR and \fBtcl_prompt2\fR. If variable
+\fBtcl_prompt1\fR exists then it must consist of a Tcl script
+to output a prompt; instead of outputting a prompt \fBtclsh\fR
+will evaluate the script in \fBtcl_prompt1\fR.
+The variable \fBtcl_prompt2\fR is used in a similar way when
+a newline is typed but the current command isn't yet complete;
+if \fBtcl_prompt2\fR isn't set then no prompt is output for
+incomplete commands.
+
+.SH KEYWORDS
+argument, interpreter, prompt, script file, shell
diff --git a/vendor/x11iraf/obm/Tcl/doc/tclvars.n b/vendor/x11iraf/obm/Tcl/doc/tclvars.n
new file mode 100644
index 00000000..5b8c1e15
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/tclvars.n
@@ -0,0 +1,156 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/tclvars.n,v 1.1 93/06/16 16:52:49 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS tclvars tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+tclvars \- Variables used by Tcl
+.BE
+
+.SH DESCRIPTION
+.PP
+The following global variables are created and managed automatically
+by the Tcl library. Except where noted below, these variables should
+normally be treated as read-only by application-specific code and by users.
+.TP
+\fBenv\fR
+.br
+This variable is maintained by Tcl as an array
+whose elements are the environment variables for the process.
+Reading an element will return the value of the corresponding
+environment variable.
+Setting an element of the array will modify the corresponding
+environment variable or create a new one if it doesn't already
+exist.
+Unsetting an element of \fBenv\fR will remove the corresponding
+environment variable.
+Changes to the \fBenv\fR array will affect the environment
+passed to children by commands like \fBexec\fR.
+If the entire \fBenv\fR array is unset then Tcl will stop
+monitoring \fBenv\fR accesses and will not update environment
+variables.
+.TP
+\fBerrorCode\fR
+After an error has occurred, this variable will be set to hold
+additional information about the error in a form that is easy
+to process with programs.
+\fBerrorCode\fR consists of a Tcl list with one or more elements.
+The first element of the list identifies a general class of
+errors, and determines the format of the rest of the list.
+The following formats for \fBerrorCode\fR are used by the
+Tcl core; individual applications may define additional formats.
+.RS
+.TP
+\fBARITH\fI code msg\fR
+.VS
+This format is used when an arithmetic error occurs (e.g. an attempt
+to divide by zero in the \fBexpr\fR command).
+\fICode\fR identifies the precise error and \fImsg\fR provides a
+human-readable description of the error. \fICode\fR will be either
+DIVZERO (for an attempt to divide by zero),
+DOMAIN (if an argument is outside the domain of a function, such as acos(\-3)),
+IOVERFLOW (for integer overflow),
+OVERLFLOW (for a floating-point overflow),
+or UNKNOWN (if the cause of the error cannot be determined).
+.VE
+.TP
+\fBCHILDKILLED\fI pid sigName msg\fR
+This format is used when a child process has been killed because of
+a signal. The second element of \fBerrorCode\fR will be the
+process's identifier (in decimal).
+The third element will be the symbolic name of the signal that caused
+the process to terminate; it will be one of the names from the
+include file signal.h, such as \fBSIGPIPE\fR.
+The fourth element will be a short human-readable message
+describing the signal, such as ``write on pipe with no readers''
+for \fBSIGPIPE\fR.
+.TP
+\fBCHILDSTATUS\fI pid code\fR
+This format is used when a child process has exited with a non-zero
+exit status. The second element of \fBerrorCode\fR will be the
+process's identifier (in decimal) and the third element will be the exit
+code returned by the process (also in decimal).
+.TP
+\fBCHILDSUSP\fI pid sigName msg\fR
+This format is used when a child process has been suspended because
+of a signal.
+The second element of \fBerrorCode\fR will be the process's identifier,
+in decimal.
+The third element will be the symbolic name of the signal that caused
+the process to suspend; this will be one of the names from the
+include file signal.h, such as \fBSIGTTIN\fR.
+The fourth element will be a short human-readable message
+describing the signal, such as ``background tty read''
+for \fBSIGTTIN\fR.
+.TP
+\fBNONE\fR
+.br
+This format is used for errors where no additional information is
+available for an error besides the message returned with the
+error. In these cases \fBerrorCode\fR will consist of a list
+containing a single element whose contents are \fBNONE\fR.
+.TP
+\fBPOSIX \fIerrName msg\fR
+.VS
+If the first element of \fBerrorCode\fR is \fBPOSIX\fR, then
+the error occurred during a POSIX kernel call.
+.VE
+The second element of the list will contain the symbolic name
+of the error that occurred, such as \fBENOENT\fR; this will
+be one of the values defined in the include file errno.h.
+The third element of the list will be a human-readable
+message corresponding to \fIerrName\fR, such as
+``no such file or directory'' for the \fBENOENT\fR case.
+.PP
+To set \fBerrorCode\fR, applications should use library
+procedures such as \fBTcl_SetErrorCode\fR and
+.VS
+\fBTcl_PosixError\fR,
+.VE
+or they may invoke the \fBerror\fR command.
+If one of these methods hasn't been used, then the Tcl
+interpreter will reset the variable to \fBNONE\fR after
+the next error.
+.RE
+.TP
+\fBerrorInfo\fR
+After an error has occurred, this string will contain one or more lines
+identifying the Tcl commands and procedures that were being executed
+when the most recent error occurred.
+Its contents take the form of a stack trace showing the various
+nested Tcl commands that had been invoked at the time of the error.
+.TP
+\fBtcl_precision\fR
+.VS
+If this variable is set, it must contain a decimal number giving the
+number of significant digits to include when converting floating-point
+values to strings.
+If this variable is not set then 6 digits are included.
+17 digits is ``perfect'' for IEEE floating-point in that it allows
+double-precision values to be converted to strings and back to
+binary with no loss of precision.
+.VE
+
+.SH KEYWORDS
+arithmetic, error, environment, POSIX, precision, subprocess, variables
diff --git a/vendor/x11iraf/obm/Tcl/doc/tell.n b/vendor/x11iraf/obm/Tcl/doc/tell.n
new file mode 100644
index 00000000..24c3ff07
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/tell.n
@@ -0,0 +1,43 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/tell.n,v 1.1 93/06/16 16:48:30 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS tell tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+tell \- Return current access position for an open file
+.SH SYNOPSIS
+\fBtell \fIfileId\fR
+.BE
+
+.SH DESCRIPTION
+.PP
+Returns a decimal string giving the current access position in
+\fIfileId\fR.
+\fIFileId\fR must have been the return
+value from a previous call to \fBopen\fR, or it may be \fBstdin\fR,
+\fBstdout\fR, or \fBstderr\fR to refer to one of the standard I/O
+channels.
+
+.SH KEYWORDS
+access position, file
diff --git a/vendor/x11iraf/obm/Tcl/doc/time.n b/vendor/x11iraf/obm/Tcl/doc/time.n
new file mode 100644
index 00000000..dca3c3f6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/time.n
@@ -0,0 +1,46 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/time.n,v 1.1 93/06/16 16:48:29 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS time tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+time \- Time the execution of a script
+.SH SYNOPSIS
+\fBtime \fIscript\fR ?\fIcount\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command will call the Tcl interpreter \fIcount\fR
+times to evaluate \fIscript\fR (or once if \fIcount\fR isn't
+specified). It will then return a string of the form
+.DS
+\fB503 microseconds per iteration\fR
+.DE
+which indicates the average amount of time required per iteration,
+in microseconds.
+Time is measured in elapsed time, not CPU time.
+
+.SH KEYWORDS
+script, time
diff --git a/vendor/x11iraf/obm/Tcl/doc/trace.n b/vendor/x11iraf/obm/Tcl/doc/trace.n
new file mode 100644
index 00000000..7d8652e8
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/trace.n
@@ -0,0 +1,175 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/trace.n,v 1.3 93/06/16 16:36:39 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS trace tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+trace \- Monitor variable accesses
+.SH SYNOPSIS
+\fBtrace \fIoption\fR ?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command causes Tcl commands to be executed whenever certain operations are
+invoked. At present, only variable tracing is implemented. The
+legal \fIoption\fR's (which may be abbreviated) are:
+.TP
+\fBtrace variable \fIname ops command\fR
+Arrange for \fIcommand\fR to be executed whenever variable \fIname\fR
+is accessed in one of the ways given by \fIops\fR. \fIName\fR may
+refer to a normal variable, an element of an array, or to an array
+as a whole (i.e. \fIname\fR may be just the name of an array, with no
+parenthesized index). If \fIname\fR refers to a whole array, then
+\fIcommand\fR is invoked whenever any element of the array is
+manipulated.
+.RS
+.LP
+\fIOps\fR indicates which operations are of interest, and consists of
+one or more of the following letters:
+.RS
+.TP
+\fBr\fR
+Invoke \fIcommand\fR whenever the variable is read.
+.TP
+\fBw\fR
+Invoke \fIcommand\fR whenever the variable is written.
+.TP
+\fBu\fR
+Invoke \fIcommand\fR whenever the variable is unset. Variables
+can be unset explicitly with the \fBunset\fR command, or
+implicitly when procedures return (all of their local variables
+are unset). Variables are also unset when interpreters are
+deleted, but traces will not be invoked because there is no
+interpreter in which to execute them.
+.RE
+.LP
+When the trace triggers, three arguments are appended to
+\fIcommand\fR so that the actual command is as follows:
+.DS C
+\fIcommand name1 name2 op\fR
+.DE
+\fIName1\fR and \fIname2\fR give the name(s) for the variable
+being accessed: if the variable is a scalar then \fIname1\fR
+gives the variable's name and \fIname2\fR is an empty string;
+if the variable is an array element then \fIname1\fR gives the
+name of the array and name2 gives the index into the array;
+if an entire array is being deleted and the trace was registered
+on the overall array, rather than a single element, then \fIname1\fR
+gives the array name and \fIname2\fR is an empty string.
+\fIOp\fR indicates what operation is being performed on the
+variable, and is one of \fBr\fR, \fBw\fR, or \fBu\fR as
+defined above.
+.LP
+\fICommand\fR executes in the same context as the code that invoked
+the traced operation: if the variable was accessed as part of a
+Tcl procedure, then \fIcommand\fR will have access to the same
+local variables as code in the procedure. This context may be
+different than the context in which the trace was created.
+If \fIcommand\fR invokes a procedure (which it normally does) then
+the procedure will have to use \fBupvar\fR or \fBuplevel\fR if it
+wishes to access the traced variable.
+Note also that \fIname1\fR may not necessarily be the same as the name
+used to set the trace on the variable; differences can occur if
+the access is made through a variable defined with the \fBupvar\fR
+command.
+.LP
+For read and write traces, \fIcommand\fR can modify
+the variable to affect the result of the traced operation.
+If \fIcommand\fR modifies the value of a variable during a
+read or write trace, then the new value will be returned as the
+result of the traced operation.
+The return value from \fIcommand\fR is ignored except that
+if it returns an error of any sort then the traced operation
+also returns an error with
+.VS
+the same error message returned by the trace command
+.VE
+(this mechanism can be used to implement read-only variables, for
+example).
+For write traces, \fIcommand\fR is invoked after the variable's
+value has been changed; it can write a new value into the variable
+to override the original value specified in the write operation.
+To implement read-only variables, \fIcommand\fR will have to restore
+the old value of the variable.
+.LP
+While \fIcommand\fR is executing during a read or write trace, traces
+on the variable are temporarily disabled.
+This means that reads and writes invoked by
+\fIcommand\fR will occur directly, without invoking \fIcommand\fR
+(or any other traces) again.
+.VS
+However, if \fIcommand\fR unsets the variable then unset traces
+will be invoked.
+.VE
+.LP
+When an unset trace is invoked, the variable has already been
+deleted: it will appear to be undefined with no traces.
+If an unset occurs because of a procedure return, then the
+trace will be invoked in the variable context of the procedure
+being returned to: the stack frame of the returning procedure
+will no longer exist.
+Traces are not disabled during unset traces, so if an unset trace
+command creates a new trace and accesses the variable, the
+trace will be invoked.
+.VS
+Any errors in unset traces are ignored.
+.VE
+.LP
+If there are multiple traces on a variable they are invoked
+in order of creation, most-recent first.
+If one trace returns an error, then no further traces are
+invoked for the variable.
+If an array element has a trace set, and there is also a trace
+set on the array as a whole, the trace on the overall array
+is invoked before the one on the element.
+.LP
+Once created, the trace remains in effect either until the
+trace is removed with the \fBtrace vdelete\fR command described
+below, until the variable is unset, or until the interpreter
+is deleted.
+Unsetting an element of array will remove any traces on that
+element, but will not remove traces on the overall array.
+.LP
+This command returns an empty string.
+.RE
+.TP
+\fBtrace vdelete \fIname ops command\fR
+If there is a trace set on variable \fIname\fR with the
+operations and command given by \fIops\fR and \fIcommand\fR,
+then the trace is removed, so that \fIcommand\fR will never
+again be invoked.
+Returns an empty string.
+.TP
+\fBtrace vinfo \fIname\fR
+Returns a list containing one element for each trace
+currently set on variable \fIname\fR.
+Each element of the list is itself a list containing two
+elements, which are the \fIops\fR and \fIcommand\fR associated
+with the trace.
+If \fIname\fR doesn't exist or doesn't have any traces set, then
+the result of the command will be an empty string.
+
+.SH KEYWORDS
+read, variable, write, trace, unset
diff --git a/vendor/x11iraf/obm/Tcl/doc/unknown.n b/vendor/x11iraf/obm/Tcl/doc/unknown.n
new file mode 100644
index 00000000..7c257575
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/unknown.n
@@ -0,0 +1,55 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/unknown.n,v 1.2 93/10/13 17:19:06 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS unknown tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+unknown \- Handle attempts to use non-existent commands
+.SH SYNOPSIS
+\fBunknown \fIcmdName \fR?\fIarg arg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command doesn't actually exist as part of Tcl, but Tcl will
+invoke it if it does exist.
+If the Tcl interpreter encounters a command name for which there
+is not a defined command, then Tcl checks for the existence of
+a command named \fBunknown\fR.
+If there is no such command, then the interpreter returns an
+error.
+If the \fBunknown\fR command exists, then it is invoked with
+arguments consisting of the fully-substituted name and arguments
+for the original non-existent command.
+The \fBunknown\fR command typically does things like searching
+through library directories for a command procedure with the name
+\fIcmdName\fR, or expanding abbreviated command names to full-length,
+or automatically executing unknown commands as sub-processes.
+In some cases (such as expanding abbreviations) \fBunknown\fR will
+change the original command slightly and then (re-)execute it.
+The result of the \fBunknown\fR command is used as the result for
+the original non-existent command.
+
+.SH KEYWORDS
+error, non-existent command
diff --git a/vendor/x11iraf/obm/Tcl/doc/unset.n b/vendor/x11iraf/obm/Tcl/doc/unset.n
new file mode 100644
index 00000000..ed27582e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/unset.n
@@ -0,0 +1,47 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/unset.n,v 1.1 93/06/16 16:48:28 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS unset tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+unset \- Delete variables
+.SH SYNOPSIS
+\fBunset \fIname \fR?\fIname name ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command removes one or more variables.
+Each \fIname\fR is a variable name, specified in any of the
+ways acceptable to the \fBset\fR command.
+If a \fIname\fR refers to an element of an array then that
+element is removed without affecting the rest of the array.
+If a \fIname\fR consists of an array name with no parenthesized
+index, then the entire array is deleted.
+The \fBunset\fR command returns an empty string as result.
+An error occurs if any of the variables doesn't exist, and any variables
+after the non-existent one are not deleted.
+
+.SH KEYWORDS
+remove, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/uplevel.n b/vendor/x11iraf/obm/Tcl/doc/uplevel.n
new file mode 100644
index 00000000..d40e966e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/uplevel.n
@@ -0,0 +1,79 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/uplevel.n,v 1.1 93/06/16 16:48:27 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS uplevel tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+uplevel \- Execute a script in a different stack frame
+.SH SYNOPSIS
+\fBuplevel \fR?\fIlevel\fR?\fI arg \fR?\fIarg ...\fR?
+.BE
+
+.SH DESCRIPTION
+.PP
+All of the \fIarg\fR arguments are concatenated as if they had
+been passed to \fBconcat\fR; the result is then evaluated in the
+variable context indicated by \fIlevel\fR. \fBUplevel\fR returns
+the result of that evaluation.
+.PP
+If \fIlevel\fR is an integer then
+it gives a distance (up the procedure calling stack) to move before
+executing the command. If \fIlevel\fR consists of \fB#\fR followed by
+a number then the number gives an absolute level number. If \fIlevel\fR
+is omitted then it defaults to \fB1\fR. \fILevel\fR cannot be
+defaulted if the first \fIcommand\fR argument starts with a digit or \fB#\fR.
+.PP
+For example, suppose that procedure \fBa\fR was invoked
+from top-level, and that it called \fBb\fR, and that \fBb\fR called \fBc\fR.
+Suppose that \fBc\fR invokes the \fBuplevel\fR command. If \fIlevel\fR
+is \fB1\fR or \fB#2\fR or omitted, then the command will be executed
+in the variable context of \fBb\fR. If \fIlevel\fR is \fB2\fR or \fB#1\fR
+then the command will be executed in the variable context of \fBa\fR.
+If \fIlevel\fR is \fB3\fR or \fB#0\fR then the command will be executed
+at top-level (only global variables will be visible).
+.PP
+The \fBuplevel\fR command causes the invoking procedure to disappear
+from the procedure calling stack while the command is being executed.
+In the above example, suppose \fBc\fR invokes the command
+.DS
+\fBuplevel 1 {set x 43; d}
+.DE
+where \fBd\fR is another Tcl procedure. The \fBset\fR command will
+modify the variable \fBx\fR in \fBb\fR's context, and \fBd\fR will execute
+at level 3, as if called from \fBb\fR. If it in turn executes
+the command
+.DS
+\fBuplevel {set x 42}
+.DE
+then the \fBset\fR command will modify the same variable \fBx\fR in \fBb\fR's
+context: the procedure \fBc\fR does not appear to be on the call stack
+when \fBd\fR is executing. The command ``\fBinfo level\fR'' may
+be used to obtain the level of the current procedure.
+.PP
+\fBUplevel\fR makes it possible to implement new control
+constructs as Tcl procedures (for example, \fBuplevel\fR could
+be used to implement the \fBwhile\fR construct as a Tcl procedure).
+
+.SH KEYWORDS
+context, stack frame, variables
diff --git a/vendor/x11iraf/obm/Tcl/doc/upvar.n b/vendor/x11iraf/obm/Tcl/doc/upvar.n
new file mode 100644
index 00000000..7a83ea2c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/upvar.n
@@ -0,0 +1,83 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/upvar.n,v 1.3 93/06/16 16:41:13 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS upvar tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+upvar \- Create link to variable in a different stack frame
+.SH SYNOPSIS
+\fBupvar \fR?\fIlevel\fR? \fIotherVar myVar \fR?\fIotherVar myVar \fR...?
+.BE
+
+.SH DESCRIPTION
+.PP
+This command arranges for one or more local variables in the current
+procedure to refer to variables in an enclosing procedure call or
+to global variables.
+\fILevel\fR may have any of the forms permitted for the \fBuplevel\fR
+command, and may be omitted if the first letter of the first \fIotherVar\fR
+isn't \fB#\fR or a digit (it defaults to \fB1\fR).
+For each \fIotherVar\fR argument, \fBupvar\fR makes the variable
+by that name in the procedure frame given by \fIlevel\fR (or at
+global level, if \fIlevel\fR is \fB#0\fR) accessible
+in the current procedure by the name given in the corresponding
+\fImyVar\fR argument.
+The variable named by \fIotherVar\fR need not exist at the time of the
+call; it will be created the first time \fImyVar\fR is referenced, just like
+an ordinary variable.
+\fBUpvar\fR may only be invoked from within procedures.
+.VS
+\fIMyVar\fR may not refer to an element of an array, but \fIotherVar\fR
+may refer to an array element.
+.VE
+\fBUpvar\fR returns an empty string.
+.PP
+The \fBupvar\fR command simplifies the implementation of call-by-name
+procedure calling and also makes it easier to build new control constructs
+as Tcl procedures.
+For example, consider the following procedure:
+.DS
+.ta 1c 2c 3c
+\fBproc add2 name {
+ upvar $name x
+ set x [expr $x+2]
+}
+.DE
+\fBAdd2\fR is invoked with an argument giving the name of a variable,
+and it adds two to the value of that variable.
+Although \fBadd2\fR could have been implemented using \fBuplevel\fR
+instead of \fBupvar\fR, \fBupvar\fR makes it simpler for \fBadd2\fR
+to access the variable in the caller's procedure frame.
+.PP
+.VS
+If an upvar variable is unset (e.g. \fBx\fR in \fBadd2\fR above), the
+\fBunset\fR operation affects the variable it is linked to, not the
+upvar variable. There is no way to unset an upvar variable except
+by exiting the procedure in which it is defined. However, it is
+possible to retarget an upvar variable by executing another \fBupvar\fR
+command.
+.VE
+
+.SH KEYWORDS
+context, frame, global, level, procedure, variable
diff --git a/vendor/x11iraf/obm/Tcl/doc/while.n b/vendor/x11iraf/obm/Tcl/doc/while.n
new file mode 100644
index 00000000..f1687621
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/doc/while.n
@@ -0,0 +1,50 @@
+'\"
+'\" Copyright (c) 1993 The Regents of the University of California.
+'\" All rights reserved.
+'\"
+'\" Permission is hereby granted, without written agreement and without
+'\" license or royalty fees, to use, copy, modify, and distribute this
+'\" documentation for any purpose, provided that the above copyright
+'\" notice and the following two paragraphs appear in all copies.
+'\"
+'\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
+'\" FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+'\" ARISING OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+'\" CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'\"
+'\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+'\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+'\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+'\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+'\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+'\"
+'\" $Header: /user6/ouster/tcl/man/RCS/while.n,v 1.1 93/06/16 16:48:27 ouster Exp $ SPRITE (Berkeley)
+'\"
+.so man.macros
+.HS while tcl
+.BS
+'\" Note: do not modify the .SH NAME line immediately below!
+.SH NAME
+while \- Execute script repeatedly as long as a condition is met
+.SH SYNOPSIS
+\fBwhile \fItest body
+.BE
+
+.SH DESCRIPTION
+.PP
+The \fIwhile\fR command evaluates \fItest\fR as an expression
+(in the same way that \fBexpr\fR evaluates its argument).
+The value of the expression must a proper boolean
+value; if it is a true value
+then \fIbody\fR is executed by passing it to the Tcl interpreter.
+Once \fIbody\fR has been executed then \fItest\fR is evaluated
+again, and the process repeats until eventually \fItest\fR
+evaluates to a false boolean value. \fBContinue\fR
+commands may be executed inside \fIbody\fR to terminate the current
+iteration of the loop, and \fBbreak\fR
+commands may be executed inside \fIbody\fR to cause immediate
+termination of the \fBwhile\fR command. The \fBwhile\fR command
+always returns an empty string.
+
+.SH KEYWORDS
+boolean value, loop, test, while
diff --git a/vendor/x11iraf/obm/Tcl/library/init.tcl b/vendor/x11iraf/obm/Tcl/library/init.tcl
new file mode 100644
index 00000000..6edb37be
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/library/init.tcl
@@ -0,0 +1,259 @@
+# init.tcl --
+#
+# Default system startup file for Tcl-based applications. Defines
+# "unknown" procedure and auto-load facilities.
+#
+# $Header: /user6/ouster/tcl/library/RCS/init.tcl,v 1.28 93/10/08 09:11:21 ouster Exp $ SPRITE (Berkeley)
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+
+set auto_path [info library]
+
+# unknown:
+# Invoked when a Tcl command is invoked that doesn't exist in the
+# interpreter:
+#
+# 1. See if the autoload facility can locate the command in a
+# Tcl script file. If so, load it and execute it.
+# 2. See if the command exists as an executable UNIX program.
+# If so, "exec" the command.
+# 3. If the command was invoked at top-level:
+# (a) see if the command requests csh-like history substitution
+# in one of the common forms !!, !<number>, or ^old^new. If
+# so, emulate csh's history substitution.
+# (b) see if the command is a unique abbreviation for another
+# command. If so, invoke the command.
+
+proc unknown args {
+ global auto_noexec auto_noload env unknown_pending tcl_interactive;
+
+ set name [lindex $args 0]
+ if ![info exists auto_noload] {
+ #
+ # Make sure we're not trying to load the same proc twice.
+ #
+ if [info exists unknown_pending($name)] {
+ unset unknown_pending($name)
+ if {[array size unknown_pending] == 0} {
+ unset unknown_pending
+ }
+ return -code error "self-referential recursion in \"unknown\" for command \"$name\"";
+ }
+ set unknown_pending($name) pending;
+ set ret [catch {auto_load $name} msg]
+ unset unknown_pending($name);
+ if {$ret != 0} {
+ return -code $ret "error while autoloading \"$name\": $msg"
+ }
+ if ![array size unknown_pending] {
+ unset unknown_pending
+ }
+ if $msg {
+ return [uplevel $args]
+ }
+ }
+ if {([info level] == 1) && ([info script] == "") && $tcl_interactive} {
+ if ![info exists auto_noexec] {
+ if [auto_execok $name] {
+ return [uplevel exec >&@stdout <@stdin $args]
+ }
+ }
+ if {$name == "!!"} {
+ return [uplevel {history redo}]
+ }
+ if [regexp {^!(.+)$} $name dummy event] {
+ return [uplevel [list history redo $event]]
+ }
+ if [regexp {^\^([^^]*)\^([^^]*)\^?$} $name dummy old new] {
+ return [uplevel [list history substitute $old $new]]
+ }
+ set cmds [info commands $name*]
+ if {[llength $cmds] == 1} {
+ return [uplevel [lreplace $args 0 0 $cmds]]
+ }
+ if {[llength $cmds] != 0} {
+ if {$name == ""} {
+ return -code error "empty command name \"\""
+ } else {
+ return -code error \
+ "ambiguous command name \"$name\": [lsort $cmds]"
+ }
+ }
+ }
+ return -code error "invalid command name \"$name\""
+}
+
+# auto_load:
+# Checks a collection of library directories to see if a procedure
+# is defined in one of them. If so, it sources the appropriate
+# library file to create the procedure. Returns 1 if it successfully
+# loaded the procedure, 0 otherwise.
+
+proc auto_load cmd {
+ global auto_index auto_oldpath auto_path env errorInfo errorCode
+
+ if [info exists auto_index($cmd)] {
+ uplevel #0 $auto_index($cmd)
+ return 1
+ }
+ if [catch {set path $auto_path}] {
+ if [catch {set path $env(TCLLIBPATH)}] {
+ if [catch {set path [info library]}] {
+ return 0
+ }
+ }
+ }
+ if [info exists auto_oldpath] {
+ if {$auto_oldpath == $path} {
+ return 0
+ }
+ }
+ set auto_oldpath $path
+ catch {unset auto_index}
+ for {set i [expr [llength $path] - 1]} {$i >= 0} {incr i -1} {
+ set dir [lindex $path $i]
+ set f ""
+ if [catch {set f [open $dir/tclIndex]}] {
+ continue
+ }
+ set error [catch {
+ set id [gets $f]
+ if {$id == "# Tcl autoload index file, version 2.0"} {
+ eval [read $f]
+ } elseif {$id == "# Tcl autoload index file: each line identifies a Tcl"} {
+ while {[gets $f line] >= 0} {
+ if {([string index $line 0] == "#")
+ || ([llength $line] != 2)} {
+ continue
+ }
+ set name [lindex $line 0]
+ set auto_index($name) "source $dir/[lindex $line 1]"
+ }
+ } else {
+ error "$dir/tclIndex isn't a proper Tcl index file"
+ }
+ } msg]
+ if {$f != ""} {
+ close $f
+ }
+ if $error {
+ error $msg $errorInfo $errorCode
+ }
+ }
+ if [info exists auto_index($cmd)] {
+ uplevel #0 $auto_index($cmd)
+ if {[info commands $cmd] != ""} {
+ return 1
+ }
+ }
+ return 0
+}
+
+# auto_execok:
+# Returns 1 if there's an executable in the current path for the
+# given name, 0 otherwise. Builds an associative array auto_execs
+# that caches information about previous checks, for speed.
+
+proc auto_execok name {
+ global auto_execs env
+
+ if [info exists auto_execs($name)] {
+ return $auto_execs($name)
+ }
+ set auto_execs($name) 0
+ if {[string first / $name] >= 0} {
+ if {[file executable $name] && ![file isdirectory $name]} {
+ set auto_execs($name) 1
+ }
+ return $auto_execs($name)
+ }
+ foreach dir [split $env(PATH) :] {
+ if {[file executable $dir/$name] && ![file isdirectory $dir/$name]} {
+ set auto_execs($name) 1
+ return 1
+ }
+ }
+ return 0
+}
+
+# auto_reset:
+# Destroy all cached information for auto-loading and auto-execution,
+# so that the information gets recomputed the next time it's needed.
+# Also delete any procedures that are listed in the auto-load index
+# except those related to auto-loading.
+
+proc auto_reset {} {
+ global auto_execs auto_index auto_oldpath
+ foreach p [info procs] {
+ if {[info exists auto_index($p)] && ($p != "unknown")
+ && ![string match auto_* $p]} {
+ rename $p {}
+ }
+ }
+ catch {unset auto_execs}
+ catch {unset auto_index}
+ catch {unset auto_oldpath}
+}
+
+# auto_mkindex:
+# Regenerate a tclIndex file from Tcl source files. Takes as argument
+# the name of the directory in which the tclIndex file is to be placed,
+# floowed by any number of glob patterns to use in that directory to
+# locate all of the relevant files.
+
+proc auto_mkindex {dir args} {
+ global errorCode errorInfo
+ set oldDir [pwd]
+ cd $dir
+ set dir [pwd]
+ append index "# Tcl autoload index file, version 2.0\n"
+ append index "# This file is generated by the \"auto_mkindex\" command\n"
+ append index "# and sourced to set up indexing information for one or\n"
+ append index "# more commands. Typically each line is a command that\n"
+ append index "# sets an element in the auto_index array, where the\n"
+ append index "# element name is the name of a command and the value is\n"
+ append index "# a script that loads the command.\n\n"
+ foreach file [eval glob $args] {
+ set f ""
+ set error [catch {
+ set f [open $file]
+ while {[gets $f line] >= 0} {
+ if [regexp {^proc[ ]+([^ ]*)} $line match procName] {
+ append index "set [list auto_index($procName)]"
+ append index " \"source \$dir/$file\"\n"
+ }
+ }
+ close $f
+ } msg]
+ if $error {
+ set code $errorCode
+ set info $errorInfo
+ catch {close $f}
+ cd $oldDir
+ error $msg $info $code
+ }
+ }
+ set f [open tclIndex w]
+ puts $f $index nonewline
+ close $f
+ cd $oldDir
+}
diff --git a/vendor/x11iraf/obm/Tcl/library/parray.tcl b/vendor/x11iraf/obm/Tcl/library/parray.tcl
new file mode 100644
index 00000000..b4c9f2dc
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/library/parray.tcl
@@ -0,0 +1,43 @@
+# parray:
+# Print the contents of a global array on stdout.
+#
+# $Header: /user6/ouster/tcl/library/RCS/parray.tcl,v 1.5 93/02/06 16:33:45 ouster Exp $ SPRITE (Berkeley)
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+
+proc parray a {
+ upvar 1 $a array
+ if [catch {array size array}] {
+ error "\"$a\" isn't an array"
+ }
+ set maxl 0
+ foreach name [lsort [array names array]] {
+ if {[string length $name] > $maxl} {
+ set maxl [string length $name]
+ }
+ }
+ set maxl [expr {$maxl + [string length $a] + 2}]
+ foreach name [lsort [array names array]] {
+ set nameString [format %s(%s) $a $name]
+ puts stdout [format "%-*s = %s" $maxl $nameString $array($name)]
+ }
+}
diff --git a/vendor/x11iraf/obm/Tcl/library/tclIndex b/vendor/x11iraf/obm/Tcl/library/tclIndex
new file mode 100644
index 00000000..ad036dcd
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/library/tclIndex
@@ -0,0 +1,14 @@
+# Tcl autoload index file, version 2.0
+# This file is generated by the "auto_mkindex" command
+# and sourced to set up indexing information for one or
+# more commands. Typically each line is a command that
+# sets an element in the auto_index array, where the
+# element name is the name of a command and the value is
+# a script that loads the command.
+
+set auto_index(unknown) "source $dir/init.tcl"
+set auto_index(auto_load) "source $dir/init.tcl"
+set auto_index(auto_execok) "source $dir/init.tcl"
+set auto_index(auto_reset) "source $dir/init.tcl"
+set auto_index(auto_mkindex) "source $dir/init.tcl"
+set auto_index(parray) "source $dir/parray.tcl"
diff --git a/vendor/x11iraf/obm/Tcl/panic.c b/vendor/x11iraf/obm/Tcl/panic.c
new file mode 100644
index 00000000..fa994812
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/panic.c
@@ -0,0 +1,69 @@
+/*
+ * panic.c --
+ *
+ * Source code for the "panic" library procedure for Tcl;
+ * individual applications will probably override this with
+ * an application-specific panic procedure.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/panic.c,v 1.5 93/07/12 14:01:35 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include <stdio.h>
+#ifdef NO_STDLIB_H
+# include "compat/stdlib.h"
+#else
+# include <stdlib.h>
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * panic --
+ *
+ * Print an error message and kill the process.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The process dies, entering the debugger if possible.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* VARARGS ARGSUSED */
+void
+panic(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+ char *format; /* Format string, suitable for passing to
+ * fprintf. */
+ char *arg1, *arg2, *arg3; /* Additional arguments (variable in number)
+ * to pass to fprintf. */
+ char *arg4, *arg5, *arg6, *arg7, *arg8;
+{
+ (void) fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6,
+ arg7, arg8);
+ (void) fflush(stderr);
+ abort();
+}
diff --git a/vendor/x11iraf/obm/Tcl/patchlevel.h b/vendor/x11iraf/obm/Tcl/patchlevel.h
new file mode 100644
index 00000000..24e4a0a1
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/patchlevel.h
@@ -0,0 +1,11 @@
+/*
+ * patchlevel.h --
+ *
+ * This file does nothing except define a "patch level" for Tcl.
+ * The patch level is an integer that increments with each new
+ * release or patch release. It's used to make sure that Tcl
+ * patches are applied in the correct order and only to appropriate
+ * sources.
+ */
+
+#define TCL_PATCH_LEVEL 106
diff --git a/vendor/x11iraf/obm/Tcl/porting.notes b/vendor/x11iraf/obm/Tcl/porting.notes
new file mode 100644
index 00000000..5e338757
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/porting.notes
@@ -0,0 +1,214 @@
+This file contains a collection of notes that various people have
+provided about porting Tcl to various machines and operating systems.
+I don't have personal access to any of these machines, so I make
+no guarantees that the notes are correct, complete, or up-to-date.
+In some cases, a person has volunteered to act as a contact point
+for questions about porting Tcl to a particular machine; in these
+cases the person's name and e-mail address are listed.
+
+---------------------------------------------
+Cray machines running UNICOS:
+Contact: John Freeman (jlf@cray.com)
+---------------------------------------------
+
+1. There is an error in the strstr function in UNICOS such that if the
+string to be searched is empty (""), the search will continue past the
+end of the string. Because of this, the history substitution loop
+will sometimes run past the end of its target string and trash
+malloc's free list, resulting in a core dump some time later. (As you
+can probably guess, this took a while to diagnose.) I've submitted a
+problem report to the C library maintainers, but in the meantime here
+is a workaround.
+
+-----------------------------------------------------------------
+diff -c1 -r1.1 tclHistory.c
+*** 1.1 1991/11/12 16:01:58
+--- tclHistory.c 1991/11/12 16:14:22
+***************
+*** 23,24 ****
+--- 23,29 ----
+ #include "tclInt.h"
++
++ #ifdef _CRAY
++ /* There is a bug in strstr in UNICOS; this works around it. */
++ #define strstr(s1,s2) ((s1)?(*(s1)?strstr((s1),(s2)):0):0)
++ #endif _CRAY
+
+---------------------------------------------
+MIPS systems runing EP/IX:
+---------------------------------------------
+
+1. Need to add a line "#include <bsd/sys/time.h>" in tclUnix.h.
+
+2. Need to add "-lbsd" into the line that makes tclTest:
+
+ ${CC} ${CFLAGS} tclTest.o libtcl.a -lbsd -o tclTest
+
+---------------------------------------------
+IBM RS/6000 systems running AIX:
+---------------------------------------------
+
+1. The system version of strtoul is buggy, at least under some
+versions of AIX. If the expression tests fail, try forcing Tcl
+to use its own version of strtoul instead of the system version.
+To do this, first copy strtoul.c from the compat subdirectory up
+to the main Tcl directory. Then modify the Makefile so that
+the definition for COMPAT_OBJS includes "strtoul.o". Note: the
+"config" script should now detect the buggy strtoul and substitute
+Tcl's version automatically.
+
+2. You may have to comment out the declaration of open in tclUnix.h.
+
+3. You may need to add "-D_BSD -lbsd" to the CFLAGS definition. This
+causes the system include files to look like BSD include files and
+causes C library routines to act like bsd library routines. Without
+this, the system may choke on "struct wait".
+
+---------------------------------------------
+AT&T 4.03 OS:
+---------------------------------------------
+
+Machine: i386/33Mhz i387 32k Cache 16MByte
+OS: AT&T SYSV Release 4 Version 3
+X: X11R5 fixlevel 9
+Xserver: X386 1.2
+
+1. Change the Tk Makefile as follows:
+XLIB = -lX11
+ should be changed to:
+XLIB = -lX11 -lsocket -lnsl
+
+-------------------------------------------------------
+Silicon Graphics systems:
+-------------------------------------------------------
+
+1. Change the CC variable in the Makefile to:
+
+CC = cc -xansi -D__STDC__ -signed
+
+2. In Irix releases 4.0.1 or earlier the C compiler has a buggy optimizer.
+ If Tcl fails its test suite or generates inexplicable errors,
+ compile tclVar.c with -O0 instead of -O.
+
+3. For IRIX 5.1 or later, comments 1 and 2 are no longer relevant,
+but you must add -D_BSD_SIGNALS to CFLAGS to get the proper signal
+routines.
+
+4. Add a "-lsun" switch in the targets for tclsh and tcltest,
+just before ${MATH_LIBS}.
+
+---------------------------------------------
+NeXT machines running NeXTStep 3.1:
+---------------------------------------------
+
+1. Run configure with predefined CPP:
+ CPP='cc -E' ./configure
+
+2. Edit Makefile:
+ -add tmpnam.o to COMPAT_OBJS:
+ COMPAT_OBJS = getcwd.o waitpid.o strtod.o tmpnam.o
+ -add '-m' to MATH_LIBS
+ MATH_LIBS = -m -lm
+
+3. Edit compat/tmpnam.o and replace "/usr/tmp" with "/tmp"
+
+After this, tcl7.0 will be build fine on NeXT (ignore linker warning)
+and run all the tests. There are some formatting problems in printf() or
+scanf() which come from NeXT's lacking POSIX conformance. Ignore those
+errors, they don't matter much.
+
+-------------------------------------------------
+ISC 2.2 UNIX (using standard ATT SYSV compiler):
+-------------------------------------------------
+
+In Makefile, change
+
+CFLAGS = -g -I. -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
+
+to
+
+CFLAGS = -g -I. -DPOSIX_JC -DTCL_LIBRARY=\"${TCL_LIBRARY}\"
+
+This brings in the typedef for pid_t, which is needed for
+/usr/include/sys/wait.h in tclUnix.h.
+
+---------------------------------------------
+DEC Alphas:
+---------------------------------------------
+
+1. There appears to be a compiler/library bug that causes core-dumps
+unless you compile tclVar.c without optimization (remove the -O compiler
+switch). The problem appears to have been fixed in the 1.3-4 version
+of the compiler.
+
+---------------------------------------------
+CDC 4680MNP, EP/IX 1.4.3:
+---------------------------------------------
+
+The installation was done in the System V environment (-systype sysv)
+with the BSD extensions available (-I/usr/include/bsd and -lbsd). It was
+built with the 2.20 level C compiler. The 2.11 level should not be used
+because it has a problem with detecting NaN values in lines like:
+ if (x != x) ...
+which appear in the TCL code.
+
+To make the configure script find the BSD extensions, I set environment
+variable DEFS to "-I/usr/include/bsd" and LIBS to "-lbsd" before
+running it. I would have also set CC to "cc2.20", but that compiler
+driver has a bug that loader errors (e.g. not finding a library routine,
+which the script uses to tell what is available) do not cause an error
+status to be returned to the shell.
+
+There is a bug in the <sys/wait.h> include file that mis-defines the
+structure fields and causes WIFEXITED and WIFSIGNALED to return incorrect
+values. My solution was to create a subdirectory "sys" of the main TCL
+source directory and put a corrected wait.h in it. The "-I." already on
+all the compile lines causes it to be used instead of the system version.
+To fix this, compare the structure definition in /usr/include/bsd/sys/wait.h
+with /bsd43/include/sys/wait.h (or mail to John Jackson, jrj@cc.purdue.edu,
+and he'll send you a context diff).
+
+After running configure, I made the following changes to Makefile:
+
+ 1) In AC_FLAGS, change:
+ -DNO_WAIT3=1
+ to
+ -DNO_WAIT3=0 -Dwait3=wait2
+ EP/IX (in the System V environment) provides a wait2() system
+ call with what TCL needs (the WNOHANG flag). The extra parameter
+ TCL passes to what it thinks is wait3() (the resources used by
+ the child process) is always zero and will be safely ignored.
+
+ 3) Change:
+ CC=cc
+ to
+ CC=cc2.20
+ because of the NaN problem mentioned earlier. Skip this if the
+ default compiler is already 2.20 (or later).
+
+ 4) Add "-lbsd" to the commands that create tclsh and tcltest
+ (look for "-o").
+
+---------------------------------------------
+Convex systems, OS 10.1 and 10.2:
+Contact: Lennart Sorth (ls@dmi.min.dk)
+---------------------------------------------
+
+1. tcl7.0b2 compiles on Convex systems (OS 10.1 and 10.2) by just running
+ configure, typing make, except tclUnixUtil.c needs to be compiled
+ with option "-pcc" (portable cc, =!ANSI) due to:
+ cc: Error on line 1111 of tclUnixUtil.c: 'waitpid' redeclared:
+ incompatible types.
+
+-------------------------------------------------
+Pyramid, OSx 5.1a (UCB universe, GCC installed):
+-------------------------------------------------
+
+1. The procedures memcpy, strchr, fmod, and strrchr are all missing,
+so you'll need to provide substitutes for them. After you do that
+everything should compile fine. There will be one error in a scan
+test, but it's an obscure one because of a non-ANSI implementation
+of sscanf on the machine; you can ignore it.
+
+2. You may also have to add "tmpnam.o" to COMPAT_OBJS in Makefile:
+the system version appears to be bad.
diff --git a/vendor/x11iraf/obm/Tcl/regexp.c b/vendor/x11iraf/obm/Tcl/regexp.c
new file mode 100644
index 00000000..6dc0e291
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/regexp.c
@@ -0,0 +1,1233 @@
+/*
+ * TclRegComp and TclRegExec -- TclRegSub and TclRegError are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * *** NOTE: this code has been altered slightly for use in Tcl: ***
+ * *** 1. Use ckalloc and ckfree instead of malloc and free. ***
+ * *** 2. Add extra argument to regexp to specify the real ***
+ * *** start of the string separately from the start of the ***
+ * *** current search. This is needed to search for multiple ***
+ * *** matches within a string. ***
+ * *** 3. Names have been changed, e.g. from regcomp to ***
+ * *** TclRegComp, to avoid clashes with other ***
+ * *** regexp implementations used by applications. ***
+ */
+#include "tclInt.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that TclRegComp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in TclRegExec() needs it and TclRegComp() is
+ * computing it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this string. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define OPEN 20 /* no Mark this point in input as start of #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define FAIL(m) { TclRegError(m); return(NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+#define META "^$.[()|?+*\\"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for TclRegComp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+
+/*
+ * Forward declarations for TclRegComp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regnode();
+STATIC char *regnext();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+#ifdef STRCSPN
+STATIC int strcspn();
+#endif
+
+/*
+ - TclRegComp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+TclRegComp(exp)
+char *exp;
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register int len;
+ int flags;
+
+ if (exp == NULL)
+ FAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+ regparse = exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *)ckalloc(sizeof(regexp) + (unsigned)regsize);
+ if (r == NULL)
+ FAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ */
+ if (flags&SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && ((int) strlen(OPERAND(scan))) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno = 0;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN+parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE+parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ register int clss;
+ register int classend;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ clss = UCHARAT(regparse-2)+1;
+ classend = UCHARAT(regparse);
+ if (clss > classend+1)
+ FAIL("invalid [] range");
+ for (; clss <= classend; clss++)
+ regc(clss);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']')
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ /* NOTREACHED */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ /* NOTREACHED */
+ break;
+ case '\\':
+ if (*regparse == '\0')
+ FAIL("trailing \\");
+ ret = regnode(EXACTLY);
+ regc(*regparse++);
+ regc('\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ default: {
+ register int len;
+ register char ender;
+
+ regparse--;
+ len = strcspn(regparse, META);
+ if (len <= 0)
+ FAIL("internal disaster");
+ ender = *(regparse+len);
+ if (len > 1 && ISMULT(ender))
+ len--; /* Back off clear of ?+* operand. */
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ ret = regnode(EXACTLY);
+ while (len > 0) {
+ regc(*regparse++);
+ len--;
+ }
+ regc('\0');
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return(ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * TclRegExec and friends
+ */
+
+/*
+ * Global work variables for TclRegExec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - TclRegExec - match a regexp against a string
+ */
+int
+TclRegExec(prog, string, start)
+register regexp *prog;
+register char *string;
+char *start;
+{
+ register char *s;
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ TclRegError("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ TclRegError("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL) {
+ s = string;
+ while ((s = strchr(s, prog->regmust[0])) != NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = start;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != NULL) {
+ if (regtry(prog, s))
+ return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(prog, string)
+regexp *prog;
+char *string;
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return(0);
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return(0);
+ reginput++;
+ break;
+ case EXACTLY: {
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[no] == NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ /* NOTREACHED */
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[no] == NULL)
+ regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ /* NOTREACHED */
+ break;
+ case BRANCH: {
+ register char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ /* NOTREACHED */
+ break;
+ case STAR:
+ case PLUS: {
+ register char nextch;
+ register int no;
+ register char *save;
+ register int min;
+
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ /* NOTREACHED */
+ break;
+ case END:
+ return(1); /* Success! */
+ /* NOTREACHED */
+ break;
+ default:
+ TclRegError("memory corruption");
+ return(0);
+ /* NOTREACHED */
+ break;
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ TclRegError("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(p)
+char *p;
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ TclRegError("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext(p)
+register char *p;
+{
+ register int offset;
+
+ if (p == &regdummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(op)
+char *op;
+{
+ register char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9:
+ sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+ p = NULL;
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9:
+ sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ default:
+ TclRegError("corrupted opcode");
+ break;
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries. They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(s1, s2)
+char *s1;
+char *s2;
+{
+ register char *scan1;
+ register char *scan2;
+ register int count;
+
+ count = 0;
+ for (scan1 = s1; *scan1 != '\0'; scan1++) {
+ for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
+ if (*scan1 == *scan2++)
+ return(count);
+ count++;
+ }
+ return(count);
+}
+#endif
diff --git a/vendor/x11iraf/obm/Tcl/tcl.h b/vendor/x11iraf/obm/Tcl/tcl.h
new file mode 100644
index 00000000..5c9288aa
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tcl.h
@@ -0,0 +1,649 @@
+/*
+ * tcl.h --
+ *
+ * This header file describes the externally-visible facilities
+ * of the Tcl interpreter.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/RCS/tcl.h,v 1.131 93/11/21 14:50:35 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _TCL
+#define _TCL
+
+#ifndef BUFSIZ
+#include <stdio.h>
+#endif
+
+#define TCL_VERSION "7.3"
+#define TCL_MAJOR_VERSION 7
+#define TCL_MINOR_VERSION 3
+
+/*
+ * Definitions that allow this header file to be used either with or
+ * without ANSI C features like function prototypes.
+ */
+
+#undef _ANSI_ARGS_
+#undef CONST
+#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus)
+# define _USING_PROTOTYPES_ 1
+# define _ANSI_ARGS_(x) x
+# define CONST const
+# ifdef __cplusplus
+# define VARARGS (...)
+# else
+# define VARARGS ()
+# endif
+#else
+# define _ANSI_ARGS_(x) ()
+# define CONST
+#endif
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+#else
+# define EXTERN extern
+#endif
+
+/*
+ * Macro to use instead of "void" for arguments that must have
+ * type "void *" in ANSI C; maps them to type "char *" in
+ * non-ANSI systems.
+ */
+
+#ifndef VOID
+# ifdef __STDC__
+# define VOID void
+# else
+# define VOID char
+# endif
+#endif
+
+/*
+ * Miscellaneous declarations (to allow Tcl to be used stand-alone,
+ * without the rest of Sprite).
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _CLIENTDATA
+# ifdef __STDC__
+ typedef void *ClientData;
+# else
+ typedef int *ClientData;
+# endif /* __STDC__ */
+#define _CLIENTDATA
+#endif
+
+/*
+ * Data structures defined opaquely in this module. The definitions
+ * below just provide dummy types. A few fields are made visible in
+ * Tcl_Interp structures, namely those for returning string values.
+ * Note: any change to the Tcl_Interp definition below must be mirrored
+ * in the "real" definition in tclInt.h.
+ */
+
+typedef struct Tcl_Interp{
+ char *result; /* Points to result string returned by last
+ * command. */
+ void (*freeProc) _ANSI_ARGS_((char *blockPtr));
+ /* Zero means result is statically allocated.
+ * If non-zero, gives address of procedure
+ * to invoke to free the result. Must be
+ * freed by Tcl_Eval before executing next
+ * command. */
+ int errorLine; /* When TCL_ERROR is returned, this gives
+ * the line number within the command where
+ * the error occurred (1 means first line). */
+} Tcl_Interp;
+
+typedef int *Tcl_Trace;
+typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler;
+
+/*
+ * When a TCL command returns, the string pointer interp->result points to
+ * a string containing return information from the command. In addition,
+ * the command procedure returns an integer value, which is one of the
+ * following:
+ *
+ * TCL_OK Command completed normally; interp->result contains
+ * the command's result.
+ * TCL_ERROR The command couldn't be completed successfully;
+ * interp->result describes what went wrong.
+ * TCL_RETURN The command requests that the current procedure
+ * return; interp->result contains the procedure's
+ * return value.
+ * TCL_BREAK The command requests that the innermost loop
+ * be exited; interp->result is meaningless.
+ * TCL_CONTINUE Go on to the next iteration of the current loop;
+ * interp->result is meaningless.
+ */
+
+#define TCL_OK 0
+#define TCL_ERROR 1
+#define TCL_RETURN 2
+#define TCL_BREAK 3
+#define TCL_CONTINUE 4
+
+#define TCL_RESULT_SIZE 200
+
+/*
+ * Argument descriptors for math function callbacks in expressions:
+ */
+
+typedef enum {TCL_INT, TCL_DOUBLE, TCL_EITHER} Tcl_ValueType;
+typedef struct Tcl_Value {
+ Tcl_ValueType type; /* Indicates intValue or doubleValue is
+ * valid, or both. */
+ int intValue; /* Integer value. */
+ double doubleValue; /* Double-precision floating value. */
+} Tcl_Value;
+
+/*
+ * Procedure types defined by Tcl:
+ */
+
+typedef int (Tcl_AsyncProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int code));
+typedef void (Tcl_CmdDeleteProc) _ANSI_ARGS_((ClientData clientData));
+typedef int (Tcl_CmdProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char *argv[]));
+typedef void (Tcl_CmdTraceProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *proc,
+ ClientData cmdClientData, int argc, char *argv[]));
+typedef void (Tcl_FreeProc) _ANSI_ARGS_((char *blockPtr));
+typedef void (Tcl_InterpDeleteProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp));
+typedef int (Tcl_MathProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args, Tcl_Value *resultPtr));
+typedef char *(Tcl_VarTraceProc) _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *part1, char *part2, int flags));
+
+/*
+ * The structure returned by Tcl_GetCmdInfo and passed into
+ * Tcl_SetCmdInfo:
+ */
+
+typedef struct Tcl_CmdInfo {
+ Tcl_CmdProc *proc; /* Procedure that implements command. */
+ ClientData clientData; /* ClientData passed to proc. */
+ Tcl_CmdDeleteProc *deleteProc; /* Procedure to call when command
+ * is deleted. */
+ ClientData deleteData; /* Value to pass to deleteProc (usually
+ * the same as clientData). */
+} Tcl_CmdInfo;
+
+/*
+ * The structure defined below is used to hold dynamic strings. The only
+ * field that clients should use is the string field, and they should
+ * never modify it.
+ */
+
+#define TCL_DSTRING_STATIC_SIZE 200
+typedef struct Tcl_DString {
+ char *string; /* Points to beginning of string: either
+ * staticSpace below or a malloc'ed array. */
+ int length; /* Number of non-NULL characters in the
+ * string. */
+ int spaceAvl; /* Total number of bytes available for the
+ * string and its terminating NULL char. */
+ char staticSpace[TCL_DSTRING_STATIC_SIZE];
+ /* Space to use in common case where string
+ * is small. */
+} Tcl_DString;
+
+#define Tcl_DStringLength(dsPtr) ((dsPtr)->length)
+#define Tcl_DStringValue(dsPtr) ((dsPtr)->string)
+
+/*
+ * Definitions for the maximum number of digits of precision that may
+ * be specified in the "tcl_precision" variable, and the number of
+ * characters of buffer space required by Tcl_PrintDouble.
+ */
+
+#define TCL_MAX_PREC 17
+#define TCL_DOUBLE_SPACE (TCL_MAX_PREC+10)
+
+/*
+ * Flag values passed to Tcl_Eval (see the man page for details; also
+ * see tclInt.h for additional flags that are only used internally by
+ * Tcl):
+ */
+
+#define TCL_BRACKET_TERM 1
+
+/*
+ * Flag that may be passed to Tcl_ConvertElement to force it not to
+ * output braces (careful! if you change this flag be sure to change
+ * the definitions at the front of tclUtil.c).
+ */
+
+#define TCL_DONT_USE_BRACES 1
+
+/*
+ * Flag value passed to Tcl_RecordAndEval to request no evaluation
+ * (record only).
+ */
+
+#define TCL_NO_EVAL -1
+
+/*
+ * Special freeProc values that may be passed to Tcl_SetResult (see
+ * the man page for details):
+ */
+
+#define TCL_VOLATILE ((Tcl_FreeProc *) -1)
+#define TCL_STATIC ((Tcl_FreeProc *) 0)
+#define TCL_DYNAMIC ((Tcl_FreeProc *) free)
+
+/*
+ * Flag values passed to variable-related procedures.
+ */
+
+#define TCL_GLOBAL_ONLY 1
+#define TCL_APPEND_VALUE 2
+#define TCL_LIST_ELEMENT 4
+#define TCL_TRACE_READS 0x10
+#define TCL_TRACE_WRITES 0x20
+#define TCL_TRACE_UNSETS 0x40
+#define TCL_TRACE_DESTROYED 0x80
+#define TCL_INTERP_DESTROYED 0x100
+#define TCL_LEAVE_ERR_MSG 0x200
+
+/*
+ * Types for linked variables:
+ */
+
+#define TCL_LINK_INT 1
+#define TCL_LINK_DOUBLE 2
+#define TCL_LINK_BOOLEAN 3
+#define TCL_LINK_STRING 4
+#define TCL_LINK_READ_ONLY 0x80
+
+/*
+ * Permission flags for files:
+ */
+
+#define TCL_FILE_READABLE 1
+#define TCL_FILE_WRITABLE 2
+
+/*
+ * The following declarations either map ckalloc and ckfree to
+ * malloc and free, or they map them to procedures with all sorts
+ * of debugging hooks defined in tclCkalloc.c.
+ */
+
+#ifdef TCL_MEM_DEBUG
+
+EXTERN char * Tcl_DbCkalloc _ANSI_ARGS_((unsigned int size,
+ char *file, int line));
+EXTERN int Tcl_DbCkfree _ANSI_ARGS_((char *ptr,
+ char *file, int line));
+EXTERN char * Tcl_DbCkrealloc _ANSI_ARGS_((char *ptr,
+ unsigned int size, char *file, int line));
+EXTERN int Tcl_DumpActiveMemory _ANSI_ARGS_((char *fileName));
+EXTERN void Tcl_ValidateAllMemory _ANSI_ARGS_((char *file,
+ int line));
+# define ckalloc(x) Tcl_DbCkalloc(x, __FILE__, __LINE__)
+# define ckfree(x) Tcl_DbCkfree(x, __FILE__, __LINE__)
+# define ckrealloc(x,y) Tcl_DbCkrealloc((x), (y),__FILE__, __LINE__)
+
+#else
+
+# define ckalloc(x) malloc(x)
+# define ckfree(x) free(x)
+# define ckrealloc(x,y) realloc(x,y)
+# define Tcl_DumpActiveMemory(x)
+# define Tcl_ValidateAllMemory(x,y)
+
+#endif /* TCL_MEM_DEBUG */
+
+/*
+ * Macro to free up result of interpreter.
+ */
+
+#define Tcl_FreeResult(interp) \
+ if ((interp)->freeProc != 0) { \
+ if ((interp)->freeProc == (Tcl_FreeProc *) free) { \
+ ckfree((interp)->result); \
+ } else { \
+ (*(interp)->freeProc)((interp)->result); \
+ } \
+ (interp)->freeProc = 0; \
+ }
+
+/*
+ * Forward declaration of Tcl_HashTable. Needed by some C++ compilers
+ * to prevent errors when the forward reference to Tcl_HashTable is
+ * encountered in the Tcl_HashEntry structure.
+ */
+
+#ifdef __cplusplus
+struct Tcl_HashTable;
+#endif
+
+/*
+ * Structure definition for an entry in a hash table. No-one outside
+ * Tcl should access any of these fields directly; use the macros
+ * defined below.
+ */
+
+typedef struct Tcl_HashEntry {
+ struct Tcl_HashEntry *nextPtr; /* Pointer to next entry in this
+ * hash bucket, or NULL for end of
+ * chain. */
+ struct Tcl_HashTable *tablePtr; /* Pointer to table containing entry. */
+ struct Tcl_HashEntry **bucketPtr; /* Pointer to bucket that points to
+ * first entry in this entry's chain:
+ * used for deleting the entry. */
+ ClientData clientData; /* Application stores something here
+ * with Tcl_SetHashValue. */
+ union { /* Key has one of these forms: */
+ char *oneWordValue; /* One-word value for key. */
+ int words[1]; /* Multiple integer words for key.
+ * The actual size will be as large
+ * as necessary for this table's
+ * keys. */
+ char string[4]; /* String for key. The actual size
+ * will be as large as needed to hold
+ * the key. */
+ } key; /* MUST BE LAST FIELD IN RECORD!! */
+} Tcl_HashEntry;
+
+/*
+ * Structure definition for a hash table. Must be in tcl.h so clients
+ * can allocate space for these structures, but clients should never
+ * access any fields in this structure.
+ */
+
+#define TCL_SMALL_HASH_TABLE 4
+typedef struct Tcl_HashTable {
+ Tcl_HashEntry **buckets; /* Pointer to bucket array. Each
+ * element points to first entry in
+ * bucket's hash chain, or NULL. */
+ Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE];
+ /* Bucket array used for small tables
+ * (to avoid mallocs and frees). */
+ int numBuckets; /* Total number of buckets allocated
+ * at **bucketPtr. */
+ int numEntries; /* Total number of entries present
+ * in table. */
+ int rebuildSize; /* Enlarge table when numEntries gets
+ * to be this large. */
+ int downShift; /* Shift count used in hashing
+ * function. Designed to use high-
+ * order bits of randomized keys. */
+ int mask; /* Mask value used in hashing
+ * function. */
+ int keyType; /* Type of keys used in this table.
+ * It's either TCL_STRING_KEYS,
+ * TCL_ONE_WORD_KEYS, or an integer
+ * giving the number of ints in a
+ */
+ Tcl_HashEntry *(*findProc) _ANSI_ARGS_((struct Tcl_HashTable *tablePtr,
+ char *key));
+ Tcl_HashEntry *(*createProc) _ANSI_ARGS_((struct Tcl_HashTable *tablePtr,
+ char *key, int *newPtr));
+} Tcl_HashTable;
+
+/*
+ * Structure definition for information used to keep track of searches
+ * through hash tables:
+ */
+
+typedef struct Tcl_HashSearch {
+ Tcl_HashTable *tablePtr; /* Table being searched. */
+ int nextIndex; /* Index of next bucket to be
+ * enumerated after present one. */
+ Tcl_HashEntry *nextEntryPtr; /* Next entry to be enumerated in the
+ * the current bucket. */
+} Tcl_HashSearch;
+
+/*
+ * Acceptable key types for hash tables:
+ */
+
+#define TCL_STRING_KEYS 0
+#define TCL_ONE_WORD_KEYS 1
+
+/*
+ * Macros for clients to use to access fields of hash entries:
+ */
+
+#define Tcl_GetHashValue(h) ((h)->clientData)
+#define Tcl_SetHashValue(h, value) ((h)->clientData = (ClientData) (value))
+#define Tcl_GetHashKey(tablePtr, h) \
+ ((char *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS) ? (h)->key.oneWordValue \
+ : (h)->key.string))
+
+/*
+ * Macros to use for clients to use to invoke find and create procedures
+ * for hash tables:
+ */
+
+#define Tcl_FindHashEntry(tablePtr, key) \
+ (*((tablePtr)->findProc))(tablePtr, key)
+#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \
+ (*((tablePtr)->createProc))(tablePtr, key, newPtr)
+
+/*
+ * Exported Tcl variables:
+ */
+
+EXTERN int tcl_AsyncReady;
+EXTERN char * tcl_RcFileName;
+
+/*
+ * Exported Tcl procedures:
+ */
+
+EXTERN void Tcl_AsyncMark _ANSI_ARGS_((Tcl_AsyncHandler async));
+EXTERN Tcl_AsyncHandler Tcl_AsyncCreate _ANSI_ARGS_((Tcl_AsyncProc *proc,
+ ClientData clientData));
+EXTERN void Tcl_AsyncDelete _ANSI_ARGS_((Tcl_AsyncHandler async));
+EXTERN int Tcl_AsyncInvoke _ANSI_ARGS_((Tcl_Interp *interp,
+ int code));
+EXTERN void Tcl_AppendElement _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string));
+#ifdef ELLIPSES
+#ifdef USE_STDARG
+EXTERN void Tcl_AppendResult _ANSI_ARGS_((Tcl_Interp *interp, ...));
+#else
+EXTERN void Tcl_AppendResult _ANSI_ARGS_(VARARGS);
+#endif
+#endif
+EXTERN int Tcl_AppInit _ANSI_ARGS_((Tcl_Interp *interp));
+EXTERN void Tcl_AddErrorInfo _ANSI_ARGS_((Tcl_Interp *interp,
+ char *message));
+EXTERN char Tcl_Backslash _ANSI_ARGS_((char *src,
+ int *readPtr));
+EXTERN void Tcl_CallWhenDeleted _ANSI_ARGS_((Tcl_Interp *interp,
+ Tcl_InterpDeleteProc *proc,
+ ClientData clientData));
+EXTERN int Tcl_CommandComplete _ANSI_ARGS_((char *cmd));
+EXTERN char * Tcl_Concat _ANSI_ARGS_((int argc, char **argv));
+EXTERN int Tcl_ConvertElement _ANSI_ARGS_((char *src,
+ char *dst, int flags));
+EXTERN void Tcl_CreateCommand _ANSI_ARGS_((Tcl_Interp *interp,
+ char *cmdName, Tcl_CmdProc *proc,
+ ClientData clientData,
+ Tcl_CmdDeleteProc *deleteProc));
+EXTERN Tcl_Interp * Tcl_CreateInterp _ANSI_ARGS_((void));
+EXTERN void Tcl_CreateMathFunc _ANSI_ARGS_((Tcl_Interp *interp,
+ char *name, int numArgs, Tcl_ValueType *argTypes,
+ Tcl_MathProc *proc, ClientData clientData));
+EXTERN int Tcl_CreatePipeline _ANSI_ARGS_((Tcl_Interp *interp,
+ int argc, char **argv, int **pidArrayPtr,
+ int *inPipePtr, int *outPipePtr,
+ int *errFilePtr));
+EXTERN Tcl_Trace Tcl_CreateTrace _ANSI_ARGS_((Tcl_Interp *interp,
+ int level, Tcl_CmdTraceProc *proc,
+ ClientData clientData));
+EXTERN void Tcl_DeleteHashEntry _ANSI_ARGS_((
+ Tcl_HashEntry *entryPtr));
+EXTERN void Tcl_DeleteHashTable _ANSI_ARGS_((
+ Tcl_HashTable *tablePtr));
+EXTERN char * Tcl_DStringAppend _ANSI_ARGS_((Tcl_DString *dsPtr,
+ char *string, int length));
+EXTERN char * Tcl_DStringAppendElement _ANSI_ARGS_((
+ Tcl_DString *dsPtr, char *string));
+EXTERN void Tcl_DStringEndSublist _ANSI_ARGS_((Tcl_DString *dsPtr));
+EXTERN void Tcl_DStringFree _ANSI_ARGS_((Tcl_DString *dsPtr));
+EXTERN void Tcl_DStringInit _ANSI_ARGS_((Tcl_DString *dsPtr));
+EXTERN void Tcl_DStringResult _ANSI_ARGS_((Tcl_Interp *interp,
+ Tcl_DString *dsPtr));
+EXTERN void Tcl_DStringStartSublist _ANSI_ARGS_((
+ Tcl_DString *dsPtr));
+EXTERN void Tcl_DStringTrunc _ANSI_ARGS_((Tcl_DString *dsPtr,
+ int length));
+EXTERN int Tcl_DeleteCommand _ANSI_ARGS_((Tcl_Interp *interp,
+ char *cmdName));
+EXTERN void Tcl_DeleteInterp _ANSI_ARGS_((Tcl_Interp *interp));
+EXTERN void Tcl_DeleteTrace _ANSI_ARGS_((Tcl_Interp *interp,
+ Tcl_Trace trace));
+EXTERN void Tcl_DetachPids _ANSI_ARGS_((int numPids, int *pidPtr));
+EXTERN void Tcl_DontCallWhenDeleted _ANSI_ARGS_((
+ Tcl_Interp *interp, Tcl_InterpDeleteProc *proc,
+ ClientData clientData));
+EXTERN void Tcl_EnterFile _ANSI_ARGS_((Tcl_Interp *interp,
+ FILE *file, int permissions));
+EXTERN char * Tcl_ErrnoId _ANSI_ARGS_((void));
+EXTERN int Tcl_Eval _ANSI_ARGS_((Tcl_Interp *interp, char *cmd));
+EXTERN int Tcl_EvalFile _ANSI_ARGS_((Tcl_Interp *interp,
+ char *fileName));
+EXTERN int Tcl_ExprBoolean _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int *ptr));
+EXTERN int Tcl_ExprDouble _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, double *ptr));
+EXTERN int Tcl_ExprLong _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, long *ptr));
+EXTERN int Tcl_ExprString _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string));
+EXTERN int Tcl_FilePermissions _ANSI_ARGS_((FILE *file));
+EXTERN Tcl_HashEntry * Tcl_FirstHashEntry _ANSI_ARGS_((
+ Tcl_HashTable *tablePtr,
+ Tcl_HashSearch *searchPtr));
+EXTERN int Tcl_GetBoolean _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int *boolPtr));
+EXTERN int Tcl_GetCommandInfo _ANSI_ARGS_((Tcl_Interp *interp,
+ char *cmdName, Tcl_CmdInfo *infoPtr));
+EXTERN int Tcl_GetDouble _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, double *doublePtr));
+EXTERN int Tcl_GetInt _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int *intPtr));
+EXTERN int Tcl_GetOpenFile _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int write, int checkUsage,
+ FILE **filePtr));
+EXTERN char * Tcl_GetVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, int flags));
+EXTERN char * Tcl_GetVar2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, int flags));
+EXTERN int Tcl_GlobalEval _ANSI_ARGS_((Tcl_Interp *interp,
+ char *command));
+EXTERN char * Tcl_HashStats _ANSI_ARGS_((Tcl_HashTable *tablePtr));
+EXTERN int Tcl_Init _ANSI_ARGS_((Tcl_Interp *interp));
+EXTERN void Tcl_InitHashTable _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ int keyType));
+EXTERN void Tcl_InitMemory _ANSI_ARGS_((Tcl_Interp *interp));
+EXTERN int Tcl_LinkVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, char *addr, int type));
+EXTERN char * Tcl_Merge _ANSI_ARGS_((int argc, char **argv));
+EXTERN Tcl_HashEntry * Tcl_NextHashEntry _ANSI_ARGS_((
+ Tcl_HashSearch *searchPtr));
+EXTERN char * Tcl_ParseVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, char **termPtr));
+EXTERN char * Tcl_PosixError _ANSI_ARGS_((Tcl_Interp *interp));
+EXTERN void Tcl_PrintDouble _ANSI_ARGS_((Tcl_Interp *interp,
+ double value, char *dst));
+EXTERN void Tcl_ReapDetachedProcs _ANSI_ARGS_((void));
+EXTERN int Tcl_RecordAndEval _ANSI_ARGS_((Tcl_Interp *interp,
+ char *cmd, int flags));
+EXTERN int Tcl_RegExpMatch _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, char *pattern));
+EXTERN void Tcl_ResetResult _ANSI_ARGS_((Tcl_Interp *interp));
+#define Tcl_Return Tcl_SetResult
+EXTERN int Tcl_ScanElement _ANSI_ARGS_((char *string,
+ int *flagPtr));
+EXTERN int Tcl_SetCommandInfo _ANSI_ARGS_((Tcl_Interp *interp,
+ char *cmdName, Tcl_CmdInfo *infoPtr));
+#ifdef ELLIPSES
+#ifdef USE_STDARG
+EXTERN void Tcl_SetErrorCode _ANSI_ARGS_((Tcl_Interp *interp, ...));
+#else
+EXTERN void Tcl_SetErrorCode _ANSI_ARGS_(VARARGS);
+#endif
+#endif
+EXTERN int Tcl_SetRecursionLimit _ANSI_ARGS_((Tcl_Interp *interp,
+ int depth));
+EXTERN void Tcl_SetResult _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, Tcl_FreeProc *freeProc));
+EXTERN char * Tcl_SetVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, char *newValue, int flags));
+EXTERN char * Tcl_SetVar2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, char *newValue,
+ int flags));
+EXTERN char * Tcl_SignalId _ANSI_ARGS_((int sig));
+EXTERN char * Tcl_SignalMsg _ANSI_ARGS_((int sig));
+EXTERN int Tcl_SplitList _ANSI_ARGS_((Tcl_Interp *interp,
+ char *list, int *argcPtr, char ***argvPtr));
+EXTERN int Tcl_StringMatch _ANSI_ARGS_((char *string,
+ char *pattern));
+EXTERN char * Tcl_TildeSubst _ANSI_ARGS_((Tcl_Interp *interp,
+ char *name, Tcl_DString *bufferPtr));
+EXTERN int Tcl_TraceVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, int flags, Tcl_VarTraceProc *proc,
+ ClientData clientData));
+EXTERN int Tcl_TraceVar2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, int flags,
+ Tcl_VarTraceProc *proc, ClientData clientData));
+EXTERN void Tcl_UnlinkVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName));
+EXTERN int Tcl_UnsetVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, int flags));
+EXTERN int Tcl_UnsetVar2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, int flags));
+EXTERN void Tcl_UntraceVar _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, int flags, Tcl_VarTraceProc *proc,
+ ClientData clientData));
+EXTERN void Tcl_UntraceVar2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, int flags,
+ Tcl_VarTraceProc *proc, ClientData clientData));
+#ifdef ELLIPSES
+#ifdef USE_STDARG
+EXTERN int Tcl_VarEval _ANSI_ARGS_((Tcl_Interp *iPtr, ...));
+#else
+EXTERN int Tcl_VarEval _ANSI_ARGS_(VARARGS);
+#endif
+#endif
+EXTERN ClientData Tcl_VarTraceInfo _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, int flags,
+ Tcl_VarTraceProc *procPtr,
+ ClientData prevClientData));
+EXTERN ClientData Tcl_VarTraceInfo2 _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, int flags,
+ Tcl_VarTraceProc *procPtr,
+ ClientData prevClientData));
+
+#endif /* _TCL */
diff --git a/vendor/x11iraf/obm/Tcl/tclAppInit.c b/vendor/x11iraf/obm/Tcl/tclAppInit.c
new file mode 100644
index 00000000..df7f93c1
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclAppInit.c
@@ -0,0 +1,95 @@
+/*
+ * tclAppInit.c --
+ *
+ * Provides a default version of the Tcl_AppInit procedure.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclAppInit.c,v 1.6 93/08/26 14:34:55 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tcl.h"
+
+/*
+ * The following variable is a special hack that allows applications
+ * to be linked using the procedure "main" from the Tcl library. The
+ * variable generates a reference to "main", which causes main to
+ * be brought in from the library (and all of Tcl with it).
+ */
+
+extern int main();
+int *tclDummyMainPtr = (int *) main;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppInit --
+ *
+ * This procedure performs application-specific initialization.
+ * Most applications, especially those that incorporate additional
+ * packages, will have their own version of this procedure.
+ *
+ * Results:
+ * Returns a standard Tcl completion code, and leaves an error
+ * message in interp->result if an error occurs.
+ *
+ * Side effects:
+ * Depends on the startup script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_AppInit(interp)
+ Tcl_Interp *interp; /* Interpreter for application. */
+{
+ /*
+ * Call the init procedures for included packages. Each call should
+ * look like this:
+ *
+ * if (Mod_Init(interp) == TCL_ERROR) {
+ * return TCL_ERROR;
+ * }
+ *
+ * where "Mod" is the name of the module.
+ */
+
+ if (Tcl_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Call Tcl_CreateCommand for application-specific commands, if
+ * they weren't already created by the init procedures called above.
+ */
+
+ /*
+ * Specify a user-specific startup file to invoke if the application
+ * is run interactively. Typically the startup file is "~/.apprc"
+ * where "app" is the name of the application. If this line is deleted
+ * then no user-specific startup file will be run under any conditions.
+ */
+
+ tcl_RcFileName = "~/.tclshrc";
+ return TCL_OK;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclAsync.c b/vendor/x11iraf/obm/Tcl/tclAsync.c
new file mode 100644
index 00000000..447f5d4c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclAsync.c
@@ -0,0 +1,256 @@
+/*
+ * tclAsync.c --
+ *
+ * This file provides low-level support needed to invoke signal
+ * handlers in a safe way. The code here doesn't actually handle
+ * signals, though. This code is based on proposals made by
+ * Mark Diekhans and Don Libes.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclAsync.c,v 1.3 93/09/02 16:02:42 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+
+/*
+ * One of the following structures exists for each asynchronous
+ * handler:
+ */
+
+typedef struct AsyncHandler {
+ int ready; /* Non-zero means this handler should
+ * be invoked in the next call to
+ * Tcl_AsyncInvoke. */
+ struct AsyncHandler *nextPtr; /* Next in list of all handlers for
+ * the process. */
+ Tcl_AsyncProc *proc; /* Procedure to call when handler
+ * is invoked. */
+ ClientData clientData; /* Value to pass to handler when it
+ * is invoked. */
+} AsyncHandler;
+
+/*
+ * The variables below maintain a list of all existing handlers.
+ */
+
+static AsyncHandler *firstHandler; /* First handler defined for process,
+ * or NULL if none. */
+static AsyncHandler *lastHandler; /* Last handler or NULL. */
+
+/*
+ * The variable below is set to 1 whenever a handler becomes ready and
+ * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be
+ * checked elsewhere in the application to see if Tcl_AsyncInvoke
+ * should be invoked.
+ */
+
+int tcl_AsyncReady = 0;
+
+/*
+ * The variable below indicates whether Tcl_AsyncInvoke is currently
+ * working. If so then we won't set tcl_AsyncReady again until
+ * Tcl_AsyncInvoke returns.
+ */
+
+static int asyncActive = 0;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AsyncCreate --
+ *
+ * This procedure creates the data structures for an asynchronous
+ * handler, so that no memory has to be allocated when the handler
+ * is activated.
+ *
+ * Results:
+ * The return value is a token for the handler, which can be used
+ * to activate it later on.
+ *
+ * Side effects:
+ * Information about the handler is recorded.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_AsyncHandler
+Tcl_AsyncCreate(proc, clientData)
+ Tcl_AsyncProc *proc; /* Procedure to call when handler
+ * is invoked. */
+ ClientData clientData; /* Argument to pass to handler. */
+{
+ AsyncHandler *asyncPtr;
+
+ asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
+ asyncPtr->ready = 0;
+ asyncPtr->nextPtr = NULL;
+ asyncPtr->proc = proc;
+ asyncPtr->clientData = clientData;
+ if (firstHandler == NULL) {
+ firstHandler = asyncPtr;
+ } else {
+ lastHandler->nextPtr = asyncPtr;
+ }
+ lastHandler = asyncPtr;
+ return (Tcl_AsyncHandler) asyncPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AsyncMark --
+ *
+ * This procedure is called to request that an asynchronous handler
+ * be invoked as soon as possible. It's typically called from
+ * an interrupt handler, where it isn't safe to do anything that
+ * depends on or modifies application state.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The handler gets marked for invocation later.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AsyncMark(async)
+ Tcl_AsyncHandler async; /* Token for handler. */
+{
+ ((AsyncHandler *) async)->ready = 1;
+ if (!asyncActive) {
+ tcl_AsyncReady = 1;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AsyncInvoke --
+ *
+ * This procedure is called at a "safe" time at background level
+ * to invoke any active asynchronous handlers.
+ *
+ * Results:
+ * The return value is a normal Tcl result, which is intended to
+ * replace the code argument as the current completion code for
+ * interp.
+ *
+ * Side effects:
+ * Depends on the handlers that are active.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_AsyncInvoke(interp, code)
+ Tcl_Interp *interp; /* If invoked from Tcl_Eval just after
+ * completing a command, points to
+ * interpreter. Otherwise it is
+ * NULL. */
+ int code; /* If interp is non-NULL, this gives
+ * completion code from command that
+ * just completed. */
+{
+ AsyncHandler *asyncPtr;
+
+ if (tcl_AsyncReady == 0) {
+ return code;
+ }
+ tcl_AsyncReady = 0;
+ asyncActive = 1;
+ if (interp == NULL) {
+ code = 0;
+ }
+
+ /*
+ * Make one or more passes over the list of handlers, invoking
+ * at most one handler in each pass. After invoking a handler,
+ * go back to the start of the list again so that (a) if a new
+ * higher-priority handler gets marked while executing a lower
+ * priority handler, we execute the higher-priority handler
+ * next, and (b) if a handler gets deleted during the execution
+ * of a handler, then the list structure may change so it isn't
+ * safe to continue down the list anyway.
+ */
+
+ while (1) {
+ for (asyncPtr = firstHandler; asyncPtr != NULL;
+ asyncPtr = asyncPtr->nextPtr) {
+ if (asyncPtr->ready) {
+ break;
+ }
+ }
+ if (asyncPtr == NULL) {
+ break;
+ }
+ asyncPtr->ready = 0;
+ code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
+ }
+ asyncActive = 0;
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AsyncDelete --
+ *
+ * Frees up all the state for an asynchronous handler. The handler
+ * should never be used again.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The state associated with the handler is deleted.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AsyncDelete(async)
+ Tcl_AsyncHandler async; /* Token for handler to delete. */
+{
+ AsyncHandler *asyncPtr = (AsyncHandler *) async;
+ AsyncHandler *prevPtr;
+
+ if (firstHandler == asyncPtr) {
+ firstHandler = asyncPtr->nextPtr;
+ if (firstHandler == NULL) {
+ lastHandler = NULL;
+ }
+ } else {
+ prevPtr = firstHandler;
+ while (prevPtr->nextPtr != asyncPtr) {
+ prevPtr = prevPtr->nextPtr;
+ }
+ prevPtr->nextPtr = asyncPtr->nextPtr;
+ if (lastHandler == asyncPtr) {
+ lastHandler = prevPtr;
+ }
+ }
+ ckfree((char *) asyncPtr);
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclBasic.c b/vendor/x11iraf/obm/Tcl/tclBasic.c
new file mode 100644
index 00000000..be5469db
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclBasic.c
@@ -0,0 +1,1381 @@
+/*
+ * tclBasic.c --
+ *
+ * Contains the basic facilities for TCL command interpretation,
+ * including interpreter creation and deletion, command creation
+ * and deletion, and command parsing and execution.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclBasic.c,v 1.153 93/09/09 16:43:19 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+#ifndef TCL_GENERIC_ONLY
+# include "tclUnix.h"
+#endif
+
+/*
+ * The following structure defines all of the commands in the Tcl core,
+ * and the C procedures that execute them.
+ */
+
+typedef struct {
+ char *name; /* Name of command. */
+ Tcl_CmdProc *proc; /* Procedure that executes command. */
+} CmdInfo;
+
+/*
+ * Built-in commands, and the procedures associated with them:
+ */
+
+static CmdInfo builtInCmds[] = {
+ /*
+ * Commands in the generic core:
+ */
+
+ {"append", Tcl_AppendCmd},
+ {"array", Tcl_ArrayCmd},
+ {"break", Tcl_BreakCmd},
+ {"case", Tcl_CaseCmd},
+ {"catch", Tcl_CatchCmd},
+ {"concat", Tcl_ConcatCmd},
+ {"continue", Tcl_ContinueCmd},
+ {"error", Tcl_ErrorCmd},
+ {"eval", Tcl_EvalCmd},
+ {"expr", Tcl_ExprCmd},
+ {"for", Tcl_ForCmd},
+ {"foreach", Tcl_ForeachCmd},
+ {"format", Tcl_FormatCmd},
+ {"global", Tcl_GlobalCmd},
+ {"history", Tcl_HistoryCmd},
+ {"if", Tcl_IfCmd},
+ {"incr", Tcl_IncrCmd},
+ {"info", Tcl_InfoCmd},
+ {"join", Tcl_JoinCmd},
+ {"lappend", Tcl_LappendCmd},
+ {"lindex", Tcl_LindexCmd},
+ {"linsert", Tcl_LinsertCmd},
+ {"list", Tcl_ListCmd},
+ {"llength", Tcl_LlengthCmd},
+ {"lrange", Tcl_LrangeCmd},
+ {"lreplace", Tcl_LreplaceCmd},
+ {"lsearch", Tcl_LsearchCmd},
+ {"lsort", Tcl_LsortCmd},
+ {"proc", Tcl_ProcCmd},
+ {"regexp", Tcl_RegexpCmd},
+ {"regsub", Tcl_RegsubCmd},
+ {"rename", Tcl_RenameCmd},
+ {"return", Tcl_ReturnCmd},
+ {"scan", Tcl_ScanCmd},
+ {"set", Tcl_SetCmd},
+ {"split", Tcl_SplitCmd},
+ {"string", Tcl_StringCmd},
+ {"switch", Tcl_SwitchCmd},
+ {"trace", Tcl_TraceCmd},
+ {"unset", Tcl_UnsetCmd},
+ {"uplevel", Tcl_UplevelCmd},
+ {"upvar", Tcl_UpvarCmd},
+ {"while", Tcl_WhileCmd},
+
+ /*
+ * Commands in the UNIX core:
+ */
+
+#ifndef TCL_GENERIC_ONLY
+ {"cd", Tcl_CdCmd},
+ {"close", Tcl_CloseCmd},
+ {"eof", Tcl_EofCmd},
+ {"exec", Tcl_ExecCmd},
+ {"exit", Tcl_ExitCmd},
+ {"file", Tcl_FileCmd},
+ {"flush", Tcl_FlushCmd},
+ {"gets", Tcl_GetsCmd},
+ {"glob", Tcl_GlobCmd},
+ {"open", Tcl_OpenCmd},
+ {"pid", Tcl_PidCmd},
+ {"puts", Tcl_PutsCmd},
+ {"pwd", Tcl_PwdCmd},
+ {"read", Tcl_ReadCmd},
+ {"seek", Tcl_SeekCmd},
+ {"source", Tcl_SourceCmd},
+ {"tell", Tcl_TellCmd},
+ {"time", Tcl_TimeCmd},
+#endif /* TCL_GENERIC_ONLY */
+ {NULL, (Tcl_CmdProc *) NULL}
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreateInterp --
+ *
+ * Create a new TCL command interpreter.
+ *
+ * Results:
+ * The return value is a token for the interpreter, which may be
+ * used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
+ * Tcl_DeleteInterp.
+ *
+ * Side effects:
+ * The command interpreter is initialized with an empty variable
+ * table and the built-in commands. SIGPIPE signals are set to
+ * be ignored (see comment below for details).
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_Interp *
+Tcl_CreateInterp()
+{
+ register Interp *iPtr;
+ register Command *cmdPtr;
+ register CmdInfo *cmdInfoPtr;
+ int i;
+ static int firstInterp = 1;
+
+ iPtr = (Interp *) ckalloc(sizeof(Interp));
+ iPtr->result = iPtr->resultSpace;
+ iPtr->freeProc = 0;
+ iPtr->errorLine = 0;
+ Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&iPtr->mathFuncTable, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
+ iPtr->numLevels = 0;
+ iPtr->maxNestingDepth = 1000;
+ iPtr->framePtr = NULL;
+ iPtr->varFramePtr = NULL;
+ iPtr->activeTracePtr = NULL;
+ iPtr->returnCode = TCL_OK;
+ iPtr->errorInfo = NULL;
+ iPtr->errorCode = NULL;
+ iPtr->numEvents = 0;
+ iPtr->events = NULL;
+ iPtr->curEvent = 0;
+ iPtr->curEventNum = 0;
+ iPtr->revPtr = NULL;
+ iPtr->historyFirst = NULL;
+ iPtr->revDisables = 1;
+ iPtr->evalFirst = iPtr->evalLast = NULL;
+ iPtr->appendResult = NULL;
+ iPtr->appendAvl = 0;
+ iPtr->appendUsed = 0;
+ for (i = 0; i < NUM_REGEXPS; i++) {
+ iPtr->patterns[i] = NULL;
+ iPtr->patLengths[i] = -1;
+ iPtr->regexps[i] = NULL;
+ }
+ strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
+ iPtr->pdPrec = DEFAULT_PD_PREC;
+ iPtr->cmdCount = 0;
+ iPtr->noEval = 0;
+ iPtr->evalFlags = 0;
+ iPtr->scriptFile = NULL;
+ iPtr->flags = 0;
+ iPtr->tracePtr = NULL;
+ iPtr->deleteCallbackPtr = NULL;
+ iPtr->resultSpace[0] = 0;
+
+ /*
+ * Create the built-in commands. Do it here, rather than calling
+ * Tcl_CreateCommand, because it's faster (there's no need to
+ * check for a pre-existing command by the same name).
+ */
+
+ for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
+ int new;
+ Tcl_HashEntry *hPtr;
+
+ hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
+ cmdInfoPtr->name, &new);
+ if (new) {
+ cmdPtr = (Command *) ckalloc(sizeof(Command));
+ cmdPtr->proc = cmdInfoPtr->proc;
+ cmdPtr->clientData = (ClientData) NULL;
+ cmdPtr->deleteProc = NULL;
+ cmdPtr->deleteData = (ClientData) NULL;
+ Tcl_SetHashValue(hPtr, cmdPtr);
+ }
+ }
+
+#ifndef TCL_GENERIC_ONLY
+ TclSetupEnv((Tcl_Interp *) iPtr);
+
+ /*
+ * The code below causes SIGPIPE (broken pipe) errors to
+ * be ignored. This is needed so that Tcl processes don't
+ * die if they create child processes (e.g. using "exec" or
+ * "open") that terminate prematurely. The signal handler
+ * is only set up when the first interpreter is created;
+ * after this the application can override the handler with
+ * a different one of its own, if it wants.
+ */
+
+ if (firstInterp) {
+ (void) signal(SIGPIPE, SIG_IGN);
+ firstInterp = 0;
+ }
+#endif
+
+ Tcl_TraceVar2((Tcl_Interp *) iPtr, "tcl_precision", (char *) NULL,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ TclPrecTraceProc, (ClientData) NULL);
+ return (Tcl_Interp *) iPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_Init --
+ *
+ * This procedure is typically invoked by Tcl_AppInit procedures
+ * to perform additional initialization for a Tcl interpreter,
+ * such as sourcing the "init.tcl" script.
+ *
+ * Results:
+ * Returns a standard Tcl completion code and sets interp->result
+ * if there is an error.
+ *
+ * Side effects:
+ * Depends on what's in the init.tcl script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_Init(interp)
+ Tcl_Interp *interp; /* Interpreter to initialize. */
+{
+ static char initCmd[] =
+ "if [file exists [info library]/init.tcl] {\n\
+ source [info library]/init.tcl\n\
+ } else {\n\
+ set msg \"can't find [info library]/init.tcl; perhaps you \"\n\
+ append msg \"need to\\ninstall Tcl or set your TCL_LIBRARY \"\n\
+ append msg \"environment variable?\"\n\
+ error $msg\n\
+ }";
+
+ return Tcl_Eval(interp, initCmd);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tcl_CallWhenDeleted --
+ *
+ * Arrange for a procedure to be called before a given
+ * interpreter is deleted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When Tcl_DeleteInterp is invoked to delete interp,
+ * proc will be invoked. See the manual entry for
+ * details.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+Tcl_CallWhenDeleted(interp, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter to watch. */
+ Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter
+ * is about to be deleted. */
+ ClientData clientData; /* One-word value to pass to proc. */
+{
+ DeleteCallback *dcPtr, *prevPtr;
+ Interp *iPtr = (Interp *) interp;
+
+ dcPtr = (DeleteCallback *) ckalloc(sizeof(DeleteCallback));
+ dcPtr->proc = proc;
+ dcPtr->clientData = clientData;
+ dcPtr->nextPtr = NULL;
+ if (iPtr->deleteCallbackPtr == NULL) {
+ iPtr->deleteCallbackPtr = dcPtr;
+ } else {
+ prevPtr = iPtr->deleteCallbackPtr;
+ while (prevPtr->nextPtr != NULL) {
+ prevPtr = prevPtr->nextPtr;
+ }
+ prevPtr->nextPtr = dcPtr;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tcl_DontCallWhenDeleted --
+ *
+ * Cancel the arrangement for a procedure to be called when
+ * a given interpreter is deleted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If proc and clientData were previously registered as a
+ * callback via Tcl_CallWhenDeleted, they are unregistered.
+ * If they weren't previously registered then nothing
+ * happens.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+Tcl_DontCallWhenDeleted(interp, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter to watch. */
+ Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter
+ * is about to be deleted. */
+ ClientData clientData; /* One-word value to pass to proc. */
+{
+ DeleteCallback *prevPtr, *dcPtr;
+ Interp *iPtr = (Interp *) interp;
+
+ for (prevPtr = NULL, dcPtr = iPtr->deleteCallbackPtr;
+ dcPtr != NULL; prevPtr = dcPtr, dcPtr = dcPtr->nextPtr) {
+ if ((dcPtr->proc != proc) || (dcPtr->clientData != clientData)) {
+ continue;
+ }
+ if (prevPtr == NULL) {
+ iPtr->deleteCallbackPtr = dcPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = dcPtr->nextPtr;
+ }
+ ckfree((char *) dcPtr);
+ break;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteInterp --
+ *
+ * Delete an interpreter and free up all of the resources associated
+ * with it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The interpreter is destroyed. The caller should never again
+ * use the interp token.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DeleteInterp(interp)
+ Tcl_Interp *interp; /* Token for command interpreter (returned
+ * by a previous call to Tcl_CreateInterp). */
+{
+ Interp *iPtr = (Interp *) interp;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ register Command *cmdPtr;
+ DeleteCallback *dcPtr;
+ int i;
+
+ /*
+ * If the interpreter is in use, delay the deletion until later.
+ */
+
+ iPtr->flags |= DELETED;
+ if (iPtr->numLevels != 0) {
+ return;
+ }
+
+ /*
+ * Invoke deletion callbacks.
+ */
+
+ while (iPtr->deleteCallbackPtr != NULL) {
+ dcPtr = iPtr->deleteCallbackPtr;
+ iPtr->deleteCallbackPtr = dcPtr->nextPtr;
+ (*dcPtr->proc)(dcPtr->clientData, interp);
+ ckfree((char *) dcPtr);
+ }
+
+ /*
+ * Free up any remaining resources associated with the
+ * interpreter.
+ */
+
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ if (cmdPtr->deleteProc != NULL) {
+ (*cmdPtr->deleteProc)(cmdPtr->deleteData);
+ }
+ ckfree((char *) cmdPtr);
+ }
+ Tcl_DeleteHashTable(&iPtr->commandTable);
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->mathFuncTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ ckfree((char *) Tcl_GetHashValue(hPtr));
+ }
+ Tcl_DeleteHashTable(&iPtr->mathFuncTable);
+ TclDeleteVars(iPtr, &iPtr->globalTable);
+
+ /*
+ * Free up the result *after* deleting variables, since variable
+ * deletion could have transferred ownership of the result string
+ * to Tcl.
+ */
+
+ Tcl_FreeResult(interp);
+ if (iPtr->errorInfo != NULL) {
+ ckfree(iPtr->errorInfo);
+ }
+ if (iPtr->errorCode != NULL) {
+ ckfree(iPtr->errorCode);
+ }
+ if (iPtr->events != NULL) {
+ int i;
+
+ for (i = 0; i < iPtr->numEvents; i++) {
+ ckfree(iPtr->events[i].command);
+ }
+ ckfree((char *) iPtr->events);
+ }
+ while (iPtr->revPtr != NULL) {
+ HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
+
+ ckfree((char *) iPtr->revPtr);
+ iPtr->revPtr = nextPtr;
+ }
+ if (iPtr->appendResult != NULL) {
+ ckfree(iPtr->appendResult);
+ }
+ for (i = 0; i < NUM_REGEXPS; i++) {
+ if (iPtr->patterns[i] == NULL) {
+ break;
+ }
+ ckfree(iPtr->patterns[i]);
+ ckfree((char *) iPtr->regexps[i]);
+ }
+ while (iPtr->tracePtr != NULL) {
+ Trace *nextPtr = iPtr->tracePtr->nextPtr;
+
+ ckfree((char *) iPtr->tracePtr);
+ iPtr->tracePtr = nextPtr;
+ }
+ ckfree((char *) iPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreateCommand --
+ *
+ * Define a new command in a command table.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If a command named cmdName already exists for interp, it is
+ * deleted. In the future, when cmdName is seen as the name of
+ * a command by Tcl_Eval, proc will be called. When the command
+ * is deleted from the table, deleteProc will be called. See the
+ * manual entry for details on the calling sequence.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
+ Tcl_Interp *interp; /* Token for command interpreter (returned
+ * by a previous call to Tcl_CreateInterp). */
+ char *cmdName; /* Name of command. */
+ Tcl_CmdProc *proc; /* Command procedure to associate with
+ * cmdName. */
+ ClientData clientData; /* Arbitrary one-word value to pass to proc. */
+ Tcl_CmdDeleteProc *deleteProc;
+ /* If not NULL, gives a procedure to call when
+ * this command is deleted. */
+{
+ Interp *iPtr = (Interp *) interp;
+ register Command *cmdPtr;
+ Tcl_HashEntry *hPtr;
+ int new;
+
+ hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
+ if (!new) {
+ /*
+ * Command already exists: delete the old one.
+ */
+
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ if (cmdPtr->deleteProc != NULL) {
+ (*cmdPtr->deleteProc)(cmdPtr->deleteData);
+ }
+ } else {
+ cmdPtr = (Command *) ckalloc(sizeof(Command));
+ Tcl_SetHashValue(hPtr, cmdPtr);
+ }
+ cmdPtr->proc = proc;
+ cmdPtr->clientData = clientData;
+ cmdPtr->deleteProc = deleteProc;
+ cmdPtr->deleteData = clientData;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetCommandInfo --
+ *
+ * Modifies various information about a Tcl command.
+ *
+ * Results:
+ * If cmdName exists in interp, then the information at *infoPtr
+ * is stored with the command in place of the current information
+ * and 1 is returned. If the command doesn't exist then 0 is
+ * returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_SetCommandInfo(interp, cmdName, infoPtr)
+ Tcl_Interp *interp; /* Interpreter in which to look
+ * for command. */
+ char *cmdName; /* Name of desired command. */
+ Tcl_CmdInfo *infoPtr; /* Where to store information about
+ * command. */
+{
+ Tcl_HashEntry *hPtr;
+ Command *cmdPtr;
+
+ hPtr = Tcl_FindHashEntry(&((Interp *) interp)->commandTable, cmdName);
+ if (hPtr == NULL) {
+ return 0;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ cmdPtr->proc = infoPtr->proc;
+ cmdPtr->clientData = infoPtr->clientData;
+ cmdPtr->deleteProc = infoPtr->deleteProc;
+ cmdPtr->deleteData = infoPtr->deleteData;
+ return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetCommandInfo --
+ *
+ * Returns various information about a Tcl command.
+ *
+ * Results:
+ * If cmdName exists in interp, then *infoPtr is modified to
+ * hold information about cmdName and 1 is returned. If the
+ * command doesn't exist then 0 is returned and *infoPtr isn't
+ * modified.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetCommandInfo(interp, cmdName, infoPtr)
+ Tcl_Interp *interp; /* Interpreter in which to look
+ * for command. */
+ char *cmdName; /* Name of desired command. */
+ Tcl_CmdInfo *infoPtr; /* Where to store information about
+ * command. */
+{
+ Tcl_HashEntry *hPtr;
+ Command *cmdPtr;
+
+ hPtr = Tcl_FindHashEntry(&((Interp *) interp)->commandTable, cmdName);
+ if (hPtr == NULL) {
+ return 0;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ infoPtr->proc = cmdPtr->proc;
+ infoPtr->clientData = cmdPtr->clientData;
+ infoPtr->deleteProc = cmdPtr->deleteProc;
+ infoPtr->deleteData = cmdPtr->deleteData;
+ return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteCommand --
+ *
+ * Remove the given command from the given interpreter.
+ *
+ * Results:
+ * 0 is returned if the command was deleted successfully.
+ * -1 is returned if there didn't exist a command by that
+ * name.
+ *
+ * Side effects:
+ * CmdName will no longer be recognized as a valid command for
+ * interp.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_DeleteCommand(interp, cmdName)
+ Tcl_Interp *interp; /* Token for command interpreter (returned
+ * by a previous call to Tcl_CreateInterp). */
+ char *cmdName; /* Name of command to remove. */
+{
+ Interp *iPtr = (Interp *) interp;
+ Tcl_HashEntry *hPtr;
+ Command *cmdPtr;
+
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
+ if (hPtr == NULL) {
+ return -1;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ if (cmdPtr->deleteProc != NULL) {
+ (*cmdPtr->deleteProc)(cmdPtr->deleteData);
+ }
+ ckfree((char *) cmdPtr);
+ Tcl_DeleteHashEntry(hPtr);
+ return 0;
+}
+
+/*
+ *-----------------------------------------------------------------
+ *
+ * Tcl_Eval --
+ *
+ * Parse and execute a command in the Tcl language.
+ *
+ * Results:
+ * The return value is one of the return codes defined in tcl.hd
+ * (such as TCL_OK), and interp->result contains a string value
+ * to supplement the return code. The value of interp->result
+ * will persist only until the next call to Tcl_Eval: copy it or
+ * lose it! *TermPtr is filled in with the character just after
+ * the last one that was part of the command (usually a NULL
+ * character or a closing bracket).
+ *
+ * Side effects:
+ * Almost certainly; depends on the command.
+ *
+ *-----------------------------------------------------------------
+ */
+
+int
+Tcl_Eval(interp, cmd)
+ Tcl_Interp *interp; /* Token for command interpreter (returned
+ * by a previous call to Tcl_CreateInterp). */
+ char *cmd; /* Pointer to TCL command to interpret. */
+{
+ /*
+ * The storage immediately below is used to generate a copy
+ * of the command, after all argument substitutions. Pv will
+ * contain the argv values passed to the command procedure.
+# define NUM_CHARS 1024
+ */
+
+# define NUM_CHARS 200
+ char copyStorage[NUM_CHARS];
+ ParseValue pv;
+ char *oldBuffer;
+
+ /*
+ * This procedure generates an (argv, argc) array for the command,
+ * It starts out with stack-allocated space but uses dynamically-
+ * allocated storage to increase it if needed.
+ */
+
+# define NUM_ARGS 10
+ char *(argStorage[NUM_ARGS]);
+ char **argv = argStorage;
+ int argc;
+ int argSize = NUM_ARGS;
+
+ register char *src; /* Points to current character
+ * in cmd. */
+ char termChar; /* Return when this character is found
+ * (either ']' or '\0'). Zero means
+ * that newlines terminate commands. */
+ int flags; /* Interp->evalFlags value when the
+ * procedure was called. */
+ int result; /* Return value. */
+ register Interp *iPtr = (Interp *) interp;
+ Tcl_HashEntry *hPtr;
+ Command *cmdPtr;
+ char *termPtr; /* Contains character just after the
+ * last one in the command. */
+ char *cmdStart; /* Points to first non-blank char. in
+ * command (used in calling trace
+ * procedures). */
+ char *ellipsis = ""; /* Used in setting errorInfo variable;
+ * set to "..." to indicate that not
+ * all of offending command is included
+ * in errorInfo. "" means that the
+ * command is all there. */
+ register Trace *tracePtr;
+
+ /*
+ * Initialize the result to an empty string and clear out any
+ * error information. This makes sure that we return an empty
+ * result if there are no commands in the command string.
+ */
+
+ Tcl_FreeResult((Tcl_Interp *) iPtr);
+ iPtr->result = iPtr->resultSpace;
+ iPtr->resultSpace[0] = 0;
+ result = TCL_OK;
+
+ /*
+ * Initialize the area in which command copies will be assembled.
+ */
+
+ pv.buffer = copyStorage;
+ pv.end = copyStorage + NUM_CHARS - 1;
+ pv.expandProc = TclExpandParseValue;
+ pv.clientData = (ClientData) NULL;
+
+ src = cmd;
+ flags = iPtr->evalFlags;
+ iPtr->evalFlags = 0;
+ if (flags & TCL_BRACKET_TERM) {
+ termChar = ']';
+ } else {
+ termChar = 0;
+ }
+ termPtr = src;
+ cmdStart = src;
+
+ /*
+ * Check depth of nested calls to Tcl_Eval: if this gets too large,
+ * it's probably because of an infinite loop somewhere.
+ */
+
+ iPtr->numLevels++;
+ if (iPtr->numLevels > iPtr->maxNestingDepth) {
+ iPtr->numLevels--;
+ iPtr->result = "too many nested calls to Tcl_Eval (infinite loop?)";
+ iPtr->termPtr = termPtr;
+ return TCL_ERROR;
+ }
+
+ /*
+ * There can be many sub-commands (separated by semi-colons or
+ * newlines) in one command string. This outer loop iterates over
+ * individual commands.
+ */
+
+ while (*src != termChar) {
+ iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
+
+ /*
+ * Skim off leading white space and semi-colons, and skip
+ * comments.
+ */
+
+ while (1) {
+ register char c = *src;
+
+ if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
+ break;
+ }
+ src += 1;
+ }
+ if (*src == '#') {
+ for (src++; *src != 0; src++) {
+ if ((*src == '\n') && (src[-1] != '\\')) {
+ src++;
+ break;
+ }
+ }
+ continue;
+ }
+ cmdStart = src;
+
+ /*
+ * Parse the words of the command, generating the argc and
+ * argv for the command procedure. May have to call
+ * TclParseWords several times, expanding the argv array
+ * between calls.
+ */
+
+ pv.next = oldBuffer = pv.buffer;
+ argc = 0;
+ while (1) {
+ int newArgs, maxArgs;
+ char **newArgv;
+ int i;
+
+ /*
+ * Note: the "- 2" below guarantees that we won't use the
+ * last two argv slots here. One is for a NULL pointer to
+ * mark the end of the list, and the other is to leave room
+ * for inserting the command name "unknown" as the first
+ * argument (see below).
+ */
+
+ maxArgs = argSize - argc - 2;
+ result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
+ maxArgs, &termPtr, &newArgs, &argv[argc], &pv);
+ src = termPtr;
+ if (result != TCL_OK) {
+ ellipsis = "...";
+ goto done;
+ }
+
+ /*
+ * Careful! Buffer space may have gotten reallocated while
+ * parsing words. If this happened, be sure to update all
+ * of the older argv pointers to refer to the new space.
+ */
+
+ if (oldBuffer != pv.buffer) {
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ argv[i] = pv.buffer + (argv[i] - oldBuffer);
+ }
+ oldBuffer = pv.buffer;
+ }
+ argc += newArgs;
+ if (newArgs < maxArgs) {
+ argv[argc] = (char *) NULL;
+ break;
+ }
+
+ /*
+ * Args didn't all fit in the current array. Make it bigger.
+ */
+
+ argSize *= 2;
+ newArgv = (char **)
+ ckalloc((unsigned) argSize * sizeof(char *));
+ for (i = 0; i < argc; i++) {
+ newArgv[i] = argv[i];
+ }
+ if (argv != argStorage) {
+ ckfree((char *) argv);
+ }
+ argv = newArgv;
+ }
+
+ /*
+ * If this is an empty command (or if we're just parsing
+ * commands without evaluating them), then just skip to the
+ * next command.
+ */
+
+ if ((argc == 0) || iPtr->noEval) {
+ continue;
+ }
+ argv[argc] = NULL;
+
+ /*
+ * Save information for the history module, if needed.
+ */
+
+ if (flags & TCL_RECORD_BOUNDS) {
+ iPtr->evalFirst = cmdStart;
+ iPtr->evalLast = src-1;
+ }
+
+ /*
+ * Find the procedure to execute this command. If there isn't
+ * one, then see if there is a command "unknown". If so,
+ * invoke it instead, passing it the words of the original
+ * command as arguments.
+ */
+
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
+ if (hPtr == NULL) {
+ int i;
+
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
+ if (hPtr == NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "invalid command name: \"",
+ argv[0], "\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ for (i = argc; i >= 0; i--) {
+ argv[i+1] = argv[i];
+ }
+ argv[0] = "unknown";
+ argc++;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+
+ /*
+ * Call trace procedures, if any.
+ */
+
+ for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
+ tracePtr = tracePtr->nextPtr) {
+ char saved;
+
+ if (tracePtr->level < iPtr->numLevels) {
+ continue;
+ }
+ saved = *src;
+ *src = 0;
+ (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
+ cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
+ *src = saved;
+ }
+
+ /*
+ * At long last, invoke the command procedure. Reset the
+ * result to its default empty value first (it could have
+ * gotten changed by earlier commands in the same command
+ * string).
+ */
+
+ iPtr->cmdCount++;
+ Tcl_FreeResult(iPtr);
+ iPtr->result = iPtr->resultSpace;
+ iPtr->resultSpace[0] = 0;
+ result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
+ if (tcl_AsyncReady) {
+ result = Tcl_AsyncInvoke(interp, result);
+ }
+ if (result != TCL_OK) {
+ break;
+ }
+ }
+
+ /*
+ * Free up any extra resources that were allocated.
+ */
+
+ done:
+ if (pv.buffer != copyStorage) {
+ ckfree((char *) pv.buffer);
+ }
+ if (argv != argStorage) {
+ ckfree((char *) argv);
+ }
+ iPtr->numLevels--;
+ if (iPtr->numLevels == 0) {
+ if (result == TCL_RETURN) {
+ result = TCL_OK;
+ }
+ if ((result != TCL_OK) && (result != TCL_ERROR)) {
+ Tcl_ResetResult(interp);
+ if (result == TCL_BREAK) {
+ iPtr->result = "invoked \"break\" outside of a loop";
+ } else if (result == TCL_CONTINUE) {
+ iPtr->result = "invoked \"continue\" outside of a loop";
+ } else {
+ iPtr->result = iPtr->resultSpace;
+ sprintf(iPtr->resultSpace, "command returned bad code: %d",
+ result);
+ }
+ result = TCL_ERROR;
+ }
+ if (iPtr->flags & DELETED) {
+ Tcl_DeleteInterp(interp);
+ }
+ }
+
+ /*
+ * If an error occurred, record information about what was being
+ * executed when the error occurred.
+ */
+
+ if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
+ int numChars;
+ register char *p;
+
+ /*
+ * Compute the line number where the error occurred.
+ */
+
+ iPtr->errorLine = 1;
+ for (p = cmd; p != cmdStart; p++) {
+ if (*p == '\n') {
+ iPtr->errorLine++;
+ }
+ }
+ for ( ; isspace(UCHAR(*p)) || (*p == ';'); p++) {
+ if (*p == '\n') {
+ iPtr->errorLine++;
+ }
+ }
+
+ /*
+ * Figure out how much of the command to print in the error
+ * message (up to a certain number of characters, or up to
+ * the first new-line).
+ */
+
+ numChars = src - cmdStart;
+ if (numChars > (NUM_CHARS-50)) {
+ numChars = NUM_CHARS-50;
+ ellipsis = " ...";
+ }
+
+ if (!(iPtr->flags & ERR_IN_PROGRESS)) {
+ sprintf(copyStorage, "\n while executing\n\"%.*s%s\"",
+ numChars, cmdStart, ellipsis);
+ } else {
+ sprintf(copyStorage, "\n invoked from within\n\"%.*s%s\"",
+ numChars, cmdStart, ellipsis);
+ }
+ Tcl_AddErrorInfo(interp, copyStorage);
+ iPtr->flags &= ~ERR_ALREADY_LOGGED;
+ } else {
+ iPtr->flags &= ~ERR_ALREADY_LOGGED;
+ }
+ iPtr->termPtr = termPtr;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreateTrace --
+ *
+ * Arrange for a procedure to be called to trace command execution.
+ *
+ * Results:
+ * The return value is a token for the trace, which may be passed
+ * to Tcl_DeleteTrace to eliminate the trace.
+ *
+ * Side effects:
+ * From now on, proc will be called just before a command procedure
+ * is called to execute a Tcl command. Calls to proc will have the
+ * following form:
+ *
+ * void
+ * proc(clientData, interp, level, command, cmdProc, cmdClientData,
+ * argc, argv)
+ * ClientData clientData;
+ * Tcl_Interp *interp;
+ * int level;
+ * char *command;
+ * int (*cmdProc)();
+ * ClientData cmdClientData;
+ * int argc;
+ * char **argv;
+ * {
+ * }
+ *
+ * The clientData and interp arguments to proc will be the same
+ * as the corresponding arguments to this procedure. Level gives
+ * the nesting level of command interpretation for this interpreter
+ * (0 corresponds to top level). Command gives the ASCII text of
+ * the raw command, cmdProc and cmdClientData give the procedure that
+ * will be called to process the command and the ClientData value it
+ * will receive, and argc and argv give the arguments to the
+ * command, after any argument parsing and substitution. Proc
+ * does not return a value.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_Trace
+Tcl_CreateTrace(interp, level, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter in which to create the trace. */
+ int level; /* Only call proc for commands at nesting level
+ * <= level (1 => top level). */
+ Tcl_CmdTraceProc *proc; /* Procedure to call before executing each
+ * command. */
+ ClientData clientData; /* Arbitrary one-word value to pass to proc. */
+{
+ register Trace *tracePtr;
+ register Interp *iPtr = (Interp *) interp;
+
+ tracePtr = (Trace *) ckalloc(sizeof(Trace));
+ tracePtr->level = level;
+ tracePtr->proc = proc;
+ tracePtr->clientData = clientData;
+ tracePtr->nextPtr = iPtr->tracePtr;
+ iPtr->tracePtr = tracePtr;
+
+ return (Tcl_Trace) tracePtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteTrace --
+ *
+ * Remove a trace.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * From now on there will be no more calls to the procedure given
+ * in trace.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DeleteTrace(interp, trace)
+ Tcl_Interp *interp; /* Interpreter that contains trace. */
+ Tcl_Trace trace; /* Token for trace (returned previously by
+ * Tcl_CreateTrace). */
+{
+ register Interp *iPtr = (Interp *) interp;
+ register Trace *tracePtr = (Trace *) trace;
+ register Trace *tracePtr2;
+
+ if (iPtr->tracePtr == tracePtr) {
+ iPtr->tracePtr = tracePtr->nextPtr;
+ ckfree((char *) tracePtr);
+ } else {
+ for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
+ tracePtr2 = tracePtr2->nextPtr) {
+ if (tracePtr2->nextPtr == tracePtr) {
+ tracePtr2->nextPtr = tracePtr->nextPtr;
+ ckfree((char *) tracePtr);
+ return;
+ }
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AddErrorInfo --
+ *
+ * Add information to a message being accumulated that describes
+ * the current error.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The contents of message are added to the "errorInfo" variable.
+ * If Tcl_Eval has been called since the current value of errorInfo
+ * was set, errorInfo is cleared before adding the new message.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AddErrorInfo(interp, message)
+ Tcl_Interp *interp; /* Interpreter to which error information
+ * pertains. */
+ char *message; /* Message to record. */
+{
+ register Interp *iPtr = (Interp *) interp;
+
+ /*
+ * If an error is already being logged, then the new errorInfo
+ * is the concatenation of the old info and the new message.
+ * If this is the first piece of info for the error, then the
+ * new errorInfo is the concatenation of the message in
+ * interp->result and the new message.
+ */
+
+ if (!(iPtr->flags & ERR_IN_PROGRESS)) {
+ Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
+ TCL_GLOBAL_ONLY);
+ iPtr->flags |= ERR_IN_PROGRESS;
+
+ /*
+ * If the errorCode variable wasn't set by the code that generated
+ * the error, set it to "NONE".
+ */
+
+ if (!(iPtr->flags & ERROR_CODE_SET)) {
+ (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
+ TCL_GLOBAL_ONLY);
+ }
+ }
+ Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
+ TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_VarEval --
+ *
+ * Given a variable number of string arguments, concatenate them
+ * all together and execute the result as a Tcl command.
+ *
+ * Results:
+ * A standard Tcl return result. An error message or other
+ * result may be left in interp->result.
+ *
+ * Side effects:
+ * Depends on what was done by the command.
+ *
+ *----------------------------------------------------------------------
+ */
+ /* VARARGS2 */ /* ARGSUSED */
+int
+#ifdef USE_STDARG
+Tcl_VarEval(Tcl_Interp *iPtr, ...)
+#else
+
+#ifndef lint
+Tcl_VarEval(va_alist)
+#else
+Tcl_VarEval(iPtr, p, va_alist)
+ Tcl_Interp *iPtr; /* Interpreter in which to execute command. */
+ char *p; /* One or more strings to concatenate,
+ * terminated with a NULL string. */
+#endif
+
+ va_dcl
+#endif
+{
+ va_list argList;
+
+#define FIXED_SIZE 200
+ char fixedSpace[FIXED_SIZE+1];
+ int spaceAvl, spaceUsed, length;
+ char *string, *cmd;
+ Tcl_Interp *interp = iPtr;
+ int result;
+
+ /*
+ * Copy the strings one after the other into a single larger
+ * string. Use stack-allocated space for small commands, but if
+ * the command gets too large than call ckalloc to create the
+ * space.
+ */
+
+#ifdef USE_STDARG
+ va_start(argList, iPtr);
+#else
+ va_start(argList);
+ (void) va_arg(argList, Tcl_Interp *);
+#endif
+ spaceAvl = FIXED_SIZE;
+ spaceUsed = 0;
+ cmd = fixedSpace;
+ while (1) {
+ string = va_arg(argList, char *);
+ if (string == NULL) {
+ break;
+ }
+ length = strlen(string);
+ if ((spaceUsed + length) > spaceAvl) {
+ char *new;
+
+ spaceAvl = spaceUsed + length;
+ spaceAvl += spaceAvl/2;
+ new = ckalloc((unsigned) spaceAvl);
+ memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
+ if (cmd != fixedSpace) {
+ ckfree(cmd);
+ }
+ cmd = new;
+ }
+ strcpy(cmd + spaceUsed, string);
+ spaceUsed += length;
+ }
+ va_end(argList);
+ cmd[spaceUsed] = '\0';
+
+ result = Tcl_Eval(interp, cmd);
+ if (cmd != fixedSpace) {
+ ckfree(cmd);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GlobalEval --
+ *
+ * Evaluate a command at global level in an interpreter.
+ *
+ * Results:
+ * A standard Tcl result is returned, and interp->result is
+ * modified accordingly.
+ *
+ * Side effects:
+ * The command string is executed in interp, and the execution
+ * is carried out in the variable context of global level (no
+ * procedures active), just as if an "uplevel #0" command were
+ * being executed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GlobalEval(interp, command)
+ Tcl_Interp *interp; /* Interpreter in which to evaluate command. */
+ char *command; /* Command to evaluate. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int result;
+ CallFrame *savedVarFramePtr;
+
+ savedVarFramePtr = iPtr->varFramePtr;
+ iPtr->varFramePtr = NULL;
+ result = Tcl_Eval(interp, command);
+ iPtr->varFramePtr = savedVarFramePtr;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetRecursionLimit --
+ *
+ * Set the maximum number of recursive calls that may be active
+ * for an interpreter at once.
+ *
+ * Results:
+ * The return value is the old limit on nesting for interp.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_SetRecursionLimit(interp, depth)
+ Tcl_Interp *interp; /* Interpreter whose nesting limit
+ * is to be set. */
+ int depth; /* New value for maximimum depth. */
+{
+ Interp *iPtr = (Interp *) interp;
+ int old;
+
+ old = iPtr->maxNestingDepth;
+ if (depth > 0) {
+ iPtr->maxNestingDepth = depth;
+ }
+ return old;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclCkalloc.c b/vendor/x11iraf/obm/Tcl/tclCkalloc.c
new file mode 100644
index 00000000..6f049224
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclCkalloc.c
@@ -0,0 +1,607 @@
+/*
+ * tclCkalloc.c --
+ * Interface to malloc and free that provides support for debugging problems
+ * involving overwritten, double freeing memory and loss of memory.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * This code contributed by Karl Lehenbauer and Mark Diekhans
+ *
+ */
+
+#include "tclInt.h"
+
+#define FALSE 0
+#define TRUE 1
+
+#ifdef TCL_MEM_DEBUG
+#ifndef TCL_GENERIC_ONLY
+#include "tclUnix.h"
+#endif
+
+#define GUARD_SIZE 8
+
+struct mem_header {
+ long length;
+ char *file;
+ int line;
+ struct mem_header *flink;
+ struct mem_header *blink;
+ int dummy; /* Aligns body on 8-byte boundary. */
+ unsigned char low_guard[GUARD_SIZE];
+ char body[1];
+};
+
+static struct mem_header *allocHead = NULL; /* List of allocated structures */
+
+#define GUARD_VALUE 0341
+
+/* static char high_guard[] = {0x89, 0xab, 0xcd, 0xef}; */
+
+static int total_mallocs = 0;
+static int total_frees = 0;
+static int current_bytes_malloced = 0;
+static int maximum_bytes_malloced = 0;
+static int current_malloc_packets = 0;
+static int maximum_malloc_packets = 0;
+static int break_on_malloc = 0;
+static int trace_on_at_malloc = 0;
+static int alloc_tracing = FALSE;
+static int init_malloced_bodies = TRUE;
+#ifdef MEM_VALIDATE
+ static int validate_memory = TRUE;
+#else
+ static int validate_memory = FALSE;
+#endif
+
+/*
+ * Prototypes for procedures defined in this file:
+ */
+
+static int MemoryCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * dump_memory_info --
+ * Display the global memory management statistics.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+dump_memory_info(outFile)
+ FILE *outFile;
+{
+ fprintf(outFile,"total mallocs %10d\n",
+ total_mallocs);
+ fprintf(outFile,"total frees %10d\n",
+ total_frees);
+ fprintf(outFile,"current packets allocated %10d\n",
+ current_malloc_packets);
+ fprintf(outFile,"current bytes allocated %10d\n",
+ current_bytes_malloced);
+ fprintf(outFile,"maximum packets allocated %10d\n",
+ maximum_malloc_packets);
+ fprintf(outFile,"maximum bytes allocated %10d\n",
+ maximum_bytes_malloced);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ValidateMemory --
+ * Procedure to validate allocted memory guard zones.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ValidateMemory (memHeaderP, file, line, nukeGuards)
+ struct mem_header *memHeaderP;
+ char *file;
+ int line;
+ int nukeGuards;
+{
+ unsigned char *hiPtr;
+ int idx;
+ int guard_failed = FALSE;
+ int byte;
+
+ for (idx = 0; idx < GUARD_SIZE; idx++) {
+ byte = *(memHeaderP->low_guard + idx);
+ if (byte != GUARD_VALUE) {
+ guard_failed = TRUE;
+ fflush (stdout);
+ byte &= 0xff;
+ fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", idx, byte,
+ (isprint(UCHAR(byte)) ? byte : ' '));
+ }
+ }
+ if (guard_failed) {
+ dump_memory_info (stderr);
+ fprintf (stderr, "low guard failed at %lx, %s %d\n",
+ memHeaderP->body, file, line);
+ fflush (stderr); /* In case name pointer is bad. */
+ fprintf (stderr, "%d bytes allocated at (%s %d)\n", memHeaderP->length,
+ memHeaderP->file, memHeaderP->line);
+ panic ("Memory validation failure");
+ }
+
+ hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
+ for (idx = 0; idx < GUARD_SIZE; idx++) {
+ byte = *(hiPtr + idx);
+ if (byte != GUARD_VALUE) {
+ guard_failed = TRUE;
+ fflush (stdout);
+ byte &= 0xff;
+ fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", idx, byte,
+ (isprint(UCHAR(byte)) ? byte : ' '));
+ }
+ }
+
+ if (guard_failed) {
+ dump_memory_info (stderr);
+ fprintf (stderr, "high guard failed at %lx, %s %d\n",
+ memHeaderP->body, file, line);
+ fflush (stderr); /* In case name pointer is bad. */
+ fprintf (stderr, "%d bytes allocated at (%s %d)\n", memHeaderP->length,
+ memHeaderP->file, memHeaderP->line);
+ panic ("Memory validation failure");
+ }
+
+ if (nukeGuards) {
+ memset ((char *) memHeaderP->low_guard, 0, GUARD_SIZE);
+ memset ((char *) hiPtr, 0, GUARD_SIZE);
+ }
+
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ValidateAllMemory --
+ * Validates guard regions for all allocated memory.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Tcl_ValidateAllMemory (file, line)
+ char *file;
+ int line;
+{
+ struct mem_header *memScanP;
+
+ for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink)
+ ValidateMemory (memScanP, file, line, FALSE);
+
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DumpActiveMemory --
+ * Displays all allocated memory to stderr.
+ *
+ * Results:
+ * Return TCL_ERROR if an error accessing the file occures, `errno'
+ * will have the file error number left in it.
+ *----------------------------------------------------------------------
+ */
+int
+Tcl_DumpActiveMemory (fileName)
+ char *fileName;
+{
+ FILE *fileP;
+ struct mem_header *memScanP;
+ char *address;
+
+ fileP = fopen (fileName, "w");
+ if (fileP == NULL)
+ return TCL_ERROR;
+
+ for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
+ address = &memScanP->body [0];
+ fprintf (fileP, "%8lx - %8lx %7d @ %s %d", address,
+ address + memScanP->length - 1, memScanP->length,
+ memScanP->file, memScanP->line);
+ (void) fputc('\n', fileP);
+ }
+ fclose (fileP);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DbCkalloc - debugging ckalloc
+ *
+ * Allocate the requested amount of space plus some extra for
+ * guard bands at both ends of the request, plus a size, panicing
+ * if there isn't enough space, then write in the guard bands
+ * and return the address of the space in the middle that the
+ * user asked for.
+ *
+ * The second and third arguments are file and line, these contain
+ * the filename and line number corresponding to the caller.
+ * These are sent by the ckalloc macro; it uses the preprocessor
+ * autodefines __FILE__ and __LINE__.
+ *
+ *----------------------------------------------------------------------
+ */
+char *
+Tcl_DbCkalloc(size, file, line)
+ unsigned int size;
+ char *file;
+ int line;
+{
+ struct mem_header *result;
+
+ if (validate_memory)
+ Tcl_ValidateAllMemory (file, line);
+
+ result = (struct mem_header *)malloc((unsigned)size +
+ sizeof(struct mem_header) + GUARD_SIZE);
+ if (result == NULL) {
+ fflush(stdout);
+ dump_memory_info(stderr);
+ panic("unable to alloc %d bytes, %s line %d", size, file,
+ line);
+ }
+
+ /*
+ * Fill in guard zones and size. Also initialize the contents of
+ * the block with bogus bytes to detect uses of initialized data.
+ * Link into allocated list.
+ */
+ if (init_malloced_bodies) {
+ memset ((VOID *) result, GUARD_VALUE,
+ size + sizeof(struct mem_header) + GUARD_SIZE);
+ } else {
+ memset ((char *) result->low_guard, GUARD_VALUE, GUARD_SIZE);
+ memset (result->body + size, GUARD_VALUE, GUARD_SIZE);
+ }
+ result->length = size;
+ result->file = file;
+ result->line = line;
+ result->flink = allocHead;
+ result->blink = NULL;
+ if (allocHead != NULL)
+ allocHead->blink = result;
+ allocHead = result;
+
+ total_mallocs++;
+ if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
+ (void) fflush(stdout);
+ fprintf(stderr, "reached malloc trace enable point (%d)\n",
+ total_mallocs);
+ fflush(stderr);
+ alloc_tracing = TRUE;
+ trace_on_at_malloc = 0;
+ }
+
+ if (alloc_tracing)
+ fprintf(stderr,"ckalloc %lx %d %s %d\n", result->body, size,
+ file, line);
+
+ if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
+ break_on_malloc = 0;
+ (void) fflush(stdout);
+ fprintf(stderr,"reached malloc break limit (%d)\n",
+ total_mallocs);
+ fprintf(stderr, "program will now enter C debugger\n");
+ (void) fflush(stderr);
+ abort();
+ }
+
+ current_malloc_packets++;
+ if (current_malloc_packets > maximum_malloc_packets)
+ maximum_malloc_packets = current_malloc_packets;
+ current_bytes_malloced += size;
+ if (current_bytes_malloced > maximum_bytes_malloced)
+ maximum_bytes_malloced = current_bytes_malloced;
+
+ return result->body;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DbCkfree - debugging ckfree
+ *
+ * Verify that the low and high guards are intact, and if so
+ * then free the buffer else panic.
+ *
+ * The guards are erased after being checked to catch duplicate
+ * frees.
+ *
+ * The second and third arguments are file and line, these contain
+ * the filename and line number corresponding to the caller.
+ * These are sent by the ckfree macro; it uses the preprocessor
+ * autodefines __FILE__ and __LINE__.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_DbCkfree(ptr, file, line)
+ char * ptr;
+ char *file;
+ int line;
+{
+ struct mem_header *memp = 0; /* Must be zero for size calc */
+
+ /*
+ * Since header ptr is zero, body offset will be size
+ */
+#ifdef _CRAYCOM
+ memp = (struct mem_header *)((char *) ptr - (sizeof(int)*((unsigned)&(memp->body))));
+#else
+ memp = (struct mem_header *)(((char *) ptr) - (int)memp->body);
+#endif
+
+ if (alloc_tracing)
+ fprintf(stderr, "ckfree %lx %ld %s %d\n", memp->body,
+ memp->length, file, line);
+
+ if (validate_memory)
+ Tcl_ValidateAllMemory (file, line);
+
+ ValidateMemory (memp, file, line, TRUE);
+ if (init_malloced_bodies) {
+ memset((VOID *) ptr, GUARD_VALUE, memp->length);
+ }
+
+ total_frees++;
+ current_malloc_packets--;
+ current_bytes_malloced -= memp->length;
+
+ /*
+ * Delink from allocated list
+ */
+ if (memp->flink != NULL)
+ memp->flink->blink = memp->blink;
+ if (memp->blink != NULL)
+ memp->blink->flink = memp->flink;
+ if (allocHead == memp)
+ allocHead = memp->flink;
+ free((char *) memp);
+ return 0;
+}
+
+/*
+ *--------------------------------------------------------------------
+ *
+ * Tcl_DbCkrealloc - debugging ckrealloc
+ *
+ * Reallocate a chunk of memory by allocating a new one of the
+ * right size, copying the old data to the new location, and then
+ * freeing the old memory space, using all the memory checking
+ * features of this package.
+ *
+ *--------------------------------------------------------------------
+ */
+char *
+Tcl_DbCkrealloc(ptr, size, file, line)
+ char *ptr;
+ unsigned int size;
+ char *file;
+ int line;
+{
+ char *new;
+ unsigned int copySize;
+ struct mem_header *memp = 0; /* Must be zero for size calc */
+
+#ifdef _CRAYCOM
+ memp = (struct mem_header *)((char *) ptr - (sizeof(int)*((unsigned)&(memp->body))));
+#else
+ memp = (struct mem_header *)(((char *) ptr) - (int)memp->body);
+#endif
+ copySize = size;
+ if (copySize > memp->length) {
+ copySize = memp->length;
+ }
+ new = Tcl_DbCkalloc(size, file, line);
+ memcpy((VOID *) new, (VOID *) ptr, (int) copySize);
+ Tcl_DbCkfree(ptr, file, line);
+ return(new);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MemoryCmd --
+ * Implements the TCL memory command:
+ * memory info
+ * memory display
+ * break_on_malloc count
+ * trace_on_at_malloc count
+ * trace on|off
+ * validate on|off
+ *
+ * Results:
+ * Standard TCL results.
+ *
+ *----------------------------------------------------------------------
+ */
+ /* ARGSUSED */
+static int
+MemoryCmd (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char **argv;
+{
+ char *fileName;
+ Tcl_DString buffer;
+ int result;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " option [args..]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (strcmp(argv[1],"trace") == 0) {
+ if (argc != 3)
+ goto bad_suboption;
+ alloc_tracing = (strcmp(argv[2],"on") == 0);
+ return TCL_OK;
+ }
+ if (strcmp(argv[1],"init") == 0) {
+ if (argc != 3)
+ goto bad_suboption;
+ init_malloced_bodies = (strcmp(argv[2],"on") == 0);
+ return TCL_OK;
+ }
+ if (strcmp(argv[1],"validate") == 0) {
+ if (argc != 3)
+ goto bad_suboption;
+ validate_memory = (strcmp(argv[2],"on") == 0);
+ return TCL_OK;
+ }
+ if (strcmp(argv[1],"trace_on_at_malloc") == 0) {
+ if (argc != 3)
+ goto argError;
+ if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK)
+ return TCL_ERROR;
+ return TCL_OK;
+ }
+ if (strcmp(argv[1],"break_on_malloc") == 0) {
+ if (argc != 3)
+ goto argError;
+ if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK)
+ return TCL_ERROR;
+ return TCL_OK;
+ }
+
+ if (strcmp(argv[1],"info") == 0) {
+ dump_memory_info(stdout);
+ return TCL_OK;
+ }
+ if (strcmp(argv[1],"active") == 0) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " active file", (char *) NULL);
+ return TCL_ERROR;
+ }
+ fileName = Tcl_TildeSubst(interp, argv[2], &buffer);
+ if (fileName == NULL) {
+ return TCL_ERROR;
+ }
+ result = Tcl_DumpActiveMemory (fileName);
+ Tcl_DStringFree(&buffer);
+ if (result != TCL_OK) {
+ Tcl_AppendResult(interp, "error accessing ", argv[2],
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be info, init, active, break_on_malloc, ",
+ "trace_on_at_malloc, trace, or validate", (char *) NULL);
+ return TCL_ERROR;
+
+argError:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ", argv[1], "count\"", (char *) NULL);
+ return TCL_ERROR;
+
+bad_suboption:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ", argv[1], " on|off\"", (char *) NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_InitMemory --
+ * Initialize the memory command.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Tcl_InitMemory(interp)
+ Tcl_Interp *interp;
+{
+Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData) NULL,
+ (Tcl_CmdDeleteProc *) NULL);
+}
+
+#else
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_Ckalloc --
+ * Interface to malloc when TCL_MEM_DEBUG is disabled. It does check
+ * that memory was actually allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+VOID *
+Tcl_Ckalloc (size)
+ unsigned int size;
+{
+ char *result;
+
+ result = malloc(size);
+ if (result == NULL)
+ panic("unable to alloc %d bytes", size);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TckCkfree --
+ * Interface to free when TCL_MEM_DEBUG is disabled. Done here rather
+ * in the macro to keep some modules from being compiled with
+ * TCL_MEM_DEBUG enabled and some with it disabled.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Tcl_Ckfree (ptr)
+ VOID *ptr;
+{
+ free (ptr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_InitMemory --
+ * Dummy initialization for memory command, which is only available
+ * if TCL_MEM_DEBUG is on.
+ *
+ *----------------------------------------------------------------------
+ */
+ /* ARGSUSED */
+void
+Tcl_InitMemory(interp)
+ Tcl_Interp *interp;
+{
+}
+
+#endif
diff --git a/vendor/x11iraf/obm/Tcl/tclCmdAH.c b/vendor/x11iraf/obm/Tcl/tclCmdAH.c
new file mode 100644
index 00000000..5238804b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclCmdAH.c
@@ -0,0 +1,952 @@
+/*
+ * tclCmdAH.c --
+ *
+ * This file contains the top-level command routines for most of
+ * the Tcl built-in commands whose names begin with the letters
+ * A to H.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdAH.c,v 1.93 93/10/28 16:19:20 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_BreakCmd --
+ *
+ * This procedure is invoked to process the "break" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_BreakCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc != 1) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_BREAK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CaseCmd --
+ *
+ * This procedure is invoked to process the "case" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_CaseCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i, result;
+ int body;
+ char *string;
+ int caseArgc, splitArgs;
+ char **caseArgv;
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " string ?in? patList body ... ?default body?\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ string = argv[1];
+ body = -1;
+ if (strcmp(argv[2], "in") == 0) {
+ i = 3;
+ } else {
+ i = 2;
+ }
+ caseArgc = argc - i;
+ caseArgv = argv + i;
+
+ /*
+ * If all of the pattern/command pairs are lumped into a single
+ * argument, split them out again.
+ */
+
+ splitArgs = 0;
+ if (caseArgc == 1) {
+ result = Tcl_SplitList(interp, caseArgv[0], &caseArgc, &caseArgv);
+ if (result != TCL_OK) {
+ return result;
+ }
+ splitArgs = 1;
+ }
+
+ for (i = 0; i < caseArgc; i += 2) {
+ int patArgc, j;
+ char **patArgv;
+ register char *p;
+
+ if (i == (caseArgc-1)) {
+ interp->result = "extra case pattern with no body";
+ result = TCL_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * Check for special case of single pattern (no list) with
+ * no backslash sequences.
+ */
+
+ for (p = caseArgv[i]; *p != 0; p++) {
+ if (isspace(UCHAR(*p)) || (*p == '\\')) {
+ break;
+ }
+ }
+ if (*p == 0) {
+ if ((*caseArgv[i] == 'd')
+ && (strcmp(caseArgv[i], "default") == 0)) {
+ body = i+1;
+ }
+ if (Tcl_StringMatch(string, caseArgv[i])) {
+ body = i+1;
+ goto match;
+ }
+ continue;
+ }
+
+ /*
+ * Break up pattern lists, then check each of the patterns
+ * in the list.
+ */
+
+ result = Tcl_SplitList(interp, caseArgv[i], &patArgc, &patArgv);
+ if (result != TCL_OK) {
+ goto cleanup;
+ }
+ for (j = 0; j < patArgc; j++) {
+ if (Tcl_StringMatch(string, patArgv[j])) {
+ body = i+1;
+ break;
+ }
+ }
+ ckfree((char *) patArgv);
+ if (j < patArgc) {
+ break;
+ }
+ }
+
+ match:
+ if (body != -1) {
+ result = Tcl_Eval(interp, caseArgv[body]);
+ if (result == TCL_ERROR) {
+ char msg[100];
+ sprintf(msg, "\n (\"%.50s\" arm line %d)", caseArgv[body-1],
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ goto cleanup;
+ }
+
+ /*
+ * Nothing matched: return nothing.
+ */
+
+ result = TCL_OK;
+
+ cleanup:
+ if (splitArgs) {
+ ckfree((char *) caseArgv);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CatchCmd --
+ *
+ * This procedure is invoked to process the "catch" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_CatchCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int result;
+
+ if ((argc != 2) && (argc != 3)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " command ?varName?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ result = Tcl_Eval(interp, argv[1]);
+ if (argc == 3) {
+ if (Tcl_SetVar(interp, argv[2], interp->result, 0) == NULL) {
+ Tcl_SetResult(interp, "couldn't save command result in variable",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ }
+ Tcl_ResetResult(interp);
+ sprintf(interp->result, "%d", result);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ConcatCmd --
+ *
+ * This procedure is invoked to process the "concat" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ConcatCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc >= 2) {
+ interp->result = Tcl_Concat(argc-1, argv+1);
+ interp->freeProc = (Tcl_FreeProc *) free;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ContinueCmd --
+ *
+ * This procedure is invoked to process the "continue" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ContinueCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc != 1) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_CONTINUE;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ErrorCmd --
+ *
+ * This procedure is invoked to process the "error" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ErrorCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Interp *iPtr = (Interp *) interp;
+
+ if ((argc < 2) || (argc > 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " message ?errorInfo? ?errorCode?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if ((argc >= 3) && (argv[2][0] != 0)) {
+ Tcl_AddErrorInfo(interp, argv[2]);
+ iPtr->flags |= ERR_ALREADY_LOGGED;
+ }
+ if (argc == 4) {
+ Tcl_SetVar2(interp, "errorCode", (char *) NULL, argv[3],
+ TCL_GLOBAL_ONLY);
+ iPtr->flags |= ERROR_CODE_SET;
+ }
+ Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_EvalCmd --
+ *
+ * This procedure is invoked to process the "eval" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_EvalCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int result;
+ char *cmd;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " arg ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 2) {
+ result = Tcl_Eval(interp, argv[1]);
+ } else {
+
+ /*
+ * More than one argument: concatenate them together with spaces
+ * between, then evaluate the result.
+ */
+
+ cmd = Tcl_Concat(argc-1, argv+1);
+ result = Tcl_Eval(interp, cmd);
+ ckfree(cmd);
+ }
+ if (result == TCL_ERROR) {
+ char msg[60];
+ sprintf(msg, "\n (\"eval\" body line %d)", interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ExprCmd --
+ *
+ * This procedure is invoked to process the "expr" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ExprCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tcl_DString buffer;
+ int i, result;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " arg ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (argc == 2) {
+ return Tcl_ExprString(interp, argv[1]);
+ }
+ Tcl_DStringInit(&buffer);
+ Tcl_DStringAppend(&buffer, argv[1], -1);
+ for (i = 2; i < argc; i++) {
+ Tcl_DStringAppend(&buffer, " ", 1);
+ Tcl_DStringAppend(&buffer, argv[i], -1);
+ }
+ result = Tcl_ExprString(interp, buffer.string);
+ Tcl_DStringFree(&buffer);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ForCmd --
+ *
+ * This procedure is invoked to process the "for" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ForCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int result, value;
+
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " start test next command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ result = Tcl_Eval(interp, argv[1]);
+ if (result != TCL_OK) {
+ if (result == TCL_ERROR) {
+ Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)");
+ }
+ return result;
+ }
+ while (1) {
+ result = Tcl_ExprBoolean(interp, argv[2], &value);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (!value) {
+ break;
+ }
+ result = Tcl_Eval(interp, argv[4]);
+ if ((result != TCL_OK) && (result != TCL_CONTINUE)) {
+ if (result == TCL_ERROR) {
+ char msg[60];
+ sprintf(msg, "\n (\"for\" body line %d)", interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ break;
+ }
+ result = Tcl_Eval(interp, argv[3]);
+ if (result == TCL_BREAK) {
+ break;
+ } else if (result != TCL_OK) {
+ if (result == TCL_ERROR) {
+ Tcl_AddErrorInfo(interp, "\n (\"for\" loop-end command)");
+ }
+ return result;
+ }
+ }
+ if (result == TCL_BREAK) {
+ result = TCL_OK;
+ }
+ if (result == TCL_OK) {
+ Tcl_ResetResult(interp);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ForeachCmd --
+ *
+ * This procedure is invoked to process the "foreach" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ForeachCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int listArgc, i, result;
+ char **listArgv;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " varName list command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Break the list up into elements, and execute the command once
+ * for each value of the element.
+ */
+
+ result = Tcl_SplitList(interp, argv[2], &listArgc, &listArgv);
+ if (result != TCL_OK) {
+ return result;
+ }
+ for (i = 0; i < listArgc; i++) {
+ if (Tcl_SetVar(interp, argv[1], listArgv[i], 0) == NULL) {
+ Tcl_SetResult(interp, "couldn't set loop variable", TCL_STATIC);
+ result = TCL_ERROR;
+ break;
+ }
+
+ result = Tcl_Eval(interp, argv[3]);
+ if (result != TCL_OK) {
+ if (result == TCL_CONTINUE) {
+ result = TCL_OK;
+ } else if (result == TCL_BREAK) {
+ result = TCL_OK;
+ break;
+ } else if (result == TCL_ERROR) {
+ char msg[100];
+ sprintf(msg, "\n (\"foreach\" body line %d)",
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ ckfree((char *) listArgv);
+ if (result == TCL_OK) {
+ Tcl_ResetResult(interp);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FormatCmd --
+ *
+ * This procedure is invoked to process the "format" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_FormatCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register char *format; /* Used to read characters from the format
+ * string. */
+ char newFormat[40]; /* A new format specifier is generated here. */
+ int width; /* Field width from field specifier, or 0 if
+ * no width given. */
+ int precision; /* Field precision from field specifier, or 0
+ * if no precision given. */
+ int size; /* Number of bytes needed for result of
+ * conversion, based on type of conversion
+ * ("e", "s", etc.) and width from above. */
+ char *oneWordValue = NULL; /* Used to hold value to pass to sprintf, if
+ * it's a one-word value. */
+ double twoWordValue; /* Used to hold value to pass to sprintf if
+ * it's a two-word value. */
+ int useTwoWords; /* 0 means use oneWordValue, 1 means use
+ * twoWordValue. */
+ char *dst = interp->result; /* Where result is stored. Starts off at
+ * interp->resultSpace, but may get dynamically
+ * re-allocated if this isn't enough. */
+ int dstSize = 0; /* Number of non-null characters currently
+ * stored at dst. */
+ int dstSpace = TCL_RESULT_SIZE;
+ /* Total amount of storage space available
+ * in dst (not including null terminator. */
+ int noPercent; /* Special case for speed: indicates there's
+ * no field specifier, just a string to copy. */
+ int argIndex; /* Index of argument to substitute next. */
+ int gotXpg = 0; /* Non-zero means that an XPG3 %n$-style
+ * specifier has been seen. */
+ int gotSequential = 0; /* Non-zero means that a regular sequential
+ * (non-XPG3) conversion specifier has been
+ * seen. */
+ int useShort; /* Value to be printed is short (half word). */
+ char *end; /* Used to locate end of numerical fields. */
+
+ /*
+ * This procedure is a bit nasty. The goal is to use sprintf to
+ * do most of the dirty work. There are several problems:
+ * 1. this procedure can't trust its arguments.
+ * 2. we must be able to provide a large enough result area to hold
+ * whatever's generated. This is hard to estimate.
+ * 2. there's no way to move the arguments from argv to the call
+ * to sprintf in a reasonable way. This is particularly nasty
+ * because some of the arguments may be two-word values (doubles).
+ * So, what happens here is to scan the format string one % group
+ * at a time, making many individual calls to sprintf.
+ */
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " formatString ?arg arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ argIndex = 2;
+ for (format = argv[1]; *format != 0; ) {
+ register char *newPtr = newFormat;
+
+ width = precision = useTwoWords = noPercent = useShort = 0;
+
+ /*
+ * Get rid of any characters before the next field specifier.
+ */
+
+ if (*format != '%') {
+ register char *p;
+
+ oneWordValue = p = format;
+ while ((*format != '%') && (*format != 0)) {
+ *p = *format;
+ p++;
+ format++;
+ }
+ size = p - oneWordValue;
+ noPercent = 1;
+ goto doField;
+ }
+
+ if (format[1] == '%') {
+ oneWordValue = format;
+ size = 1;
+ noPercent = 1;
+ format += 2;
+ goto doField;
+ }
+
+ /*
+ * Parse off a field specifier, compute how many characters
+ * will be needed to store the result, and substitute for
+ * "*" size specifiers.
+ */
+
+ *newPtr = '%';
+ newPtr++;
+ format++;
+ if (isdigit(UCHAR(*format))) {
+ int tmp;
+
+ /*
+ * Check for an XPG3-style %n$ specification. Note: there
+ * must not be a mixture of XPG3 specs and non-XPG3 specs
+ * in the same format string.
+ */
+
+ tmp = strtoul(format, &end, 10);
+ if (*end != '$') {
+ goto notXpg;
+ }
+ format = end+1;
+ gotXpg = 1;
+ if (gotSequential) {
+ goto mixedXPG;
+ }
+ argIndex = tmp+1;
+ if ((argIndex < 2) || (argIndex >= argc)) {
+ goto badIndex;
+ }
+ goto xpgCheckDone;
+ }
+
+ notXpg:
+ gotSequential = 1;
+ if (gotXpg) {
+ goto mixedXPG;
+ }
+
+ xpgCheckDone:
+ while ((*format == '-') || (*format == '#') || (*format == '0')
+ || (*format == ' ') || (*format == '+')) {
+ *newPtr = *format;
+ newPtr++;
+ format++;
+ }
+ if (isdigit(UCHAR(*format))) {
+ width = strtoul(format, &end, 10);
+ format = end;
+ } else if (*format == '*') {
+ if (argIndex >= argc) {
+ goto badIndex;
+ }
+ if (Tcl_GetInt(interp, argv[argIndex], &width) != TCL_OK) {
+ goto fmtError;
+ }
+ argIndex++;
+ format++;
+ }
+ if (width != 0) {
+ sprintf(newPtr, "%d", width);
+ while (*newPtr != 0) {
+ newPtr++;
+ }
+ }
+ if (*format == '.') {
+ *newPtr = '.';
+ newPtr++;
+ format++;
+ }
+ if (isdigit(UCHAR(*format))) {
+ precision = strtoul(format, &end, 10);
+ format = end;
+ } else if (*format == '*') {
+ if (argIndex >= argc) {
+ goto badIndex;
+ }
+ if (Tcl_GetInt(interp, argv[argIndex], &precision) != TCL_OK) {
+ goto fmtError;
+ }
+ argIndex++;
+ format++;
+ }
+ if (precision != 0) {
+ sprintf(newPtr, "%d", precision);
+ while (*newPtr != 0) {
+ newPtr++;
+ }
+ }
+ if (*format == 'l') {
+ format++;
+ } else if (*format == 'h') {
+ useShort = 1;
+ *newPtr = 'h';
+ newPtr++;
+ format++;
+ }
+ *newPtr = *format;
+ newPtr++;
+ *newPtr = 0;
+ if (argIndex >= argc) {
+ goto badIndex;
+ }
+ switch (*format) {
+ case 'i':
+ newPtr[-1] = 'd';
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (Tcl_GetInt(interp, argv[argIndex], (int *) &oneWordValue)
+ != TCL_OK) {
+ goto fmtError;
+ }
+ size = 40;
+ break;
+ case 's':
+ oneWordValue = argv[argIndex];
+ size = strlen(argv[argIndex]);
+ break;
+ case 'c':
+ if (Tcl_GetInt(interp, argv[argIndex], (int *) &oneWordValue)
+ != TCL_OK) {
+ goto fmtError;
+ }
+ size = 1;
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (Tcl_GetDouble(interp, argv[argIndex], &twoWordValue)
+ != TCL_OK) {
+ goto fmtError;
+ }
+ useTwoWords = 1;
+ size = 320;
+ if (precision > 10) {
+ size += precision;
+ }
+ break;
+ case 0:
+ interp->result =
+ "format string ended in middle of field specifier";
+ goto fmtError;
+ default:
+ sprintf(interp->result, "bad field specifier \"%c\"", *format);
+ goto fmtError;
+ }
+ argIndex++;
+ format++;
+
+ /*
+ * Make sure that there's enough space to hold the formatted
+ * result, then format it.
+ */
+
+ doField:
+ if (width > size) {
+ size = width;
+ }
+ if ((dstSize + size) > dstSpace) {
+ char *newDst;
+ int newSpace;
+
+ newSpace = 2*(dstSize + size);
+ newDst = (char *) ckalloc((unsigned) newSpace+1);
+ if (dstSize != 0) {
+ memcpy((VOID *) newDst, (VOID *) dst, dstSize);
+ }
+ if (dstSpace != TCL_RESULT_SIZE) {
+ ckfree(dst);
+ }
+ dst = newDst;
+ dstSpace = newSpace;
+ }
+ if (noPercent) {
+ memcpy((VOID *) (dst+dstSize), (VOID *) oneWordValue, size);
+ dstSize += size;
+ dst[dstSize] = 0;
+ } else {
+ if (useTwoWords) {
+ sprintf(dst+dstSize, newFormat, twoWordValue);
+ } else if (useShort) {
+ /*
+ * The double cast below is needed for a few machines
+ * (e.g. Pyramids as of 1/93) that don't like casts
+ * directly from pointers to shorts.
+ */
+
+ sprintf(dst+dstSize, newFormat, (short) (int) oneWordValue);
+ } else {
+ sprintf(dst+dstSize, newFormat, (char *) oneWordValue);
+ }
+ dstSize += strlen(dst+dstSize);
+ }
+ }
+
+ interp->result = dst;
+ if (dstSpace != TCL_RESULT_SIZE) {
+ interp->freeProc = (Tcl_FreeProc *) free;
+ } else {
+ interp->freeProc = 0;
+ }
+ return TCL_OK;
+
+ mixedXPG:
+ interp->result = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ goto fmtError;
+
+ badIndex:
+ if (gotXpg) {
+ interp->result = "\"%n$\" argument index out of range";
+ } else {
+ interp->result = "not enough arguments for all format specifiers";
+ }
+
+ fmtError:
+ if (dstSpace != TCL_RESULT_SIZE) {
+ ckfree(dst);
+ }
+ return TCL_ERROR;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclCmdIL.c b/vendor/x11iraf/obm/Tcl/tclCmdIL.c
new file mode 100644
index 00000000..d32e0f1e
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclCmdIL.c
@@ -0,0 +1,1403 @@
+/*
+ * tclCmdIL.c --
+ *
+ * This file contains the top-level command routines for most of
+ * the Tcl built-in commands whose names begin with the letters
+ * I through L. It contains only commands in the generic core
+ * (i.e. those that don't depend much upon UNIX facilities).
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdIL.c,v 1.103 93/10/28 16:19:29 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+#include "patchlevel.h"
+
+/*
+ * The variables below are used to implement the "lsort" command.
+ * Unfortunately, this use of static variables prevents "lsort"
+ * from being thread-safe, but there's no alternative given the
+ * current implementation of qsort. In a threaded environment
+ * these variables should be made thread-local if possible, or else
+ * "lsort" needs internal mutual exclusion.
+ */
+
+static Tcl_Interp *sortInterp; /* Interpreter for "lsort" command. */
+static enum {ASCII, INTEGER, REAL, COMMAND} sortMode;
+ /* Mode for sorting: compare as strings,
+ * compare as numbers, or call
+ * user-defined command for
+ * comparison. */
+static Tcl_DString sortCmd; /* Holds command if mode is COMMAND.
+ * pre-initialized to hold base of
+ * command. */
+static int sortIncreasing; /* 0 means sort in decreasing order,
+ * 1 means increasing order. */
+static int sortCode; /* Anything other than TCL_OK means a
+ * problem occurred while sorting; this
+ * executing a comparison command, so
+ * the sort was aborted. */
+
+/*
+ * Forward declarations for procedures defined in this file:
+ */
+
+static int SortCompareProc _ANSI_ARGS_((CONST VOID *first,
+ CONST VOID *second));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_IfCmd --
+ *
+ * This procedure is invoked to process the "if" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_IfCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i, result, value;
+
+ i = 1;
+ while (1) {
+ /*
+ * At this point in the loop, argv and argc refer to an expression
+ * to test, either for the main expression or an expression
+ * following an "elseif". The arguments after the expression must
+ * be "then" (optional) and a script to execute if the expression is
+ * true.
+ */
+
+ if (i >= argc) {
+ Tcl_AppendResult(interp, "wrong # args: no expression after \"",
+ argv[i-1], "\" argument", (char *) NULL);
+ return TCL_ERROR;
+ }
+ result = Tcl_ExprBoolean(interp, argv[i], &value);
+ if (result != TCL_OK) {
+ return result;
+ }
+ i++;
+ if ((i < argc) && (strcmp(argv[i], "then") == 0)) {
+ i++;
+ }
+ if (i >= argc) {
+ Tcl_AppendResult(interp, "wrong # args: no script following \"",
+ argv[i-1], "\" argument", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (value) {
+ return Tcl_Eval(interp, argv[i]);
+ }
+
+ /*
+ * The expression evaluated to false. Skip the command, then
+ * see if there is an "else" or "elseif" clause.
+ */
+
+ i++;
+ if (i >= argc) {
+ return TCL_OK;
+ }
+ if ((argv[i][0] == 'e') && (strcmp(argv[i], "elseif") == 0)) {
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Couldn't find a "then" or "elseif" clause to execute. Check now
+ * for an "else" clause. We know that there's at least one more
+ * argument when we get here.
+ */
+
+ if (strcmp(argv[i], "else") == 0) {
+ i++;
+ if (i >= argc) {
+ Tcl_AppendResult(interp,
+ "wrong # args: no script following \"else\" argument",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ return Tcl_Eval(interp, argv[i]);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_IncrCmd --
+ *
+ * This procedure is invoked to process the "incr" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_IncrCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int value;
+ char *oldString, *result;
+ char newString[30];
+
+ if ((argc != 2) && (argc != 3)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " varName ?increment?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ oldString = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG);
+ if (oldString == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, oldString, &value) != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (reading value of variable to increment)");
+ return TCL_ERROR;
+ }
+ if (argc == 2) {
+ value += 1;
+ } else {
+ int increment;
+
+ if (Tcl_GetInt(interp, argv[2], &increment) != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (reading increment)");
+ return TCL_ERROR;
+ }
+ value += increment;
+ }
+ sprintf(newString, "%d", value);
+ result = Tcl_SetVar(interp, argv[1], newString, TCL_LEAVE_ERR_MSG);
+ if (result == NULL) {
+ return TCL_ERROR;
+ }
+ interp->result = result;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_InfoCmd --
+ *
+ * This procedure is invoked to process the "info" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_InfoCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int length;
+ char c;
+ Arg *argPtr;
+ Proc *procPtr;
+ Var *varPtr;
+ Command *cmdPtr;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option ?arg arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ if ((c == 'a') && (strncmp(argv[1], "args", length)) == 0) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " args procname\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ procPtr = TclFindProc(iPtr, argv[2]);
+ if (procPtr == NULL) {
+ infoNoSuchProc:
+ Tcl_AppendResult(interp, "\"", argv[2],
+ "\" isn't a procedure", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (argPtr = procPtr->argPtr; argPtr != NULL;
+ argPtr = argPtr->nextPtr) {
+ Tcl_AppendElement(interp, argPtr->name);
+ }
+ return TCL_OK;
+ } else if ((c == 'b') && (strncmp(argv[1], "body", length)) == 0) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " body procname\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ procPtr = TclFindProc(iPtr, argv[2]);
+ if (procPtr == NULL) {
+ goto infoNoSuchProc;
+ }
+ iPtr->result = procPtr->command;
+ return TCL_OK;
+ } else if ((c == 'c') && (strncmp(argv[1], "cmdcount", length) == 0)
+ && (length >= 2)) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " cmdcount\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ sprintf(iPtr->result, "%d", iPtr->cmdCount);
+ return TCL_OK;
+ } else if ((c == 'c') && (strncmp(argv[1], "commands", length) == 0)
+ && (length >= 4)) {
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " commands [pattern]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ char *name = Tcl_GetHashKey(&iPtr->commandTable, hPtr);
+ if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) {
+ continue;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ return TCL_OK;
+ } else if ((c == 'c') && (strncmp(argv[1], "complete", length) == 0)
+ && (length >= 4)) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " complete command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_CommandComplete(argv[2])) {
+ interp->result = "1";
+ } else {
+ interp->result = "0";
+ }
+ return TCL_OK;
+ } else if ((c == 'd') && (strncmp(argv[1], "default", length)) == 0) {
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " default procname arg varname\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ procPtr = TclFindProc(iPtr, argv[2]);
+ if (procPtr == NULL) {
+ goto infoNoSuchProc;
+ }
+ for (argPtr = procPtr->argPtr; ; argPtr = argPtr->nextPtr) {
+ if (argPtr == NULL) {
+ Tcl_AppendResult(interp, "procedure \"", argv[2],
+ "\" doesn't have an argument \"", argv[3],
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (strcmp(argv[3], argPtr->name) == 0) {
+ if (argPtr->defValue != NULL) {
+ if (Tcl_SetVar((Tcl_Interp *) iPtr, argv[4],
+ argPtr->defValue, 0) == NULL) {
+ defStoreError:
+ Tcl_AppendResult(interp,
+ "couldn't store default value in variable \"",
+ argv[4], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ iPtr->result = "1";
+ } else {
+ if (Tcl_SetVar((Tcl_Interp *) iPtr, argv[4], "", 0)
+ == NULL) {
+ goto defStoreError;
+ }
+ iPtr->result = "0";
+ }
+ return TCL_OK;
+ }
+ }
+ } else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0)) {
+ char *p;
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " exists varName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ p = Tcl_GetVar((Tcl_Interp *) iPtr, argv[2], 0);
+
+ /*
+ * The code below handles the special case where the name is for
+ * an array: Tcl_GetVar will reject this since you can't read
+ * an array variable without an index.
+ */
+
+ if (p == NULL) {
+ Tcl_HashEntry *hPtr;
+ Var *varPtr;
+
+ if (strchr(argv[2], '(') != NULL) {
+ noVar:
+ iPtr->result = "0";
+ return TCL_OK;
+ }
+ if (iPtr->varFramePtr == NULL) {
+ hPtr = Tcl_FindHashEntry(&iPtr->globalTable, argv[2]);
+ } else {
+ hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, argv[2]);
+ }
+ if (hPtr == NULL) {
+ goto noVar;
+ }
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UPVAR) {
+ varPtr = varPtr->value.upvarPtr;
+ }
+ if (!(varPtr->flags & VAR_ARRAY)) {
+ goto noVar;
+ }
+ }
+ iPtr->result = "1";
+ return TCL_OK;
+ } else if ((c == 'g') && (strncmp(argv[1], "globals", length) == 0)) {
+ char *name;
+
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " globals [pattern]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->globalTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UNDEFINED) {
+ continue;
+ }
+ name = Tcl_GetHashKey(&iPtr->globalTable, hPtr);
+ if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) {
+ continue;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ return TCL_OK;
+ } else if ((c == 'l') && (strncmp(argv[1], "level", length) == 0)
+ && (length >= 2)) {
+ if (argc == 2) {
+ if (iPtr->varFramePtr == NULL) {
+ iPtr->result = "0";
+ } else {
+ sprintf(iPtr->result, "%d", iPtr->varFramePtr->level);
+ }
+ return TCL_OK;
+ } else if (argc == 3) {
+ int level;
+ CallFrame *framePtr;
+
+ if (Tcl_GetInt(interp, argv[2], &level) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (level <= 0) {
+ if (iPtr->varFramePtr == NULL) {
+ levelError:
+ Tcl_AppendResult(interp, "bad level \"", argv[2],
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ level += iPtr->varFramePtr->level;
+ }
+ for (framePtr = iPtr->varFramePtr; framePtr != NULL;
+ framePtr = framePtr->callerVarPtr) {
+ if (framePtr->level == level) {
+ break;
+ }
+ }
+ if (framePtr == NULL) {
+ goto levelError;
+ }
+ iPtr->result = Tcl_Merge(framePtr->argc, framePtr->argv);
+ iPtr->freeProc = (Tcl_FreeProc *) free;
+ return TCL_OK;
+ }
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " level [number]\"", (char *) NULL);
+ return TCL_ERROR;
+ } else if ((c == 'l') && (strncmp(argv[1], "library", length) == 0)
+ && (length >= 2)) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " library\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ interp->result = getenv("TCL_LIBRARY");
+ if (interp->result == NULL) {
+#ifdef TCL_LIBRARY
+ interp->result = TCL_LIBRARY;
+#else
+ interp->result = "there is no Tcl library at this installation";
+ return TCL_ERROR;
+#endif
+ }
+ return TCL_OK;
+ } else if ((c == 'l') && (strncmp(argv[1], "locals", length) == 0)
+ && (length >= 2)) {
+ char *name;
+
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " locals [pattern]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (iPtr->varFramePtr == NULL) {
+ return TCL_OK;
+ }
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->varFramePtr->varTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & (VAR_UNDEFINED|VAR_UPVAR)) {
+ continue;
+ }
+ name = Tcl_GetHashKey(&iPtr->varFramePtr->varTable, hPtr);
+ if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) {
+ continue;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ return TCL_OK;
+ } else if ((c == 'p') && (strncmp(argv[1], "patchlevel", length) == 0)
+ && (length >= 2)) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " patchlevel\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ sprintf(interp->result, "%d", TCL_PATCH_LEVEL);
+ return TCL_OK;
+ } else if ((c == 'p') && (strncmp(argv[1], "procs", length) == 0)
+ && (length >= 2)) {
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " procs [pattern]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ char *name = Tcl_GetHashKey(&iPtr->commandTable, hPtr);
+
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ if (!TclIsProc(cmdPtr)) {
+ continue;
+ }
+ if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) {
+ continue;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ return TCL_OK;
+ } else if ((c == 's') && (strncmp(argv[1], "script", length) == 0)) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " script\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (iPtr->scriptFile != NULL) {
+ /*
+ * Can't depend on iPtr->scriptFile to be non-volatile:
+ * if this command is returned as the result of the script,
+ * then iPtr->scriptFile will go away.
+ */
+
+ Tcl_SetResult(interp, iPtr->scriptFile, TCL_VOLATILE);
+ }
+ return TCL_OK;
+ } else if ((c == 't') && (strncmp(argv[1], "tclversion", length) == 0)) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " tclversion\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Note: TCL_VERSION below is expected to be set with a "-D"
+ * switch in the Makefile.
+ */
+
+ strcpy(iPtr->result, TCL_VERSION);
+ return TCL_OK;
+ } else if ((c == 'v') && (strncmp(argv[1], "vars", length)) == 0) {
+ Tcl_HashTable *tablePtr;
+ char *name;
+
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " vars [pattern]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (iPtr->varFramePtr == NULL) {
+ tablePtr = &iPtr->globalTable;
+ } else {
+ tablePtr = &iPtr->varFramePtr->varTable;
+ }
+ for (hPtr = Tcl_FirstHashEntry(tablePtr, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UNDEFINED) {
+ continue;
+ }
+ name = Tcl_GetHashKey(tablePtr, hPtr);
+ if ((argc == 3) && !Tcl_StringMatch(name, argv[2])) {
+ continue;
+ }
+ Tcl_AppendElement(interp, name);
+ }
+ return TCL_OK;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be args, body, cmdcount, commands, ",
+ "complete, default, ",
+ "exists, globals, level, library, locals, ",
+ "patchlevel, procs, script, tclversion, or vars",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_JoinCmd --
+ *
+ * This procedure is invoked to process the "join" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_JoinCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *joinString;
+ char **listArgv;
+ int listArgc, i;
+
+ if (argc == 2) {
+ joinString = " ";
+ } else if (argc == 3) {
+ joinString = argv[2];
+ } else {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list ?joinString?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ for (i = 0; i < listArgc; i++) {
+ if (i == 0) {
+ Tcl_AppendResult(interp, listArgv[0], (char *) NULL);
+ } else {
+ Tcl_AppendResult(interp, joinString, listArgv[i], (char *) NULL);
+ }
+ }
+ ckfree((char *) listArgv);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LindexCmd --
+ *
+ * This procedure is invoked to process the "lindex" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LindexCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *p, *element;
+ int index, size, parenthesized, result;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list index\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (index < 0) {
+ return TCL_OK;
+ }
+ for (p = argv[1] ; index >= 0; index--) {
+ result = TclFindElement(interp, p, &element, &p, &size,
+ &parenthesized);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+ if (size == 0) {
+ return TCL_OK;
+ }
+ if (size >= TCL_RESULT_SIZE) {
+ interp->result = (char *) ckalloc((unsigned) size+1);
+ interp->freeProc = (Tcl_FreeProc *) free;
+ }
+ if (parenthesized) {
+ memcpy((VOID *) interp->result, (VOID *) element, size);
+ interp->result[size] = 0;
+ } else {
+ TclCopyAndCollapse(size, element, interp->result);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LinsertCmd --
+ *
+ * This procedure is invoked to process the "linsert" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LinsertCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *p, *element, savedChar;
+ int i, index, count, result, size;
+
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list index element ?element ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Skip over the first "index" elements of the list, then add
+ * all of those elements to the result.
+ */
+
+ size = 0;
+ element = argv[1];
+ for (count = 0, p = argv[1]; (count < index) && (*p != 0); count++) {
+ result = TclFindElement(interp, p, &element, &p, &size, (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+ if (*p == 0) {
+ Tcl_AppendResult(interp, argv[1], (char *) NULL);
+ } else {
+ char *end;
+
+ end = element+size;
+ if (element != argv[1]) {
+ while ((*end != 0) && !isspace(UCHAR(*end))) {
+ end++;
+ }
+ }
+ savedChar = *end;
+ *end = 0;
+ Tcl_AppendResult(interp, argv[1], (char *) NULL);
+ *end = savedChar;
+ }
+
+ /*
+ * Add the new list elements.
+ */
+
+ for (i = 3; i < argc; i++) {
+ Tcl_AppendElement(interp, argv[i]);
+ }
+
+ /*
+ * Append the remainder of the original list.
+ */
+
+ if (*p != 0) {
+ Tcl_AppendResult(interp, " ", p, (char *) NULL);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ListCmd --
+ *
+ * This procedure is invoked to process the "list" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ListCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc >= 2) {
+ interp->result = Tcl_Merge(argc-1, argv+1);
+ interp->freeProc = (Tcl_FreeProc *) free;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LlengthCmd --
+ *
+ * This procedure is invoked to process the "llength" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LlengthCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int count, result;
+ char *element, *p;
+
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (count = 0, p = argv[1]; *p != 0 ; count++) {
+ result = TclFindElement(interp, p, &element, &p, (int *) NULL,
+ (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (*element == 0) {
+ break;
+ }
+ }
+ sprintf(interp->result, "%d", count);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LrangeCmd --
+ *
+ * This procedure is invoked to process the "lrange" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LrangeCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int first, last, result;
+ char *begin, *end, c, *dummy;
+ int count;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list first last\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (first < 0) {
+ first = 0;
+ }
+ if ((*argv[3] == 'e') && (strncmp(argv[3], "end", strlen(argv[3])) == 0)) {
+ last = 1000000;
+ } else {
+ if (Tcl_GetInt(interp, argv[3], &last) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp,
+ "expected integer or \"end\" but got \"",
+ argv[3], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (first > last) {
+ return TCL_OK;
+ }
+
+ /*
+ * Extract a range of fields.
+ */
+
+ for (count = 0, begin = argv[1]; count < first; count++) {
+ result = TclFindElement(interp, begin, &dummy, &begin, (int *) NULL,
+ (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (*begin == 0) {
+ break;
+ }
+ }
+ for (count = first, end = begin; (count <= last) && (*end != 0);
+ count++) {
+ result = TclFindElement(interp, end, &dummy, &end, (int *) NULL,
+ (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+
+ /*
+ * Chop off trailing spaces.
+ */
+
+ while (isspace(UCHAR(end[-1]))) {
+ end--;
+ }
+ c = *end;
+ *end = 0;
+ Tcl_SetResult(interp, begin, TCL_VOLATILE);
+ *end = c;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LreplaceCmd --
+ *
+ * This procedure is invoked to process the "lreplace" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LreplaceCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *p1, *p2, *element, savedChar, *dummy;
+ int i, first, last, count, result, size;
+
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " list first last ?element element ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (TclGetListIndex(interp, argv[3], &last) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (first < 0) {
+ first = 0;
+ }
+ if (last < 0) {
+ last = 0;
+ }
+ if (first > last) {
+ Tcl_AppendResult(interp, "first index must not be greater than second",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Skip over the elements of the list before "first".
+ */
+
+ size = 0;
+ element = argv[1];
+ for (count = 0, p1 = argv[1]; (count < first) && (*p1 != 0); count++) {
+ result = TclFindElement(interp, p1, &element, &p1, &size,
+ (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+ if (*p1 == 0) {
+ Tcl_AppendResult(interp, "list doesn't contain element ",
+ argv[2], (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Skip over the elements of the list up through "last".
+ */
+
+ for (p2 = p1 ; (count <= last) && (*p2 != 0); count++) {
+ result = TclFindElement(interp, p2, &dummy, &p2, (int *) NULL,
+ (int *) NULL);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+
+ /*
+ * Add the elements before "first" to the result. Be sure to
+ * include quote or brace characters that might terminate the
+ * last of these elements.
+ */
+
+ p1 = element+size;
+ if (element != argv[1]) {
+ while ((*p1 != 0) && !isspace(UCHAR(*p1))) {
+ p1++;
+ }
+ }
+ savedChar = *p1;
+ *p1 = 0;
+ Tcl_AppendResult(interp, argv[1], (char *) NULL);
+ *p1 = savedChar;
+
+ /*
+ * Add the new list elements.
+ */
+
+ for (i = 4; i < argc; i++) {
+ Tcl_AppendElement(interp, argv[i]);
+ }
+
+ /*
+ * Append the remainder of the original list.
+ */
+
+ if (*p2 != 0) {
+ if (*interp->result == 0) {
+ Tcl_SetResult(interp, p2, TCL_VOLATILE);
+ } else {
+ Tcl_AppendResult(interp, " ", p2, (char *) NULL);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LsearchCmd --
+ *
+ * This procedure is invoked to process the "lsearch" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LsearchCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+#define EXACT 0
+#define GLOB 1
+#define REGEXP 2
+ int listArgc;
+ char **listArgv;
+ int i, match, mode, index;
+
+ mode = GLOB;
+ if (argc == 4) {
+ if (strcmp(argv[1], "-exact") == 0) {
+ mode = EXACT;
+ } else if (strcmp(argv[1], "-glob") == 0) {
+ mode = GLOB;
+ } else if (strcmp(argv[1], "-regexp") == 0) {
+ mode = REGEXP;
+ } else {
+ Tcl_AppendResult(interp, "bad search mode \"", argv[1],
+ "\": must be -exact, -glob, or -regexp", (char *) NULL);
+ return TCL_ERROR;
+ }
+ } else if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?mode? list pattern\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_SplitList(interp, argv[argc-2], &listArgc, &listArgv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ index = -1;
+ for (i = 0; i < listArgc; i++) {
+ match = 0;
+ switch (mode) {
+ case EXACT:
+ match = (strcmp(listArgv[i], argv[argc-1]) == 0);
+ break;
+ case GLOB:
+ match = Tcl_StringMatch(listArgv[i], argv[argc-1]);
+ break;
+ case REGEXP:
+ match = Tcl_RegExpMatch(interp, listArgv[i], argv[argc-1]);
+ if (match < 0) {
+ ckfree((char *) listArgv);
+ return TCL_ERROR;
+ }
+ break;
+ }
+ if (match) {
+ index = i;
+ break;
+ }
+ }
+ sprintf(interp->result, "%d", index);
+ ckfree((char *) listArgv);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LsortCmd --
+ *
+ * This procedure is invoked to process the "lsort" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LsortCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int listArgc, i, c, length;
+ char **listArgv;
+ char *command = NULL; /* Initialization needed only to
+ * prevent compiler warning. */
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?-ascii? ?-integer? ?-real? ?-increasing? ?-decreasing?",
+ " ?-command string? list\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Parse arguments to set up the mode for the sort.
+ */
+
+ sortInterp = interp;
+ sortMode = ASCII;
+ sortIncreasing = 1;
+ sortCode = TCL_OK;
+ for (i = 1; i < argc-1; i++) {
+ length = strlen(argv[i]);
+ if (length < 2) {
+ badSwitch:
+ Tcl_AppendResult(interp, "bad switch \"", argv[i],
+ "\": must be -ascii, -integer, -real, -increasing",
+ " -decreasing, or -command", (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = argv[i][1];
+ if ((c == 'a') && (strncmp(argv[i], "-ascii", length) == 0)) {
+ sortMode = ASCII;
+ } else if ((c == 'c') && (strncmp(argv[i], "-command", length) == 0)) {
+ if (i == argc-2) {
+ Tcl_AppendResult(interp, "\"-command\" must be",
+ " followed by comparison command", (char *) NULL);
+ return TCL_ERROR;
+ }
+ sortMode = COMMAND;
+ command = argv[i+1];
+ i++;
+ } else if ((c == 'd')
+ && (strncmp(argv[i], "-decreasing", length) == 0)) {
+ sortIncreasing = 0;
+ } else if ((c == 'i') && (length >= 4)
+ && (strncmp(argv[i], "-increasing", length) == 0)) {
+ sortIncreasing = 1;
+ } else if ((c == 'i') && (length >= 4)
+ && (strncmp(argv[i], "-integer", length) == 0)) {
+ sortMode = INTEGER;
+ } else if ((c == 'r')
+ && (strncmp(argv[i], "-real", length) == 0)) {
+ sortMode = REAL;
+ } else {
+ goto badSwitch;
+ }
+ }
+ if (sortMode == COMMAND) {
+ Tcl_DStringInit(&sortCmd);
+ Tcl_DStringAppend(&sortCmd, command, -1);
+ }
+
+ if (Tcl_SplitList(interp, argv[argc-1], &listArgc, &listArgv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ qsort((VOID *) listArgv, listArgc, sizeof (char *), SortCompareProc);
+ if (sortCode == TCL_OK) {
+ Tcl_ResetResult(interp);
+ interp->result = Tcl_Merge(listArgc, listArgv);
+ interp->freeProc = (Tcl_FreeProc *) free;
+ }
+ if (sortMode == COMMAND) {
+ Tcl_DStringFree(&sortCmd);
+ }
+ ckfree((char *) listArgv);
+ return sortCode;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SortCompareProc --
+ *
+ * This procedure is invoked by qsort to determine the proper
+ * ordering between two elements.
+ *
+ * Results:
+ * < 0 means first is "smaller" than "second", > 0 means "first"
+ * is larger than "second", and 0 means they should be treated
+ * as equal.
+ *
+ * Side effects:
+ * None, unless a user-defined comparison command does something
+ * weird.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+SortCompareProc(first, second)
+ CONST VOID *first, *second; /* Elements to be compared. */
+{
+ int order;
+ char *firstString = *((char **) first);
+ char *secondString = *((char **) second);
+
+ order = 0;
+ if (sortCode != TCL_OK) {
+ /*
+ * Once an error has occurred, skip any future comparisons
+ * so as to preserve the error message in sortInterp->result.
+ */
+
+ return order;
+ }
+ if (sortMode == ASCII) {
+ order = strcmp(firstString, secondString);
+ } else if (sortMode == INTEGER) {
+ int a, b;
+
+ if ((Tcl_GetInt(sortInterp, firstString, &a) != TCL_OK)
+ || (Tcl_GetInt(sortInterp, secondString, &b) != TCL_OK)) {
+ Tcl_AddErrorInfo(sortInterp,
+ "\n (converting list element from string to integer)");
+ sortCode = TCL_ERROR;
+ return order;
+ }
+ if (a > b) {
+ order = 1;
+ } else if (b > a) {
+ order = -1;
+ }
+ } else if (sortMode == REAL) {
+ double a, b;
+
+ if ((Tcl_GetDouble(sortInterp, firstString, &a) != TCL_OK)
+ || (Tcl_GetDouble(sortInterp, secondString, &b) != TCL_OK)) {
+ Tcl_AddErrorInfo(sortInterp,
+ "\n (converting list element from string to real)");
+ sortCode = TCL_ERROR;
+ return order;
+ }
+ if (a > b) {
+ order = 1;
+ } else if (b > a) {
+ order = -1;
+ }
+ } else {
+ int oldLength;
+ char *end;
+
+ /*
+ * Generate and evaluate a command to determine which string comes
+ * first.
+ */
+
+ oldLength = Tcl_DStringLength(&sortCmd);
+ Tcl_DStringAppendElement(&sortCmd, firstString);
+ Tcl_DStringAppendElement(&sortCmd, secondString);
+ sortCode = Tcl_Eval(sortInterp, Tcl_DStringValue(&sortCmd));
+ Tcl_DStringTrunc(&sortCmd, oldLength);
+ if (sortCode != TCL_OK) {
+ Tcl_AddErrorInfo(sortInterp,
+ "\n (user-defined comparison command)");
+ return order;
+ }
+
+ /*
+ * Parse the result of the command.
+ */
+
+ order = strtol(sortInterp->result, &end, 0);
+ if ((end == sortInterp->result) || (*end != 0)) {
+ Tcl_ResetResult(sortInterp);
+ Tcl_AppendResult(sortInterp,
+ "comparison command returned non-numeric result",
+ (char *) NULL);
+ sortCode = TCL_ERROR;
+ return order;
+ }
+ }
+ if (!sortIncreasing) {
+ order = -order;
+ }
+ return order;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclCmdMZ.c b/vendor/x11iraf/obm/Tcl/tclCmdMZ.c
new file mode 100644
index 00000000..92f9340c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclCmdMZ.c
@@ -0,0 +1,1730 @@
+/*
+ * tclCmdMZ.c --
+ *
+ * This file contains the top-level command routines for most of
+ * the Tcl built-in commands whose names begin with the letters
+ * M to Z. It contains only commands in the generic core (i.e.
+ * those that don't depend much upon UNIX facilities).
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdMZ.c,v 1.44 93/10/15 11:41:16 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+/*
+ * Structure used to hold information about variable traces:
+ */
+
+typedef struct {
+ int flags; /* Operations for which Tcl command is
+ * to be invoked. */
+ char *errMsg; /* Error message returned from Tcl command,
+ * or NULL. Malloc'ed. */
+ int length; /* Number of non-NULL chars. in command. */
+ char command[4]; /* Space for Tcl command to invoke. Actual
+ * size will be as large as necessary to
+ * hold command. This field must be the
+ * last in the structure, so that it can
+ * be larger than 4 bytes. */
+} TraceVarInfo;
+
+/*
+ * Forward declarations for procedures defined in this file:
+ */
+
+static char * TraceVarProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *name1, char *name2,
+ int flags));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RegexpCmd --
+ *
+ * This procedure is invoked to process the "regexp" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_RegexpCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int noCase = 0;
+ int indices = 0;
+ regexp *regexpPtr;
+ char **argPtr, *string, *pattern;
+ int match = 0; /* Initialization needed only to
+ * prevent compiler warning. */
+ int i;
+ Tcl_DString stringDString, patternDString;
+
+ if (argc < 3) {
+ wrongNumArgs:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?switches? exp string ?matchVar? ?subMatchVar ",
+ "subMatchVar ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ argPtr = argv+1;
+ argc--;
+ while ((argc > 0) && (argPtr[0][0] == '-')) {
+ if (strcmp(argPtr[0], "-indices") == 0) {
+ indices = 1;
+ } else if (strcmp(argPtr[0], "-nocase") == 0) {
+ noCase = 1;
+ } else if (strcmp(argPtr[0], "--") == 0) {
+ argPtr++;
+ argc--;
+ break;
+ } else {
+ Tcl_AppendResult(interp, "bad switch \"", argPtr[0],
+ "\": must be -indices, -nocase, or --", (char *) NULL);
+ return TCL_ERROR;
+ }
+ argPtr++;
+ argc--;
+ }
+ if (argc < 2) {
+ goto wrongNumArgs;
+ }
+
+ /*
+ * Convert the string and pattern to lower case, if desired, and
+ * perform the matching operation.
+ */
+
+ if (noCase) {
+ register char *p;
+
+ Tcl_DStringInit(&patternDString);
+ Tcl_DStringAppend(&patternDString, argPtr[0], -1);
+ pattern = Tcl_DStringValue(&patternDString);
+ for (p = pattern; *p != 0; p++) {
+ if (isupper(UCHAR(*p))) {
+ *p = tolower(*p);
+ }
+ }
+ Tcl_DStringInit(&stringDString);
+ Tcl_DStringAppend(&stringDString, argPtr[1], -1);
+ string = Tcl_DStringValue(&stringDString);
+ for (p = string; *p != 0; p++) {
+ if (isupper(UCHAR(*p))) {
+ *p = tolower(*p);
+ }
+ }
+ } else {
+ pattern = argPtr[0];
+ string = argPtr[1];
+ }
+ regexpPtr = TclCompileRegexp(interp, pattern);
+ if (regexpPtr != NULL) {
+ tclRegexpError = NULL;
+ match = TclRegExec(regexpPtr, string, string);
+ }
+ if (noCase) {
+ Tcl_DStringFree(&stringDString);
+ Tcl_DStringFree(&patternDString);
+ }
+ if (regexpPtr == NULL) {
+ return TCL_ERROR;
+ }
+ if (tclRegexpError != NULL) {
+ Tcl_AppendResult(interp, "error while matching pattern: ",
+ tclRegexpError, (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (!match) {
+ interp->result = "0";
+ return TCL_OK;
+ }
+
+ /*
+ * If additional variable names have been specified, return
+ * index information in those variables.
+ */
+
+ argc -= 2;
+ if (argc > NSUBEXP) {
+ interp->result = "too many substring variables";
+ return TCL_ERROR;
+ }
+ for (i = 0; i < argc; i++) {
+ char *result, info[50];
+
+ if (regexpPtr->startp[i] == NULL) {
+ if (indices) {
+ result = Tcl_SetVar(interp, argPtr[i+2], "-1 -1", 0);
+ } else {
+ result = Tcl_SetVar(interp, argPtr[i+2], "", 0);
+ }
+ } else {
+ if (indices) {
+ sprintf(info, "%d %d", regexpPtr->startp[i] - string,
+ regexpPtr->endp[i] - string - 1);
+ result = Tcl_SetVar(interp, argPtr[i+2], info, 0);
+ } else {
+ char savedChar, *first, *last;
+
+ first = argPtr[1] + (regexpPtr->startp[i] - string);
+ last = argPtr[1] + (regexpPtr->endp[i] - string);
+ savedChar = *last;
+ *last = 0;
+ result = Tcl_SetVar(interp, argPtr[i+2], first, 0);
+ *last = savedChar;
+ }
+ }
+ if (result == NULL) {
+ Tcl_AppendResult(interp, "couldn't set variable \"",
+ argPtr[i+2], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ interp->result = "1";
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RegsubCmd --
+ *
+ * This procedure is invoked to process the "regsub" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_RegsubCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int noCase = 0, all = 0;
+ regexp *regexpPtr;
+ char *string, *pattern, *p, *firstChar, *newValue, **argPtr;
+ int match, flags, code, anyMatches;
+ register char *src, c;
+ Tcl_DString stringDString, patternDString;
+
+ if (argc < 5) {
+ wrongNumArgs:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?switches? exp string subSpec varName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ argPtr = argv+1;
+ argc--;
+ while (argPtr[0][0] == '-') {
+ if (strcmp(argPtr[0], "-nocase") == 0) {
+ noCase = 1;
+ } else if (strcmp(argPtr[0], "-all") == 0) {
+ all = 1;
+ } else if (strcmp(argPtr[0], "--") == 0) {
+ argPtr++;
+ argc--;
+ break;
+ } else {
+ Tcl_AppendResult(interp, "bad switch \"", argPtr[0],
+ "\": must be -all, -nocase, or --", (char *) NULL);
+ return TCL_ERROR;
+ }
+ argPtr++;
+ argc--;
+ }
+ if (argc != 4) {
+ goto wrongNumArgs;
+ }
+
+ /*
+ * Convert the string and pattern to lower case, if desired.
+ */
+
+ if (noCase) {
+ Tcl_DStringInit(&patternDString);
+ Tcl_DStringAppend(&patternDString, argPtr[0], -1);
+ pattern = Tcl_DStringValue(&patternDString);
+ for (p = pattern; *p != 0; p++) {
+ if (isupper(UCHAR(*p))) {
+ *p = tolower(*p);
+ }
+ }
+ Tcl_DStringInit(&stringDString);
+ Tcl_DStringAppend(&stringDString, argPtr[1], -1);
+ string = Tcl_DStringValue(&stringDString);
+ for (p = string; *p != 0; p++) {
+ if (isupper(UCHAR(*p))) {
+ *p = tolower(*p);
+ }
+ }
+ } else {
+ pattern = argPtr[0];
+ string = argPtr[1];
+ }
+ regexpPtr = TclCompileRegexp(interp, pattern);
+ if (regexpPtr == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * The following loop is to handle multiple matches within the
+ * same source string; each iteration handles one match and its
+ * corresponding substitution. If "-all" hasn't been specified
+ * then the loop body only gets executed once.
+ */
+
+ flags = 0;
+ anyMatches = 0;
+ for (p = string; *p != 0; ) {
+ tclRegexpError = NULL;
+ match = TclRegExec(regexpPtr, p, string);
+ if (tclRegexpError != NULL) {
+ Tcl_AppendResult(interp, "error while matching pattern: ",
+ tclRegexpError, (char *) NULL);
+ code = TCL_ERROR;
+ goto done;
+ }
+ if (!match) {
+ break;
+ }
+ anyMatches = 1;
+
+ /*
+ * Copy the portion of the source string before the match to the
+ * result variable.
+ */
+
+ src = argPtr[1] + (regexpPtr->startp[0] - string);
+ c = *src;
+ *src = 0;
+ newValue = Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string),
+ flags);
+ *src = c;
+ flags = TCL_APPEND_VALUE;
+ if (newValue == NULL) {
+ cantSet:
+ Tcl_AppendResult(interp, "couldn't set variable \"",
+ argPtr[3], "\"", (char *) NULL);
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * Append the subSpec argument to the variable, making appropriate
+ * substitutions. This code is a bit hairy because of the backslash
+ * conventions and because the code saves up ranges of characters in
+ * subSpec to reduce the number of calls to Tcl_SetVar.
+ */
+
+ for (src = firstChar = argPtr[2], c = *src; c != 0; src++, c = *src) {
+ int index;
+
+ if (c == '&') {
+ index = 0;
+ } else if (c == '\\') {
+ c = src[1];
+ if ((c >= '0') && (c <= '9')) {
+ index = c - '0';
+ } else if ((c == '\\') || (c == '&')) {
+ *src = c;
+ src[1] = 0;
+ newValue = Tcl_SetVar(interp, argPtr[3], firstChar,
+ TCL_APPEND_VALUE);
+ *src = '\\';
+ src[1] = c;
+ if (newValue == NULL) {
+ goto cantSet;
+ }
+ firstChar = src+2;
+ src++;
+ continue;
+ } else {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ if (firstChar != src) {
+ c = *src;
+ *src = 0;
+ newValue = Tcl_SetVar(interp, argPtr[3], firstChar,
+ TCL_APPEND_VALUE);
+ *src = c;
+ if (newValue == NULL) {
+ goto cantSet;
+ }
+ }
+ if ((index < NSUBEXP) && (regexpPtr->startp[index] != NULL)
+ && (regexpPtr->endp[index] != NULL)) {
+ char *first, *last, saved;
+
+ first = argPtr[1] + (regexpPtr->startp[index] - string);
+ last = argPtr[1] + (regexpPtr->endp[index] - string);
+ saved = *last;
+ *last = 0;
+ newValue = Tcl_SetVar(interp, argPtr[3], first,
+ TCL_APPEND_VALUE);
+ *last = saved;
+ if (newValue == NULL) {
+ goto cantSet;
+ }
+ }
+ if (*src == '\\') {
+ src++;
+ }
+ firstChar = src+1;
+ }
+ if (firstChar != src) {
+ if (Tcl_SetVar(interp, argPtr[3], firstChar,
+ TCL_APPEND_VALUE) == NULL) {
+ goto cantSet;
+ }
+ }
+ if (regexpPtr->endp[0] == p) {
+ char tmp[2];
+
+ /*
+ * Always consume at least one character of the input string
+ * in order to prevent infinite loops.
+ */
+
+ tmp[0] = argPtr[1][p - string];
+ tmp[1] = 0;
+ newValue = Tcl_SetVar(interp, argPtr[3], tmp, flags);
+ if (newValue == NULL) {
+ goto cantSet;
+ }
+ p = regexpPtr->endp[0] + 1;
+ } else {
+ p = regexpPtr->endp[0];
+ }
+ if (!all) {
+ break;
+ }
+ }
+
+ /*
+ * Copy the portion of the source string after the last match to the
+ * result variable.
+ */
+
+ if ((*p != 0) || !anyMatches) {
+ if (Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string),
+ flags) == NULL) {
+ goto cantSet;
+ }
+ }
+ if (anyMatches) {
+ interp->result = "1";
+ } else {
+ interp->result = "0";
+ }
+ code = TCL_OK;
+
+ done:
+ if (noCase) {
+ Tcl_DStringFree(&stringDString);
+ Tcl_DStringFree(&patternDString);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RenameCmd --
+ *
+ * This procedure is invoked to process the "rename" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_RenameCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Command *cmdPtr;
+ Interp *iPtr = (Interp *) interp;
+ Tcl_HashEntry *hPtr;
+ int new;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " oldName newName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argv[2][0] == '\0') {
+ if (Tcl_DeleteCommand(interp, argv[1]) != 0) {
+ Tcl_AppendResult(interp, "can't delete \"", argv[1],
+ "\": command doesn't exist", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[2]);
+ if (hPtr != NULL) {
+ Tcl_AppendResult(interp, "can't rename to \"", argv[2],
+ "\": command already exists", (char *) NULL);
+ return TCL_ERROR;
+ }
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[1]);
+ if (hPtr == NULL) {
+ Tcl_AppendResult(interp, "can't rename \"", argv[1],
+ "\": command doesn't exist", (char *) NULL);
+ return TCL_ERROR;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ Tcl_DeleteHashEntry(hPtr);
+ hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, argv[2], &new);
+ Tcl_SetHashValue(hPtr, cmdPtr);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ReturnCmd --
+ *
+ * This procedure is invoked to process the "return" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ReturnCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Interp *iPtr = (Interp *) interp;
+ int c, code;
+
+ if (iPtr->errorInfo != NULL) {
+ ckfree(iPtr->errorInfo);
+ iPtr->errorInfo = NULL;
+ }
+ if (iPtr->errorCode != NULL) {
+ ckfree(iPtr->errorCode);
+ iPtr->errorCode = NULL;
+ }
+ code = TCL_OK;
+ for (argv++, argc--; argc > 1; argv += 2, argc -= 2) {
+ if (strcmp(argv[0], "-code") == 0) {
+ c = argv[1][0];
+ if ((c == 'o') && (strcmp(argv[1], "ok") == 0)) {
+ code = TCL_OK;
+ } else if ((c == 'e') && (strcmp(argv[1], "error") == 0)) {
+ code = TCL_ERROR;
+ } else if ((c == 'r') && (strcmp(argv[1], "return") == 0)) {
+ code = TCL_RETURN;
+ } else if ((c == 'b') && (strcmp(argv[1], "break") == 0)) {
+ code = TCL_BREAK;
+ } else if ((c == 'c') && (strcmp(argv[1], "continue") == 0)) {
+ code = TCL_CONTINUE;
+ } else if (Tcl_GetInt(interp, argv[1], &code) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "bad completion code \"",
+ argv[1], "\": must be ok, error, return, break, ",
+ "continue, or an integer", (char *) NULL);
+ return TCL_ERROR;
+ }
+ } else if (strcmp(argv[0], "-errorinfo") == 0) {
+ iPtr->errorInfo = ckalloc((unsigned) (strlen(argv[1]) + 1));
+ strcpy(iPtr->errorInfo, argv[1]);
+ } else if (strcmp(argv[0], "-errorcode") == 0) {
+ iPtr->errorCode = ckalloc((unsigned) (strlen(argv[1]) + 1));
+ strcpy(iPtr->errorCode, argv[1]);
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[0],
+ ": must be -code, -errorcode, or -errorinfo",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (argc == 1) {
+ Tcl_SetResult(interp, argv[0], TCL_VOLATILE);
+ }
+ iPtr->returnCode = code;
+ return TCL_RETURN;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ScanCmd --
+ *
+ * This procedure is invoked to process the "scan" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ScanCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+# define MAX_FIELDS 20
+ typedef struct {
+ char fmt; /* Format for field. */
+ int size; /* How many bytes to allow for
+ * field. */
+ char *location; /* Where field will be stored. */
+ } Field;
+ Field fields[MAX_FIELDS]; /* Info about all the fields in the
+ * format string. */
+ register Field *curField;
+ int numFields = 0; /* Number of fields actually
+ * specified. */
+ int suppress; /* Current field is assignment-
+ * suppressed. */
+ int totalSize = 0; /* Number of bytes needed to store
+ * all results combined. */
+ char *results; /* Where scanned output goes.
+ * Malloced; NULL means not allocated
+ * yet. */
+ int numScanned; /* sscanf's result. */
+ register char *fmt;
+ int i, widthSpecified, length, code;
+
+ /*
+ * The variables below are used to hold a copy of the format
+ * string, so that we can replace format specifiers like "%f"
+ * and "%F" with specifiers like "%lf"
+ */
+
+# define STATIC_SIZE 5
+ char copyBuf[STATIC_SIZE], *fmtCopy;
+ register char *dst;
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " string format ?varName varName ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * This procedure operates in four stages:
+ * 1. Scan the format string, collecting information about each field.
+ * 2. Allocate an array to hold all of the scanned fields.
+ * 3. Call sscanf to do all the dirty work, and have it store the
+ * parsed fields in the array.
+ * 4. Pick off the fields from the array and assign them to variables.
+ */
+
+ code = TCL_OK;
+ results = NULL;
+ length = strlen(argv[2]) * 2 + 1;
+ if (length < STATIC_SIZE) {
+ fmtCopy = copyBuf;
+ } else {
+ fmtCopy = ckalloc((unsigned) length);
+ }
+ dst = fmtCopy;
+ for (fmt = argv[2]; *fmt != 0; fmt++) {
+ *dst = *fmt;
+ dst++;
+ if (*fmt != '%') {
+ continue;
+ }
+ fmt++;
+ if (*fmt == '%') {
+ *dst = *fmt;
+ dst++;
+ continue;
+ }
+ if (*fmt == '*') {
+ suppress = 1;
+ *dst = *fmt;
+ dst++;
+ fmt++;
+ } else {
+ suppress = 0;
+ }
+ widthSpecified = 0;
+ while (isdigit(UCHAR(*fmt))) {
+ widthSpecified = 1;
+ *dst = *fmt;
+ dst++;
+ fmt++;
+ }
+ if ((*fmt == 'l') || (*fmt == 'h') || (*fmt == 'L')) {
+ fmt++;
+ }
+ *dst = *fmt;
+ dst++;
+ if (suppress) {
+ continue;
+ }
+ if (numFields == MAX_FIELDS) {
+ interp->result = "too many fields to scan";
+ code = TCL_ERROR;
+ goto done;
+ }
+ curField = &fields[numFields];
+ numFields++;
+ switch (*fmt) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'x':
+ curField->fmt = 'd';
+ curField->size = sizeof(int);
+ break;
+
+ case 'u':
+ curField->fmt = 'u';
+ curField->size = sizeof(int);
+ break;
+
+ case 's':
+ curField->fmt = 's';
+ curField->size = strlen(argv[1]) + 1;
+ break;
+
+ case 'c':
+ if (widthSpecified) {
+ interp->result =
+ "field width may not be specified in %c conversion";
+ code = TCL_ERROR;
+ goto done;
+ }
+ curField->fmt = 'c';
+ curField->size = sizeof(int);
+ break;
+
+ case 'e':
+ case 'f':
+ case 'g':
+ dst[-1] = 'l';
+ dst[0] = 'f';
+ dst++;
+ curField->fmt = 'f';
+ curField->size = sizeof(double);
+ break;
+
+ case '[':
+ curField->fmt = 's';
+ curField->size = strlen(argv[1]) + 1;
+ do {
+ fmt++;
+ *dst = *fmt;
+ dst++;
+ } while (*fmt != ']');
+ break;
+
+ default:
+ sprintf(interp->result, "bad scan conversion character \"%c\"",
+ *fmt);
+ code = TCL_ERROR;
+ goto done;
+ }
+ curField->size = TCL_ALIGN(curField->size);
+ totalSize += curField->size;
+ }
+ *dst = 0;
+
+ if (numFields != (argc-3)) {
+ interp->result =
+ "different numbers of variable names and field specifiers";
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * Step 2:
+ */
+
+ results = (char *) ckalloc((unsigned) totalSize);
+ for (i = 0, totalSize = 0, curField = fields;
+ i < numFields; i++, curField++) {
+ curField->location = results + totalSize;
+ totalSize += curField->size;
+ }
+
+ /*
+ * Fill in the remaining fields with NULL; the only purpose of
+ * this is to keep some memory analyzers, like Purify, from
+ * complaining.
+ */
+
+ for ( ; i < MAX_FIELDS; i++, curField++) {
+ curField->location = NULL;
+ }
+
+ /*
+ * Step 3:
+ */
+
+ numScanned = sscanf(argv[1], fmtCopy,
+ fields[0].location, fields[1].location, fields[2].location,
+ fields[3].location, fields[4].location, fields[5].location,
+ fields[6].location, fields[7].location, fields[8].location,
+ fields[9].location, fields[10].location, fields[11].location,
+ fields[12].location, fields[13].location, fields[14].location,
+ fields[15].location, fields[16].location, fields[17].location,
+ fields[18].location, fields[19].location);
+
+ /*
+ * Step 4:
+ */
+
+ if (numScanned < numFields) {
+ numFields = numScanned;
+ }
+ for (i = 0, curField = fields; i < numFields; i++, curField++) {
+ switch (curField->fmt) {
+ char string[TCL_DOUBLE_SPACE];
+
+ case 'd':
+ sprintf(string, "%d", *((int *) curField->location));
+ if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
+ storeError:
+ Tcl_AppendResult(interp,
+ "couldn't set variable \"", argv[i+3], "\"",
+ (char *) NULL);
+ code = TCL_ERROR;
+ goto done;
+ }
+ break;
+
+ case 'u':
+ sprintf(string, "%u", *((int *) curField->location));
+ if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
+ goto storeError;
+ }
+ break;
+
+ case 'c':
+ sprintf(string, "%d", *((char *) curField->location) & 0xff);
+ if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
+ goto storeError;
+ }
+ break;
+
+ case 's':
+ if (Tcl_SetVar(interp, argv[i+3], curField->location, 0)
+ == NULL) {
+ goto storeError;
+ }
+ break;
+
+ case 'f':
+ Tcl_PrintDouble(interp, *((double *) curField->location),
+ string);
+ if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
+ goto storeError;
+ }
+ break;
+ }
+ }
+ sprintf(interp->result, "%d", numScanned);
+ done:
+ if (results != NULL) {
+ ckfree(results);
+ }
+ if (fmtCopy != copyBuf) {
+ ckfree(fmtCopy);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SplitCmd --
+ *
+ * This procedure is invoked to process the "split" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_SplitCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *splitChars;
+ register char *p, *p2;
+ char *elementStart;
+
+ if (argc == 2) {
+ splitChars = " \n\t\r";
+ } else if (argc == 3) {
+ splitChars = argv[2];
+ } else {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " string ?splitChars?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Handle the special case of splitting on every character.
+ */
+
+ if (*splitChars == 0) {
+ char string[2];
+ string[1] = 0;
+ for (p = argv[1]; *p != 0; p++) {
+ string[0] = *p;
+ Tcl_AppendElement(interp, string);
+ }
+ return TCL_OK;
+ }
+
+ /*
+ * Normal case: split on any of a given set of characters.
+ * Discard instances of the split characters.
+ */
+
+ for (p = elementStart = argv[1]; *p != 0; p++) {
+ char c = *p;
+ for (p2 = splitChars; *p2 != 0; p2++) {
+ if (*p2 == c) {
+ *p = 0;
+ Tcl_AppendElement(interp, elementStart);
+ *p = c;
+ elementStart = p+1;
+ break;
+ }
+ }
+ }
+ if (p != argv[1]) {
+ Tcl_AppendElement(interp, elementStart);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_StringCmd --
+ *
+ * This procedure is invoked to process the "string" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_StringCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int length;
+ register char *p, c;
+ int match;
+ int first;
+ int left = 0, right = 0;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option arg ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ if ((c == 'c') && (strncmp(argv[1], "compare", length) == 0)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " compare string1 string2\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ match = strcmp(argv[2], argv[3]);
+ if (match > 0) {
+ interp->result = "1";
+ } else if (match < 0) {
+ interp->result = "-1";
+ } else {
+ interp->result = "0";
+ }
+ return TCL_OK;
+ } else if ((c == 'f') && (strncmp(argv[1], "first", length) == 0)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " first string1 string2\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ first = 1;
+
+ firstLast:
+ match = -1;
+ c = *argv[2];
+ length = strlen(argv[2]);
+ for (p = argv[3]; *p != 0; p++) {
+ if (*p != c) {
+ continue;
+ }
+ if (strncmp(argv[2], p, length) == 0) {
+ match = p-argv[3];
+ if (first) {
+ break;
+ }
+ }
+ }
+ sprintf(interp->result, "%d", match);
+ return TCL_OK;
+ } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)) {
+ int index;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " index string charIndex\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if ((index >= 0) && (index < (int) strlen(argv[2]))) {
+ interp->result[0] = argv[2][index];
+ interp->result[1] = 0;
+ }
+ return TCL_OK;
+ } else if ((c == 'l') && (strncmp(argv[1], "last", length) == 0)
+ && (length >= 2)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " last string1 string2\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ first = 0;
+ goto firstLast;
+ } else if ((c == 'l') && (strncmp(argv[1], "length", length) == 0)
+ && (length >= 2)) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " length string\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ sprintf(interp->result, "%d", strlen(argv[2]));
+ return TCL_OK;
+ } else if ((c == 'm') && (strncmp(argv[1], "match", length) == 0)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " match pattern string\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_StringMatch(argv[3], argv[2]) != 0) {
+ interp->result = "1";
+ } else {
+ interp->result = "0";
+ }
+ return TCL_OK;
+ } else if ((c == 'r') && (strncmp(argv[1], "range", length) == 0)) {
+ int first, last, stringLength;
+
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " range string first last\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ stringLength = strlen(argv[2]);
+ if (Tcl_GetInt(interp, argv[3], &first) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if ((*argv[4] == 'e')
+ && (strncmp(argv[4], "end", strlen(argv[4])) == 0)) {
+ last = stringLength-1;
+ } else {
+ if (Tcl_GetInt(interp, argv[4], &last) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp,
+ "expected integer or \"end\" but got \"",
+ argv[4], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (first < 0) {
+ first = 0;
+ }
+ if (last >= stringLength) {
+ last = stringLength-1;
+ }
+ if (last >= first) {
+ char saved, *p;
+
+ p = argv[2] + last + 1;
+ saved = *p;
+ *p = 0;
+ Tcl_SetResult(interp, argv[2] + first, TCL_VOLATILE);
+ *p = saved;
+ }
+ return TCL_OK;
+ } else if ((c == 't') && (strncmp(argv[1], "tolower", length) == 0)
+ && (length >= 3)) {
+ register char *p;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " tolower string\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tcl_SetResult(interp, argv[2], TCL_VOLATILE);
+ for (p = interp->result; *p != 0; p++) {
+ if (isupper(UCHAR(*p))) {
+ *p = tolower(*p);
+ }
+ }
+ return TCL_OK;
+ } else if ((c == 't') && (strncmp(argv[1], "toupper", length) == 0)
+ && (length >= 3)) {
+ register char *p;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " toupper string\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tcl_SetResult(interp, argv[2], TCL_VOLATILE);
+ for (p = interp->result; *p != 0; p++) {
+ if (islower(UCHAR(*p))) {
+ *p = toupper(*p);
+ }
+ }
+ return TCL_OK;
+ } else if ((c == 't') && (strncmp(argv[1], "trim", length) == 0)
+ && (length == 4)) {
+ char *trimChars;
+ register char *p, *checkPtr;
+
+ left = right = 1;
+
+ trim:
+ if (argc == 4) {
+ trimChars = argv[3];
+ } else if (argc == 3) {
+ trimChars = " \t\n\r";
+ } else {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ", argv[1], " string ?chars?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ p = argv[2];
+ if (left) {
+ for (c = *p; c != 0; p++, c = *p) {
+ for (checkPtr = trimChars; *checkPtr != c; checkPtr++) {
+ if (*checkPtr == 0) {
+ goto doneLeft;
+ }
+ }
+ }
+ }
+ doneLeft:
+ Tcl_SetResult(interp, p, TCL_VOLATILE);
+ if (right) {
+ char *donePtr;
+
+ p = interp->result + strlen(interp->result) - 1;
+ donePtr = &interp->result[-1];
+ for (c = *p; p != donePtr; p--, c = *p) {
+ for (checkPtr = trimChars; *checkPtr != c; checkPtr++) {
+ if (*checkPtr == 0) {
+ goto doneRight;
+ }
+ }
+ }
+ doneRight:
+ p[1] = 0;
+ }
+ return TCL_OK;
+ } else if ((c == 't') && (strncmp(argv[1], "trimleft", length) == 0)
+ && (length > 4)) {
+ left = 1;
+ argv[1] = "trimleft";
+ goto trim;
+ } else if ((c == 't') && (strncmp(argv[1], "trimright", length) == 0)
+ && (length > 4)) {
+ right = 1;
+ argv[1] = "trimright";
+ goto trim;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be compare, first, index, last, length, match, ",
+ "range, tolower, toupper, trim, trimleft, or trimright",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SwitchCmd --
+ *
+ * This procedure is invoked to process the "switch" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_SwitchCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+#define EXACT 0
+#define GLOB 1
+#define REGEXP 2
+ int i, code, mode, matched;
+ int body;
+ char *string;
+ int switchArgc, splitArgs;
+ char **switchArgv;
+
+ switchArgc = argc-1;
+ switchArgv = argv+1;
+ mode = EXACT;
+ while ((switchArgc > 0) && (*switchArgv[0] == '-')) {
+ if (strcmp(*switchArgv, "-exact") == 0) {
+ mode = EXACT;
+ } else if (strcmp(*switchArgv, "-glob") == 0) {
+ mode = GLOB;
+ } else if (strcmp(*switchArgv, "-regexp") == 0) {
+ mode = REGEXP;
+ } else if (strcmp(*switchArgv, "--") == 0) {
+ switchArgc--;
+ switchArgv++;
+ break;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", switchArgv[0],
+ "\": should be -exact, -glob, -regexp, or --",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ switchArgc--;
+ switchArgv++;
+ }
+ if (switchArgc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " ?switches? string pattern body ... ?default body?\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ string = *switchArgv;
+ switchArgc--;
+ switchArgv++;
+
+ /*
+ * If all of the pattern/command pairs are lumped into a single
+ * argument, split them out again.
+ */
+
+ splitArgs = 0;
+ if (switchArgc == 1) {
+ code = Tcl_SplitList(interp, switchArgv[0], &switchArgc, &switchArgv);
+ if (code != TCL_OK) {
+ return code;
+ }
+ splitArgs = 1;
+ }
+
+ for (i = 0; i < switchArgc; i += 2) {
+ if (i == (switchArgc-1)) {
+ interp->result = "extra switch pattern with no body";
+ code = TCL_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * See if the pattern matches the string.
+ */
+
+ matched = 0;
+ if ((*switchArgv[i] == 'd') && (i == switchArgc-2)
+ && (strcmp(switchArgv[i], "default") == 0)) {
+ matched = 1;
+ } else {
+ switch (mode) {
+ case EXACT:
+ matched = (strcmp(string, switchArgv[i]) == 0);
+ break;
+ case GLOB:
+ matched = Tcl_StringMatch(string, switchArgv[i]);
+ break;
+ case REGEXP:
+ matched = Tcl_RegExpMatch(interp, string, switchArgv[i]);
+ if (matched < 0) {
+ code = TCL_ERROR;
+ goto cleanup;
+ }
+ break;
+ }
+ }
+ if (!matched) {
+ continue;
+ }
+
+ /*
+ * We've got a match. Find a body to execute, skipping bodies
+ * that are "-".
+ */
+
+ for (body = i+1; ; body += 2) {
+ if (body >= switchArgc) {
+ Tcl_AppendResult(interp, "no body specified for pattern \"",
+ switchArgv[i], "\"", (char *) NULL);
+ code = TCL_ERROR;
+ goto cleanup;
+ }
+ if ((switchArgv[body][0] != '-') || (switchArgv[body][1] != 0)) {
+ break;
+ }
+ }
+ code = Tcl_Eval(interp, switchArgv[body]);
+ if (code == TCL_ERROR) {
+ char msg[100];
+ sprintf(msg, "\n (\"%.50s\" arm line %d)", switchArgv[i],
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ goto cleanup;
+ }
+
+ /*
+ * Nothing matched: return nothing.
+ */
+
+ code = TCL_OK;
+
+ cleanup:
+ if (splitArgs) {
+ ckfree((char *) switchArgv);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TraceCmd --
+ *
+ * This procedure is invoked to process the "trace" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_TraceCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char c;
+ int length;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "too few args: should be \"",
+ argv[0], " option [arg arg ...]\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = argv[1][1];
+ length = strlen(argv[1]);
+ if ((c == 'a') && (strncmp(argv[1], "variable", length) == 0)
+ && (length >= 2)) {
+ char *p;
+ int flags, length;
+ TraceVarInfo *tvarPtr;
+
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " variable name ops command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ flags = 0;
+ for (p = argv[3] ; *p != 0; p++) {
+ if (*p == 'r') {
+ flags |= TCL_TRACE_READS;
+ } else if (*p == 'w') {
+ flags |= TCL_TRACE_WRITES;
+ } else if (*p == 'u') {
+ flags |= TCL_TRACE_UNSETS;
+ } else {
+ goto badOps;
+ }
+ }
+ if (flags == 0) {
+ goto badOps;
+ }
+
+ length = strlen(argv[4]);
+ tvarPtr = (TraceVarInfo *) ckalloc((unsigned)
+ (sizeof(TraceVarInfo) - sizeof(tvarPtr->command) + length + 1));
+ tvarPtr->flags = flags;
+ tvarPtr->errMsg = NULL;
+ tvarPtr->length = length;
+ flags |= TCL_TRACE_UNSETS;
+ strcpy(tvarPtr->command, argv[4]);
+ if (Tcl_TraceVar(interp, argv[2], flags, TraceVarProc,
+ (ClientData) tvarPtr) != TCL_OK) {
+ ckfree((char *) tvarPtr);
+ return TCL_ERROR;
+ }
+ } else if ((c == 'd') && (strncmp(argv[1], "vdelete", length)
+ && (length >= 2)) == 0) {
+ char *p;
+ int flags, length;
+ TraceVarInfo *tvarPtr;
+ ClientData clientData;
+
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " vdelete name ops command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ flags = 0;
+ for (p = argv[3] ; *p != 0; p++) {
+ if (*p == 'r') {
+ flags |= TCL_TRACE_READS;
+ } else if (*p == 'w') {
+ flags |= TCL_TRACE_WRITES;
+ } else if (*p == 'u') {
+ flags |= TCL_TRACE_UNSETS;
+ } else {
+ goto badOps;
+ }
+ }
+ if (flags == 0) {
+ goto badOps;
+ }
+
+ /*
+ * Search through all of our traces on this variable to
+ * see if there's one with the given command. If so, then
+ * delete the first one that matches.
+ */
+
+ length = strlen(argv[4]);
+ clientData = 0;
+ while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0,
+ TraceVarProc, clientData)) != 0) {
+ tvarPtr = (TraceVarInfo *) clientData;
+ if ((tvarPtr->length == length) && (tvarPtr->flags == flags)
+ && (strncmp(argv[4], tvarPtr->command, length) == 0)) {
+ Tcl_UntraceVar(interp, argv[2], flags | TCL_TRACE_UNSETS,
+ TraceVarProc, clientData);
+ if (tvarPtr->errMsg != NULL) {
+ ckfree(tvarPtr->errMsg);
+ }
+ ckfree((char *) tvarPtr);
+ break;
+ }
+ }
+ } else if ((c == 'i') && (strncmp(argv[1], "vinfo", length) == 0)
+ && (length >= 2)) {
+ ClientData clientData;
+ char ops[4], *p;
+ char *prefix = "{";
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " vinfo name\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ clientData = 0;
+ while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0,
+ TraceVarProc, clientData)) != 0) {
+ TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData;
+ p = ops;
+ if (tvarPtr->flags & TCL_TRACE_READS) {
+ *p = 'r';
+ p++;
+ }
+ if (tvarPtr->flags & TCL_TRACE_WRITES) {
+ *p = 'w';
+ p++;
+ }
+ if (tvarPtr->flags & TCL_TRACE_UNSETS) {
+ *p = 'u';
+ p++;
+ }
+ *p = '\0';
+ Tcl_AppendResult(interp, prefix, (char *) NULL);
+ Tcl_AppendElement(interp, ops);
+ Tcl_AppendElement(interp, tvarPtr->command);
+ Tcl_AppendResult(interp, "}", (char *) NULL);
+ prefix = " {";
+ }
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be variable, vdelete, or vinfo",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+
+ badOps:
+ Tcl_AppendResult(interp, "bad operations \"", argv[3],
+ "\": should be one or more of rwu", (char *) NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TraceVarProc --
+ *
+ * This procedure is called to handle variable accesses that have
+ * been traced using the "trace" command.
+ *
+ * Results:
+ * Normally returns NULL. If the trace command returns an error,
+ * then this procedure returns an error string.
+ *
+ * Side effects:
+ * Depends on the command associated with the trace.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static char *
+TraceVarProc(clientData, interp, name1, name2, flags)
+ ClientData clientData; /* Information about the variable trace. */
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ char *name1; /* Name of variable or array. */
+ char *name2; /* Name of element within array; NULL means
+ * scalar variable is being referenced. */
+ int flags; /* OR-ed bits giving operation and other
+ * information. */
+{
+ TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData;
+ char *result;
+ int code;
+ Interp dummy;
+ Tcl_DString cmd;
+
+ result = NULL;
+ if (tvarPtr->errMsg != NULL) {
+ ckfree(tvarPtr->errMsg);
+ tvarPtr->errMsg = NULL;
+ }
+ if ((tvarPtr->flags & flags) && !(flags & TCL_INTERP_DESTROYED)) {
+
+ /*
+ * Generate a command to execute by appending list elements
+ * for the two variable names and the operation. The five
+ * extra characters are for three space, the opcode character,
+ * and the terminating null.
+ */
+
+ if (name2 == NULL) {
+ name2 = "";
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, tvarPtr->command, tvarPtr->length);
+ Tcl_DStringAppendElement(&cmd, name1);
+ Tcl_DStringAppendElement(&cmd, name2);
+ if (flags & TCL_TRACE_READS) {
+ Tcl_DStringAppend(&cmd, " r", 2);
+ } else if (flags & TCL_TRACE_WRITES) {
+ Tcl_DStringAppend(&cmd, " w", 2);
+ } else if (flags & TCL_TRACE_UNSETS) {
+ Tcl_DStringAppend(&cmd, " u", 2);
+ }
+
+ /*
+ * Execute the command. Be careful to save and restore the
+ * result from the interpreter used for the command.
+ */
+
+ if (interp->freeProc == 0) {
+ dummy.freeProc = (Tcl_FreeProc *) 0;
+ dummy.result = "";
+ Tcl_SetResult((Tcl_Interp *) &dummy, interp->result, TCL_VOLATILE);
+ } else {
+ dummy.freeProc = interp->freeProc;
+ dummy.result = interp->result;
+ interp->freeProc = (Tcl_FreeProc *) 0;
+ }
+ code = Tcl_Eval(interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if (code != TCL_OK) {
+ tvarPtr->errMsg = ckalloc((unsigned) (strlen(interp->result) + 1));
+ strcpy(tvarPtr->errMsg, interp->result);
+ result = tvarPtr->errMsg;
+ Tcl_ResetResult(interp); /* Must clear error state. */
+ }
+ Tcl_SetResult(interp, dummy.result,
+ (dummy.freeProc == 0) ? TCL_VOLATILE : dummy.freeProc);
+ }
+ if (flags & TCL_TRACE_DESTROYED) {
+ result = NULL;
+ if (tvarPtr->errMsg != NULL) {
+ ckfree(tvarPtr->errMsg);
+ }
+ ckfree((char *) tvarPtr);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_WhileCmd --
+ *
+ * This procedure is invoked to process the "while" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_WhileCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int result, value;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " test command\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ while (1) {
+ result = Tcl_ExprBoolean(interp, argv[1], &value);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (!value) {
+ break;
+ }
+ result = Tcl_Eval(interp, argv[2]);
+ if ((result != TCL_OK) && (result != TCL_CONTINUE)) {
+ if (result == TCL_ERROR) {
+ char msg[60];
+ sprintf(msg, "\n (\"while\" body line %d)",
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ break;
+ }
+ }
+ if (result == TCL_BREAK) {
+ result = TCL_OK;
+ }
+ if (result == TCL_OK) {
+ Tcl_ResetResult(interp);
+ }
+ return result;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclEnv.c b/vendor/x11iraf/obm/Tcl/tclEnv.c
new file mode 100644
index 00000000..012542fe
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclEnv.c
@@ -0,0 +1,531 @@
+/*
+ * tclEnv.c --
+ *
+ * Tcl support for environment variables, including a setenv
+ * procedure.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclEnv.c,v 1.17 93/10/13 17:16:56 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+/*
+ * The putenv and setenv definitions below cause any system prototypes for
+ * those procedures to be ignored so that there won't be a clash when the
+ * versions in this file are compiled.
+ */
+
+#define putenv ignore_putenv
+#define setenv ignore_setenv
+#include "tclInt.h"
+#include "tclUnix.h"
+#undef putenv
+#undef setenv
+
+/*
+ * The structure below is used to keep track of all of the interpereters
+ * for which we're managing the "env" array. It's needed so that they
+ * can all be updated whenever an environment variable is changed
+ * anywhere.
+ */
+
+typedef struct EnvInterp {
+ Tcl_Interp *interp; /* Interpreter for which we're managing
+ * the env array. */
+ struct EnvInterp *nextPtr; /* Next in list of all such interpreters,
+ * or zero. */
+} EnvInterp;
+
+static EnvInterp *firstInterpPtr;
+ /* First in list of all managed interpreters,
+ * or NULL if none. */
+
+static int environSize = 0; /* Non-zero means that the all of the
+ * environ-related information is malloc-ed
+ * and the environ array itself has this
+ * many total entries allocated to it (not
+ * all may be in use at once). Zero means
+ * that the environment array is in its
+ * original static state. */
+
+/*
+ * Declarations for local procedures defined in this file:
+ */
+
+static void EnvInit _ANSI_ARGS_((void));
+static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *name1, char *name2,
+ int flags));
+static int FindVariable _ANSI_ARGS_((CONST char *name,
+ int *lengthPtr));
+void TclSetEnv _ANSI_ARGS_((CONST char *name,
+ CONST char *value));
+void TclUnsetEnv _ANSI_ARGS_((CONST char *name));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclSetupEnv --
+ *
+ * This procedure is invoked for an interpreter to make environment
+ * variables accessible from that interpreter via the "env"
+ * associative array.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The interpreter is added to a list of interpreters managed
+ * by us, so that its view of envariables can be kept consistent
+ * with the view in other interpreters. If this is the first
+ * call to Tcl_SetupEnv, then additional initialization happens,
+ * such as copying the environment to dynamically-allocated space
+ * for ease of management.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclSetupEnv(interp)
+ Tcl_Interp *interp; /* Interpreter whose "env" array is to be
+ * managed. */
+{
+ EnvInterp *eiPtr;
+ int i;
+
+ /*
+ * First, initialize our environment-related information, if
+ * necessary.
+ */
+
+ if (environSize == 0) {
+ EnvInit();
+ }
+
+ /*
+ * Next, add the interpreter to the list of those that we manage.
+ */
+
+ eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
+ eiPtr->interp = interp;
+ eiPtr->nextPtr = firstInterpPtr;
+ firstInterpPtr = eiPtr;
+
+ /*
+ * Store the environment variable values into the interpreter's
+ * "env" array, and arrange for us to be notified on future
+ * writes and unsets to that array.
+ */
+
+ (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
+ for (i = 0; ; i++) {
+ char *p, *p2;
+
+ p = environ[i];
+ if (p == NULL) {
+ break;
+ }
+ for (p2 = p; *p2 != '='; p2++) {
+ /* Empty loop body. */
+ }
+ *p2 = 0;
+ (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY);
+ *p2 = '=';
+ }
+ Tcl_TraceVar2(interp, "env", (char *) NULL,
+ TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
+ EnvTraceProc, (ClientData) NULL);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FindVariable --
+ *
+ * Locate the entry in environ for a given name.
+ *
+ * Results:
+ * The return value is the index in environ of an entry with the
+ * name "name", or -1 if there is no such entry. The integer at
+ * *lengthPtr is filled in with the length of name (if a matching
+ * entry is found) or the length of the environ array (if no matching
+ * entry is found).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+FindVariable(name, lengthPtr)
+ CONST char *name; /* Name of desired environment variable. */
+ int *lengthPtr; /* Used to return length of name (for
+ * successful searches) or number of non-NULL
+ * entries in environ (for unsuccessful
+ * searches). */
+{
+ int i;
+ CONST char *p1, *p2;
+
+ for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
+ for (p2 = name; *p2 == *p1; p1++, p2++) {
+ /* NULL loop body. */
+ }
+ if ((*p1 == '=') && (*p2 == '\0')) {
+ *lengthPtr = p2-name;
+ return i;
+ }
+ }
+ *lengthPtr = i;
+ return -1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclSetEnv --
+ *
+ * Set an environment variable, replacing an existing value
+ * or creating a new variable if there doesn't exist a variable
+ * by the given name. This procedure is intended to be a
+ * stand-in for the UNIX "setenv" procedure so that applications
+ * using that procedure will interface properly to Tcl. To make
+ * it a stand-in, the Makefile must define "TclSetEnv" to "setenv".
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The environ array gets updated, as do all of the interpreters
+ * that we manage.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclSetEnv(name, value)
+ CONST char *name; /* Name of variable whose value is to be
+ * set. */
+ CONST char *value; /* New value for variable. */
+{
+ int index, length, nameLength;
+ char *p;
+ EnvInterp *eiPtr;
+
+ if (environSize == 0) {
+ EnvInit();
+ }
+
+ /*
+ * Figure out where the entry is going to go. If the name doesn't
+ * already exist, enlarge the array if necessary to make room. If
+ * the name exists, free its old entry.
+ */
+
+ index = FindVariable(name, &length);
+ if (index == -1) {
+ if ((length+2) > environSize) {
+ char **newEnviron;
+
+ newEnviron = (char **) ckalloc((unsigned)
+ ((length+5) * sizeof(char *)));
+ memcpy((VOID *) newEnviron, (VOID *) environ,
+ length*sizeof(char *));
+ ckfree((char *) environ);
+ environ = newEnviron;
+ environSize = length+5;
+ }
+ index = length;
+ environ[index+1] = NULL;
+ nameLength = strlen(name);
+ } else {
+ /*
+ * Compare the new value to the existing value. If they're
+ * the same then quit immediately (e.g. don't rewrite the
+ * value or propagate it to other interpreters). Otherwise,
+ * when there are N interpreters there will be N! propagations
+ * of the same value among the interpreters.
+ */
+
+ if (strcmp(value, environ[index]+length+1) == 0) {
+ return;
+ }
+ ckfree(environ[index]);
+ nameLength = length;
+ }
+
+ /*
+ * Create a new entry and enter it into the table.
+ */
+
+ p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
+ environ[index] = p;
+ strcpy(p, name);
+ p += nameLength;
+ *p = '=';
+ strcpy(p+1, value);
+
+ /*
+ * Update all of the interpreters.
+ */
+
+ for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
+ (void) Tcl_SetVar2(eiPtr->interp, "env", (char *) name,
+ p+1, TCL_GLOBAL_ONLY);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PutEnv --
+ *
+ * Set an environment variable. Similar to setenv except that
+ * the information is passed in a single string of the form
+ * NAME=value, rather than as separate name strings. This procedure
+ * is intended to be a stand-in for the UNIX "putenv" procedure
+ * so that applications using that procedure will interface
+ * properly to Tcl. To make it a stand-in, the Makefile will
+ * define "Tcl_PutEnv" to "putenv".
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The environ array gets updated, as do all of the interpreters
+ * that we manage.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_PutEnv(string)
+ CONST char *string; /* Info about environment variable in the
+ * form NAME=value. */
+{
+ int nameLength;
+ char *name, *value;
+
+ if (string == NULL) {
+ return 0;
+ }
+
+ /*
+ * Separate the string into name and value parts, then call
+ * TclSetEnv to do all of the real work.
+ */
+
+ value = strchr(string, '=');
+ if (value == NULL) {
+ return 0;
+ }
+ nameLength = value - string;
+ if (nameLength == 0) {
+ return 0;
+ }
+ name = ckalloc((unsigned) nameLength+1);
+ memcpy(name, string, nameLength);
+ name[nameLength] = 0;
+ TclSetEnv(name, value+1);
+ ckfree(name);
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclUnsetEnv --
+ *
+ * Remove an environment variable, updating the "env" arrays
+ * in all interpreters managed by us. This function is intended
+ * to replace the UNIX "unsetenv" function (but to do this the
+ * Makefile must be modified to redefine "TclUnsetEnv" to
+ * "unsetenv".
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Interpreters are updated, as is environ.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclUnsetEnv(name)
+ CONST char *name; /* Name of variable to remove. */
+{
+ int index, dummy;
+ char **envPtr;
+ EnvInterp *eiPtr;
+
+ if (environSize == 0) {
+ EnvInit();
+ }
+
+ /*
+ * Update the environ array.
+ */
+
+ index = FindVariable(name, &dummy);
+ if (index == -1) {
+ return;
+ }
+ ckfree(environ[index]);
+ for (envPtr = environ+index+1; ; envPtr++) {
+ envPtr[-1] = *envPtr;
+ if (*envPtr == NULL) {
+ break;
+ }
+ }
+
+ /*
+ * Update all of the interpreters.
+ */
+
+ for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
+ (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *) name,
+ TCL_GLOBAL_ONLY);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EnvTraceProc --
+ *
+ * This procedure is invoked whenever an environment variable
+ * is modified or deleted. It propagates the change to the
+ * "environ" array and to any other interpreters for whom
+ * we're managing an "env" array.
+ *
+ * Results:
+ * Always returns NULL to indicate success.
+ *
+ * Side effects:
+ * Environment variable changes get propagated. If the whole
+ * "env" array is deleted, then we stop managing things for
+ * this interpreter (usually this happens because the whole
+ * interpreter is being deleted).
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static char *
+EnvTraceProc(clientData, interp, name1, name2, flags)
+ ClientData clientData; /* Not used. */
+ Tcl_Interp *interp; /* Interpreter whose "env" variable is
+ * being modified. */
+ char *name1; /* Better be "env". */
+ char *name2; /* Name of variable being modified, or
+ * NULL if whole array is being deleted. */
+ int flags; /* Indicates what's happening. */
+{
+ /*
+ * First see if the whole "env" variable is being deleted. If
+ * so, just forget about this interpreter.
+ */
+
+ if (name2 == NULL) {
+ register EnvInterp *eiPtr, *prevPtr;
+
+ if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
+ != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
+ panic("EnvTraceProc called with confusing arguments");
+ }
+ eiPtr = firstInterpPtr;
+ if (eiPtr->interp == interp) {
+ firstInterpPtr = eiPtr->nextPtr;
+ } else {
+ for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
+ prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
+ if (eiPtr == NULL) {
+ panic("EnvTraceProc couldn't find interpreter");
+ }
+ if (eiPtr->interp == interp) {
+ prevPtr->nextPtr = eiPtr->nextPtr;
+ break;
+ }
+ }
+ }
+ ckfree((char *) eiPtr);
+ return NULL;
+ }
+
+ /*
+ * If a value is being set, call TclSetEnv to do all of the work.
+ */
+
+ if (flags & TCL_TRACE_WRITES) {
+ TclSetEnv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY));
+ }
+
+ if (flags & TCL_TRACE_UNSETS) {
+ TclUnsetEnv(name2);
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EnvInit --
+ *
+ * This procedure is called to initialize our management
+ * of the environ array.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Environ gets copied to malloc-ed storage, so that in
+ * the future we don't have to worry about which entries
+ * are malloc-ed and which are static.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+EnvInit()
+{
+ char **newEnviron;
+ int i, length;
+
+ if (environSize != 0) {
+ return;
+ }
+ for (length = 0; environ[length] != NULL; length++) {
+ /* Empty loop body. */
+ }
+ environSize = length+5;
+ newEnviron = (char **) ckalloc((unsigned)
+ (environSize * sizeof(char *)));
+ for (i = 0; i < length; i++) {
+ newEnviron[i] = (char *) ckalloc((unsigned) (strlen(environ[i]) + 1));
+ strcpy(newEnviron[i], environ[i]);
+ }
+ newEnviron[length] = NULL;
+ environ = newEnviron;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclExpr.c b/vendor/x11iraf/obm/Tcl/tclExpr.c
new file mode 100644
index 00000000..45780842
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclExpr.c
@@ -0,0 +1,2011 @@
+/*
+ * tclExpr.c --
+ *
+ * This file contains the code to evaluate expressions for
+ * Tcl.
+ *
+ * This implementation of floating-point support was modelled
+ * after an initial implementation by Bill Carpenter.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclExpr.c,v 1.68 93/10/31 16:19:44 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+#ifdef NO_FLOAT_H
+# include "compat/float.h"
+#else
+# include <float.h>
+#endif
+#ifndef TCL_NO_MATH
+#include <math.h>
+#endif
+
+/*
+ * The stuff below is a bit of a hack so that this file can be used
+ * in environments that include no UNIX, i.e. no errno. Just define
+ * errno here.
+ */
+
+#ifndef TCL_GENERIC_ONLY
+#include "tclUnix.h"
+extern int errno;
+#else
+#define NO_ERRNO_H
+#endif
+
+#ifdef NO_ERRNO_H
+int errno;
+#define EDOM 33
+#define ERANGE 34
+#endif
+
+/* Slackware/RedHat4.2 compatibility hack. */
+#if defined(linux) && defined(isalnum)
+#undef isalnum
+#define isalnum(c) (isalpha(c)||isdigit(c))
+#endif
+
+
+/*
+ * The data structure below is used to describe an expression value,
+ * which can be either an integer (the usual case), a double-precision
+ * floating-point value, or a string. A given number has only one
+ * value at a time.
+ */
+
+#define STATIC_STRING_SPACE 150
+
+typedef struct {
+ long intValue; /* Integer value, if any. */
+ double doubleValue; /* Floating-point value, if any. */
+ ParseValue pv; /* Used to hold a string value, if any. */
+ char staticSpace[STATIC_STRING_SPACE];
+ /* Storage for small strings; large ones
+ * are malloc-ed. */
+ int type; /* Type of value: TYPE_INT, TYPE_DOUBLE,
+ * or TYPE_STRING. */
+} Value;
+
+/*
+ * Valid values for type:
+ */
+
+#define TYPE_INT 0
+#define TYPE_DOUBLE 1
+#define TYPE_STRING 2
+
+/*
+ * The data structure below describes the state of parsing an expression.
+ * It's passed among the routines in this module.
+ */
+
+typedef struct {
+ char *originalExpr; /* The entire expression, as originally
+ * passed to Tcl_ExprString et al. */
+ char *expr; /* Position to the next character to be
+ * scanned from the expression string. */
+ int token; /* Type of the last token to be parsed from
+ * expr. See below for definitions.
+ * Corresponds to the characters just
+ * before expr. */
+} ExprInfo;
+
+/*
+ * The token types are defined below. In addition, there is a table
+ * associating a precedence with each operator. The order of types
+ * is important. Consult the code before changing it.
+ */
+
+#define VALUE 0
+#define OPEN_PAREN 1
+#define CLOSE_PAREN 2
+#define COMMA 3
+#define END 4
+#define UNKNOWN 5
+
+/*
+ * Binary operators:
+ */
+
+#define MULT 8
+#define DIVIDE 9
+#define MOD 10
+#define PLUS 11
+#define MINUS 12
+#define LEFT_SHIFT 13
+#define RIGHT_SHIFT 14
+#define LESS 15
+#define GREATER 16
+#define LEQ 17
+#define GEQ 18
+#define EQUAL 19
+#define NEQ 20
+#define BIT_AND 21
+#define BIT_XOR 22
+#define BIT_OR 23
+#define AND 24
+#define OR 25
+#define QUESTY 26
+#define COLON 27
+
+/*
+ * Unary operators:
+ */
+
+#define UNARY_MINUS 28
+#define NOT 29
+#define BIT_NOT 30
+
+/*
+ * Precedence table. The values for non-operator token types are ignored.
+ */
+
+int precTable[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 11, 11, 11, /* MULT, DIVIDE, MOD */
+ 10, 10, /* PLUS, MINUS */
+ 9, 9, /* LEFT_SHIFT, RIGHT_SHIFT */
+ 8, 8, 8, 8, /* LESS, GREATER, LEQ, GEQ */
+ 7, 7, /* EQUAL, NEQ */
+ 6, /* BIT_AND */
+ 5, /* BIT_XOR */
+ 4, /* BIT_OR */
+ 3, /* AND */
+ 2, /* OR */
+ 1, 1, /* QUESTY, COLON */
+ 12, 12, 12 /* UNARY_MINUS, NOT, BIT_NOT */
+};
+
+/*
+ * Mapping from operator numbers to strings; used for error messages.
+ */
+
+char *operatorStrings[] = {
+ "VALUE", "(", ")", "END", "UNKNOWN", "5", "6", "7",
+ "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=",
+ ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":",
+ "-", "!", "~"
+};
+
+/*
+ * The following slight modification to DBL_MAX is needed because of
+ * a compiler bug on Sprite (4/15/93).
+ */
+
+#ifdef sprite
+#undef DBL_MAX
+#define DBL_MAX 1.797693134862316e+307
+#endif
+
+/*
+ * Macros for testing floating-point values for certain special
+ * cases. Test for not-a-number by comparing a value against
+ * itself; test for infinity by comparing against the largest
+ * floating-point value.
+ */
+
+#define IS_NAN(v) ((v) != (v))
+#ifdef DBL_MAX
+# define IS_INF(v) (((v) > DBL_MAX) || ((v) < -DBL_MAX))
+#else
+# define IS_INF(v) 0
+#endif
+
+/*
+ * The following global variable is use to signal matherr that Tcl
+ * is responsible for the arithmetic, so errors can be handled in a
+ * fashion appropriate for Tcl. Zero means no Tcl math is in
+ * progress; non-zero means Tcl is doing math.
+ */
+
+int tcl_MathInProgress = 0;
+
+/*
+ * The variable below serves no useful purpose except to generate
+ * a reference to matherr, so that the Tcl version of matherr is
+ * linked in rather than the system version. Without this reference
+ * the need for matherr won't be discovered during linking until after
+ * libtcl.a has been processed, so Tcl's version won't be used.
+ */
+
+#ifdef NEED_MATHERR
+extern int matherr();
+int (*tclMatherrPtr)() = matherr;
+#endif
+
+/*
+ * Declarations for local procedures to this file:
+ */
+
+static int ExprAbsFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+static int ExprBinaryFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+static int ExprDoubleFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+static void ExprFloatError _ANSI_ARGS_((Tcl_Interp *interp,
+ double value));
+static int ExprGetValue _ANSI_ARGS_((Tcl_Interp *interp,
+ ExprInfo *infoPtr, int prec, Value *valuePtr));
+static int ExprIntFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+static int ExprLex _ANSI_ARGS_((Tcl_Interp *interp,
+ ExprInfo *infoPtr, Value *valuePtr));
+static void ExprMakeString _ANSI_ARGS_((Tcl_Interp *interp,
+ Value *valuePtr));
+static int ExprMathFunc _ANSI_ARGS_((Tcl_Interp *interp,
+ ExprInfo *infoPtr, Value *valuePtr));
+static int ExprParseString _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, Value *valuePtr));
+static int ExprRoundFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+static int ExprTopLevel _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, Value *valuePtr));
+static int ExprUnaryFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+
+/*
+ * Built-in math functions:
+ */
+
+typedef struct {
+ char *name; /* Name of function. */
+ int numArgs; /* Number of arguments for function. */
+ Tcl_ValueType argTypes[MAX_MATH_ARGS];
+ /* Acceptable types for each argument. */
+ Tcl_MathProc *proc; /* Procedure that implements this function. */
+ ClientData clientData; /* Additional argument to pass to the function
+ * when invoking it. */
+} BuiltinFunc;
+
+static BuiltinFunc funcTable[] = {
+#ifndef TCL_NO_MATH
+ {"acos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) acos},
+ {"asin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) asin},
+ {"atan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) atan},
+ {"atan2", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) atan2},
+ {"ceil", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) ceil},
+ {"cos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cos},
+ {"cosh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cosh},
+ {"exp", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) exp},
+ {"floor", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) floor},
+ {"fmod", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) fmod},
+ {"hypot", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) hypot},
+ {"log", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log},
+ {"log10", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log10},
+ {"pow", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) pow},
+ {"sin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sin},
+ {"sinh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sinh},
+ {"sqrt", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sqrt},
+ {"tan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tan},
+ {"tanh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tanh},
+#endif
+ {"abs", 1, {TCL_EITHER}, ExprAbsFunc, 0},
+ {"double", 1, {TCL_EITHER}, ExprDoubleFunc, 0},
+ {"int", 1, {TCL_EITHER}, ExprIntFunc, 0},
+ {"round", 1, {TCL_EITHER}, ExprRoundFunc, 0},
+ {0,0,{0},0,0},
+};
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ExprParseString --
+ *
+ * Given a string (such as one coming from command or variable
+ * substitution), make a Value based on the string. The value
+ * will be a floating-point or integer, if possible, or else it
+ * will just be a copy of the string.
+ *
+ * Results:
+ * TCL_OK is returned under normal circumstances, and TCL_ERROR
+ * is returned if a floating-point overflow or underflow occurred
+ * while reading in a number. The value at *valuePtr is modified
+ * to hold a number, if possible.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ExprParseString(interp, string, valuePtr)
+ Tcl_Interp *interp; /* Where to store error message. */
+ char *string; /* String to turn into value. */
+ Value *valuePtr; /* Where to store value information.
+ * Caller must have initialized pv field. */
+{
+ char *term, *p, *start;
+
+ if (*string != 0) {
+ valuePtr->type = TYPE_INT;
+ errno = 0;
+
+ /*
+ * Note: use strtoul instead of strtol for integer conversions
+ * to allow full-size unsigned numbers, but don't depend on
+ * strtoul to handle sign characters; it won't in some
+ * implementations.
+ */
+
+ for (p = string; isspace(UCHAR(*p)); p++) {
+ /* Empty loop body. */
+ }
+ if (*p == '-') {
+ start = p+1;
+ valuePtr->intValue = -strtoul(start, &term, 0);
+ } else if (*p == '+') {
+ start = p+1;
+ valuePtr->intValue = strtoul(start, &term, 0);
+ } else {
+ start = p;
+ valuePtr->intValue = strtoul(start, &term, 0);
+ }
+ if (errno == ERANGE) {
+ /*
+ * This procedure is sometimes called with string in
+ * interp->result, so we have to clear the result before
+ * logging an error message.
+ */
+
+ Tcl_ResetResult(interp);
+ interp->result = "integer value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", interp->result,
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ if ((term != start) && (*term == '\0')) {
+ return TCL_OK;
+ }
+ errno = 0;
+ valuePtr->doubleValue = strtod(p, &term);
+ if ((term != p) && (*term == '\0')) {
+ if (errno != 0) {
+ Tcl_ResetResult(interp);
+ ExprFloatError(interp, valuePtr->doubleValue);
+ return TCL_ERROR;
+ }
+ valuePtr->type = TYPE_DOUBLE;
+ return TCL_OK;
+ }
+ }
+
+ /*
+ * Not a valid number. Save a string value (but don't do anything
+ * if it's already the value).
+ */
+
+ valuePtr->type = TYPE_STRING;
+ if (string != valuePtr->pv.buffer) {
+ int length, shortfall;
+
+ length = strlen(string);
+ valuePtr->pv.next = valuePtr->pv.buffer;
+ shortfall = length - (valuePtr->pv.end - valuePtr->pv.buffer);
+ if (shortfall > 0) {
+ (*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);
+ }
+ strcpy(valuePtr->pv.buffer, string);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ExprLex --
+ *
+ * Lexical analyzer for expression parser: parses a single value,
+ * operator, or other syntactic element from an expression string.
+ *
+ * Results:
+ * TCL_OK is returned unless an error occurred while doing lexical
+ * analysis or executing an embedded command. In that case a
+ * standard Tcl error is returned, using interp->result to hold
+ * an error message. In the event of a successful return, the token
+ * and field in infoPtr is updated to refer to the next symbol in
+ * the expression string, and the expr field is advanced past that
+ * token; if the token is a value, then the value is stored at
+ * valuePtr.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+ExprLex(interp, infoPtr, valuePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error
+ * reporting. */
+ register ExprInfo *infoPtr; /* Describes the state of the parse. */
+ register Value *valuePtr; /* Where to store value, if that is
+ * what's parsed from string. Caller
+ * must have initialized pv field
+ * correctly. */
+{
+ register char *p;
+ char *var, *term;
+ int result;
+
+ p = infoPtr->expr;
+ while (isspace(UCHAR(*p))) {
+ p++;
+ }
+ if (*p == 0) {
+ infoPtr->token = END;
+ infoPtr->expr = p;
+ return TCL_OK;
+ }
+
+ /*
+ * First try to parse the token as an integer or floating-point number.
+ * A couple of tricky points:
+ *
+ * 1. Can't just check for leading digits to see if there's a number
+ * there, because it could be a special value like "NaN".
+ * 2. Don't want to check for a number if the first character is "+"
+ * or "-". If we do, we might treat a binary operator as unary
+ * by mistake, which will eventually cause a syntax error.
+ * 3. First see if there's an integer, then if there's stuff after
+ * the integer that looks like it could be a floating-point number
+ * (or if there wasn't even a sensible integer), then try to parse
+ * as a floating-point number. The check for the characters '8'
+ * or '9' is to handle floating-point numbers like 028.6: the
+ * leading zero causes strtoul to interpret the number as octal
+ * and stop when it gets to the 8.
+ */
+
+ if ((*p != '+') && (*p != '-')) {
+ errno = 0;
+ valuePtr->intValue = strtoul(p, &term, 0);
+ if ((term == p) || (*term == '.') || (*term == 'e') ||
+ (*term == 'E') || (*term == '8') || (*term == '9')) {
+ char *term2;
+
+ /*
+ * The code here is a bit tricky: we want to use a floating-point
+ * number if there is one, but if there isn't then fall through to
+ * use the integer that was already parsed, if there was one.
+ */
+
+ errno = 0;
+ valuePtr->doubleValue = strtod(p, &term2);
+ if (term2 != p) {
+ if (errno != 0) {
+ ExprFloatError(interp, valuePtr->doubleValue);
+ return TCL_ERROR;
+ }
+ infoPtr->token = VALUE;
+ infoPtr->expr = term2;
+ valuePtr->type = TYPE_DOUBLE;
+ return TCL_OK;
+ }
+ if (term != p) {
+ interp->result = "poorly-formed floating-point value";
+ return TCL_ERROR;
+ }
+ }
+ if (term != p) {
+ /*
+ * No floating-point number, but there is an integer.
+ */
+
+ if (errno == ERANGE) {
+ interp->result = "integer value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", interp->result,
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ infoPtr->token = VALUE;
+ infoPtr->expr = term;
+ valuePtr->type = TYPE_INT;
+ return TCL_OK;
+ }
+ }
+
+ infoPtr->expr = p+1;
+ switch (*p) {
+ case '$':
+
+ /*
+ * Variable. Fetch its value, then see if it makes sense
+ * as an integer or floating-point number.
+ */
+
+ infoPtr->token = VALUE;
+ var = Tcl_ParseVar(interp, p, &infoPtr->expr);
+ if (var == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_ResetResult(interp);
+ if (((Interp *) interp)->noEval) {
+ valuePtr->type = TYPE_INT;
+ valuePtr->intValue = 0;
+ return TCL_OK;
+ }
+ return ExprParseString(interp, var, valuePtr);
+
+ case '[':
+ infoPtr->token = VALUE;
+ ((Interp *) interp)->evalFlags = TCL_BRACKET_TERM;
+ result = Tcl_Eval(interp, p+1);
+ infoPtr->expr = ((Interp *) interp)->termPtr;
+ if (result != TCL_OK) {
+ return result;
+ }
+ infoPtr->expr++;
+ if (((Interp *) interp)->noEval) {
+ valuePtr->type = TYPE_INT;
+ valuePtr->intValue = 0;
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+ }
+ result = ExprParseString(interp, interp->result, valuePtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+
+ case '"':
+ infoPtr->token = VALUE;
+ result = TclParseQuotes(interp, infoPtr->expr, '"', 0,
+ &infoPtr->expr, &valuePtr->pv);
+ if (result != TCL_OK) {
+ return result;
+ }
+ Tcl_ResetResult(interp);
+ return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);
+
+ case '{':
+ infoPtr->token = VALUE;
+ result = TclParseBraces(interp, infoPtr->expr, &infoPtr->expr,
+ &valuePtr->pv);
+ if (result != TCL_OK) {
+ return result;
+ }
+ Tcl_ResetResult(interp);
+ return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);
+
+ case '(':
+ infoPtr->token = OPEN_PAREN;
+ return TCL_OK;
+
+ case ')':
+ infoPtr->token = CLOSE_PAREN;
+ return TCL_OK;
+
+ case ',':
+ infoPtr->token = COMMA;
+ return TCL_OK;
+
+ case '*':
+ infoPtr->token = MULT;
+ return TCL_OK;
+
+ case '/':
+ infoPtr->token = DIVIDE;
+ return TCL_OK;
+
+ case '%':
+ infoPtr->token = MOD;
+ return TCL_OK;
+
+ case '+':
+ infoPtr->token = PLUS;
+ return TCL_OK;
+
+ case '-':
+ infoPtr->token = MINUS;
+ return TCL_OK;
+
+ case '?':
+ infoPtr->token = QUESTY;
+ return TCL_OK;
+
+ case ':':
+ infoPtr->token = COLON;
+ return TCL_OK;
+
+ case '<':
+ switch (p[1]) {
+ case '<':
+ infoPtr->expr = p+2;
+ infoPtr->token = LEFT_SHIFT;
+ break;
+ case '=':
+ infoPtr->expr = p+2;
+ infoPtr->token = LEQ;
+ break;
+ default:
+ infoPtr->token = LESS;
+ break;
+ }
+ return TCL_OK;
+
+ case '>':
+ switch (p[1]) {
+ case '>':
+ infoPtr->expr = p+2;
+ infoPtr->token = RIGHT_SHIFT;
+ break;
+ case '=':
+ infoPtr->expr = p+2;
+ infoPtr->token = GEQ;
+ break;
+ default:
+ infoPtr->token = GREATER;
+ break;
+ }
+ return TCL_OK;
+
+ case '=':
+ if (p[1] == '=') {
+ infoPtr->expr = p+2;
+ infoPtr->token = EQUAL;
+ } else {
+ infoPtr->token = UNKNOWN;
+ }
+ return TCL_OK;
+
+ case '!':
+ if (p[1] == '=') {
+ infoPtr->expr = p+2;
+ infoPtr->token = NEQ;
+ } else {
+ infoPtr->token = NOT;
+ }
+ return TCL_OK;
+
+ case '&':
+ if (p[1] == '&') {
+ infoPtr->expr = p+2;
+ infoPtr->token = AND;
+ } else {
+ infoPtr->token = BIT_AND;
+ }
+ return TCL_OK;
+
+ case '^':
+ infoPtr->token = BIT_XOR;
+ return TCL_OK;
+
+ case '|':
+ if (p[1] == '|') {
+ infoPtr->expr = p+2;
+ infoPtr->token = OR;
+ } else {
+ infoPtr->token = BIT_OR;
+ }
+ return TCL_OK;
+
+ case '~':
+ infoPtr->token = BIT_NOT;
+ return TCL_OK;
+
+ default:
+ if (isalpha(UCHAR(*p))) {
+ infoPtr->expr = p;
+ return ExprMathFunc(interp, infoPtr, valuePtr);
+ }
+ infoPtr->expr = p+1;
+ infoPtr->token = UNKNOWN;
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ExprGetValue --
+ *
+ * Parse a "value" from the remainder of the expression in infoPtr.
+ *
+ * Results:
+ * Normally TCL_OK is returned. The value of the expression is
+ * returned in *valuePtr. If an error occurred, then interp->result
+ * contains an error message and TCL_ERROR is returned.
+ * InfoPtr->token will be left pointing to the token AFTER the
+ * expression, and infoPtr->expr will point to the character just
+ * after the terminating token.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+ExprGetValue(interp, infoPtr, prec, valuePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error
+ * reporting. */
+ register ExprInfo *infoPtr; /* Describes the state of the parse
+ * just before the value (i.e. ExprLex
+ * will be called to get first token
+ * of value). */
+ int prec; /* Treat any un-parenthesized operator
+ * with precedence <= this as the end
+ * of the expression. */
+ Value *valuePtr; /* Where to store the value of the
+ * expression. Caller must have
+ * initialized pv field. */
+{
+ Interp *iPtr = (Interp *) interp;
+ Value value2; /* Second operand for current
+ * operator. */
+ int operator; /* Current operator (either unary
+ * or binary). */
+ int badType; /* Type of offending argument; used
+ * for error messages. */
+ int gotOp; /* Non-zero means already lexed the
+ * operator (while picking up value
+ * for unary operator). Don't lex
+ * again. */
+ int result;
+
+ /*
+ * There are two phases to this procedure. First, pick off an initial
+ * value. Then, parse (binary operator, value) pairs until done.
+ */
+
+ gotOp = 0;
+ value2.pv.buffer = value2.pv.next = value2.staticSpace;
+ value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1;
+ value2.pv.expandProc = TclExpandParseValue;
+ value2.pv.clientData = (ClientData) NULL;
+ result = ExprLex(interp, infoPtr, valuePtr);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ if (infoPtr->token == OPEN_PAREN) {
+
+ /*
+ * Parenthesized sub-expression.
+ */
+
+ result = ExprGetValue(interp, infoPtr, -1, valuePtr);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ if (infoPtr->token != CLOSE_PAREN) {
+ Tcl_AppendResult(interp, "unmatched parentheses in expression \"",
+ infoPtr->originalExpr, "\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ } else {
+ if (infoPtr->token == MINUS) {
+ infoPtr->token = UNARY_MINUS;
+ }
+ if (infoPtr->token >= UNARY_MINUS) {
+
+ /*
+ * Process unary operators.
+ */
+
+ operator = infoPtr->token;
+ result = ExprGetValue(interp, infoPtr, precTable[infoPtr->token],
+ valuePtr);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ switch (operator) {
+ case UNARY_MINUS:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue = -valuePtr->intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE){
+ valuePtr->doubleValue = -valuePtr->doubleValue;
+ } else {
+ badType = valuePtr->type;
+ goto illegalType;
+ }
+ break;
+ case NOT:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue = !valuePtr->intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ /*
+ * Theoretically, should be able to use
+ * "!valuePtr->intValue", but apparently some
+ * compilers can't handle it.
+ */
+ if (valuePtr->doubleValue == 0.0) {
+ valuePtr->intValue = 1;
+ } else {
+ valuePtr->intValue = 0;
+ }
+ valuePtr->type = TYPE_INT;
+ } else {
+ badType = valuePtr->type;
+ goto illegalType;
+ }
+ break;
+ case BIT_NOT:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue = ~valuePtr->intValue;
+ } else {
+ badType = valuePtr->type;
+ goto illegalType;
+ }
+ break;
+ }
+ gotOp = 1;
+ } else if (infoPtr->token != VALUE) {
+ goto syntaxError;
+ }
+ }
+
+ /*
+ * Got the first operand. Now fetch (operator, operand) pairs.
+ */
+
+ if (!gotOp) {
+ result = ExprLex(interp, infoPtr, &value2);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ }
+ while (1) {
+ operator = infoPtr->token;
+ value2.pv.next = value2.pv.buffer;
+ if ((operator < MULT) || (operator >= UNARY_MINUS)) {
+ if ((operator == END) || (operator == CLOSE_PAREN)
+ || (operator == COMMA)) {
+ result = TCL_OK;
+ goto done;
+ } else {
+ goto syntaxError;
+ }
+ }
+ if (precTable[operator] <= prec) {
+ result = TCL_OK;
+ goto done;
+ }
+
+ /*
+ * If we're doing an AND or OR and the first operand already
+ * determines the result, don't execute anything in the
+ * second operand: just parse. Same style for ?: pairs.
+ */
+
+ if ((operator == AND) || (operator == OR) || (operator == QUESTY)) {
+ if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue = valuePtr->doubleValue != 0;
+ valuePtr->type = TYPE_INT;
+ } else if (valuePtr->type == TYPE_STRING) {
+ badType = TYPE_STRING;
+ goto illegalType;
+ }
+ if (((operator == AND) && !valuePtr->intValue)
+ || ((operator == OR) && valuePtr->intValue)) {
+ iPtr->noEval++;
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ &value2);
+ iPtr->noEval--;
+ } else if (operator == QUESTY) {
+ if (valuePtr->intValue != 0) {
+ valuePtr->pv.next = valuePtr->pv.buffer;
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ valuePtr);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ if (infoPtr->token != COLON) {
+ goto syntaxError;
+ }
+ value2.pv.next = value2.pv.buffer;
+ iPtr->noEval++;
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ &value2);
+ iPtr->noEval--;
+ } else {
+ iPtr->noEval++;
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ &value2);
+ iPtr->noEval--;
+ if (result != TCL_OK) {
+ goto done;
+ }
+ if (infoPtr->token != COLON) {
+ goto syntaxError;
+ }
+ valuePtr->pv.next = valuePtr->pv.buffer;
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ valuePtr);
+ }
+ } else {
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ &value2);
+ }
+ } else {
+ result = ExprGetValue(interp, infoPtr, precTable[operator],
+ &value2);
+ }
+ if (result != TCL_OK) {
+ goto done;
+ }
+ if ((infoPtr->token < MULT) && (infoPtr->token != VALUE)
+ && (infoPtr->token != END) && (infoPtr->token != COMMA)
+ && (infoPtr->token != CLOSE_PAREN)) {
+ goto syntaxError;
+ }
+
+ /*
+ * At this point we've got two values and an operator. Check
+ * to make sure that the particular data types are appropriate
+ * for the particular operator, and perform type conversion
+ * if necessary.
+ */
+
+ switch (operator) {
+
+ /*
+ * For the operators below, no strings are allowed and
+ * ints get converted to floats if necessary.
+ */
+
+ case MULT: case DIVIDE: case PLUS: case MINUS:
+ if ((valuePtr->type == TYPE_STRING)
+ || (value2.type == TYPE_STRING)) {
+ badType = TYPE_STRING;
+ goto illegalType;
+ }
+ if (valuePtr->type == TYPE_DOUBLE) {
+ if (value2.type == TYPE_INT) {
+ value2.doubleValue = value2.intValue;
+ value2.type = TYPE_DOUBLE;
+ }
+ } else if (value2.type == TYPE_DOUBLE) {
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->doubleValue = valuePtr->intValue;
+ valuePtr->type = TYPE_DOUBLE;
+ }
+ }
+ break;
+
+ /*
+ * For the operators below, only integers are allowed.
+ */
+
+ case MOD: case LEFT_SHIFT: case RIGHT_SHIFT:
+ case BIT_AND: case BIT_XOR: case BIT_OR:
+ if (valuePtr->type != TYPE_INT) {
+ badType = valuePtr->type;
+ goto illegalType;
+ } else if (value2.type != TYPE_INT) {
+ badType = value2.type;
+ goto illegalType;
+ }
+ break;
+
+ /*
+ * For the operators below, any type is allowed but the
+ * two operands must have the same type. Convert integers
+ * to floats and either to strings, if necessary.
+ */
+
+ case LESS: case GREATER: case LEQ: case GEQ:
+ case EQUAL: case NEQ:
+ if (valuePtr->type == TYPE_STRING) {
+ if (value2.type != TYPE_STRING) {
+ ExprMakeString(interp, &value2);
+ }
+ } else if (value2.type == TYPE_STRING) {
+ if (valuePtr->type != TYPE_STRING) {
+ ExprMakeString(interp, valuePtr);
+ }
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ if (value2.type == TYPE_INT) {
+ value2.doubleValue = value2.intValue;
+ value2.type = TYPE_DOUBLE;
+ }
+ } else if (value2.type == TYPE_DOUBLE) {
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->doubleValue = valuePtr->intValue;
+ valuePtr->type = TYPE_DOUBLE;
+ }
+ }
+ break;
+
+ /*
+ * For the operators below, no strings are allowed, but
+ * no int->double conversions are performed.
+ */
+
+ case AND: case OR:
+ if (valuePtr->type == TYPE_STRING) {
+ badType = valuePtr->type;
+ goto illegalType;
+ }
+ if (value2.type == TYPE_STRING) {
+ badType = value2.type;
+ goto illegalType;
+ }
+ break;
+
+ /*
+ * For the operators below, type and conversions are
+ * irrelevant: they're handled elsewhere.
+ */
+
+ case QUESTY: case COLON:
+ break;
+
+ /*
+ * Any other operator is an error.
+ */
+
+ default:
+ interp->result = "unknown operator in expression";
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * If necessary, convert one of the operands to the type
+ * of the other. If the operands are incompatible with
+ * the operator (e.g. "+" on strings) then return an
+ * error.
+ */
+
+ switch (operator) {
+ case MULT:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue *= value2.intValue;
+ } else {
+ valuePtr->doubleValue *= value2.doubleValue;
+ }
+ break;
+ case DIVIDE:
+ case MOD:
+ if (valuePtr->type == TYPE_INT) {
+ int divisor, quot, rem, negative;
+ if (value2.intValue == 0) {
+ divideByZero:
+ interp->result = "divide by zero";
+ Tcl_SetErrorCode(interp, "ARITH", "DIVZERO",
+ interp->result, (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * The code below is tricky because C doesn't guarantee
+ * much about the properties of the quotient or
+ * remainder, but Tcl does: the remainder always has
+ * the same sign as the divisor and a smaller absolute
+ * value.
+ */
+
+ divisor = value2.intValue;
+ negative = 0;
+ if (divisor < 0) {
+ divisor = -divisor;
+ valuePtr->intValue = -valuePtr->intValue;
+ negative = 1;
+ }
+ quot = valuePtr->intValue / divisor;
+ rem = valuePtr->intValue % divisor;
+ if (rem < 0) {
+ rem += divisor;
+ quot -= 1;
+ }
+ if (negative) {
+ rem = -rem;
+ }
+ valuePtr->intValue = (operator == DIVIDE) ? quot : rem;
+ } else {
+ if (value2.doubleValue == 0.0) {
+ goto divideByZero;
+ }
+ valuePtr->doubleValue /= value2.doubleValue;
+ }
+ break;
+ case PLUS:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue += value2.intValue;
+ } else {
+ valuePtr->doubleValue += value2.doubleValue;
+ }
+ break;
+ case MINUS:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue -= value2.intValue;
+ } else {
+ valuePtr->doubleValue -= value2.doubleValue;
+ }
+ break;
+ case LEFT_SHIFT:
+ valuePtr->intValue <<= value2.intValue;
+ break;
+ case RIGHT_SHIFT:
+ /*
+ * The following code is a bit tricky: it ensures that
+ * right shifts propagate the sign bit even on machines
+ * where ">>" won't do it by default.
+ */
+
+ if (valuePtr->intValue < 0) {
+ valuePtr->intValue =
+ ~((~valuePtr->intValue) >> value2.intValue);
+ } else {
+ valuePtr->intValue >>= value2.intValue;
+ }
+ break;
+ case LESS:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue < value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue < value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) < 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case GREATER:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue > value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue > value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) > 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case LEQ:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue <= value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue <= value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) <= 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case GEQ:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue >= value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue >= value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) >= 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case EQUAL:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue == value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue == value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) == 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case NEQ:
+ if (valuePtr->type == TYPE_INT) {
+ valuePtr->intValue =
+ valuePtr->intValue != value2.intValue;
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ valuePtr->intValue =
+ valuePtr->doubleValue != value2.doubleValue;
+ } else {
+ valuePtr->intValue =
+ strcmp(valuePtr->pv.buffer, value2.pv.buffer) != 0;
+ }
+ valuePtr->type = TYPE_INT;
+ break;
+ case BIT_AND:
+ valuePtr->intValue &= value2.intValue;
+ break;
+ case BIT_XOR:
+ valuePtr->intValue ^= value2.intValue;
+ break;
+ case BIT_OR:
+ valuePtr->intValue |= value2.intValue;
+ break;
+
+ /*
+ * For AND and OR, we know that the first value has already
+ * been converted to an integer. Thus we need only consider
+ * the possibility of int vs. double for the second value.
+ */
+
+ case AND:
+ if (value2.type == TYPE_DOUBLE) {
+ value2.intValue = value2.doubleValue != 0;
+ value2.type = TYPE_INT;
+ }
+ valuePtr->intValue = valuePtr->intValue && value2.intValue;
+ break;
+ case OR:
+ if (value2.type == TYPE_DOUBLE) {
+ value2.intValue = value2.doubleValue != 0;
+ value2.type = TYPE_INT;
+ }
+ valuePtr->intValue = valuePtr->intValue || value2.intValue;
+ break;
+
+ case COLON:
+ interp->result = "can't have : operator without ? first";
+ result = TCL_ERROR;
+ goto done;
+ }
+ }
+
+ done:
+ if (value2.pv.buffer != value2.staticSpace) {
+ ckfree(value2.pv.buffer);
+ }
+ return result;
+
+ syntaxError:
+ Tcl_AppendResult(interp, "syntax error in expression \"",
+ infoPtr->originalExpr, "\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+
+ illegalType:
+ Tcl_AppendResult(interp, "can't use ", (badType == TYPE_DOUBLE) ?
+ "floating-point value" : "non-numeric string",
+ " as operand of \"", operatorStrings[operator], "\"",
+ (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ExprMakeString --
+ *
+ * Convert a value from int or double representation to
+ * a string.
+ *
+ * Results:
+ * The information at *valuePtr gets converted to string
+ * format, if it wasn't that way already.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+ExprMakeString(interp, valuePtr)
+ Tcl_Interp *interp; /* Interpreter to use for precision
+ * information. */
+ register Value *valuePtr; /* Value to be converted. */
+{
+ int shortfall;
+
+ shortfall = 150 - (valuePtr->pv.end - valuePtr->pv.buffer);
+ if (shortfall > 0) {
+ (*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);
+ }
+ if (valuePtr->type == TYPE_INT) {
+ sprintf(valuePtr->pv.buffer, "%ld", valuePtr->intValue);
+ } else if (valuePtr->type == TYPE_DOUBLE) {
+ Tcl_PrintDouble(interp, valuePtr->doubleValue, valuePtr->pv.buffer);
+ }
+ valuePtr->type = TYPE_STRING;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ExprTopLevel --
+ *
+ * This procedure provides top-level functionality shared by
+ * procedures like Tcl_ExprInt, Tcl_ExprDouble, etc.
+ *
+ * Results:
+ * The result is a standard Tcl return value. If an error
+ * occurs then an error message is left in interp->result.
+ * The value of the expression is returned in *valuePtr, in
+ * whatever form it ends up in (could be string or integer
+ * or double). Caller may need to convert result. Caller
+ * is also responsible for freeing string memory in *valuePtr,
+ * if any was allocated.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ExprTopLevel(interp, string, valuePtr)
+ Tcl_Interp *interp; /* Context in which to evaluate the
+ * expression. */
+ char *string; /* Expression to evaluate. */
+ Value *valuePtr; /* Where to store result. Should
+ * not be initialized by caller. */
+{
+ ExprInfo info;
+ int result;
+
+ /*
+ * Create the math functions the first time an expression is
+ * evaluated.
+ */
+
+ if (!(((Interp *) interp)->flags & EXPR_INITIALIZED)) {
+ BuiltinFunc *funcPtr;
+
+ ((Interp *) interp)->flags |= EXPR_INITIALIZED;
+ for (funcPtr = funcTable; funcPtr->name != NULL;
+ funcPtr++) {
+ Tcl_CreateMathFunc(interp, funcPtr->name, funcPtr->numArgs,
+ funcPtr->argTypes, funcPtr->proc, funcPtr->clientData);
+ }
+ }
+
+ info.originalExpr = string;
+ info.expr = string;
+ valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->staticSpace;
+ valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1;
+ valuePtr->pv.expandProc = TclExpandParseValue;
+ valuePtr->pv.clientData = (ClientData) NULL;
+
+ result = ExprGetValue(interp, &info, -1, valuePtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (info.token != END) {
+ Tcl_AppendResult(interp, "syntax error in expression \"",
+ string, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if ((valuePtr->type == TYPE_DOUBLE) && (IS_NAN(valuePtr->doubleValue)
+ || IS_INF(valuePtr->doubleValue))) {
+ /*
+ * IEEE floating-point error.
+ */
+
+ ExprFloatError(interp, valuePtr->doubleValue);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean --
+ *
+ * Procedures to evaluate an expression and return its value
+ * in a particular form.
+ *
+ * Results:
+ * Each of the procedures below returns a standard Tcl result.
+ * If an error occurs then an error message is left in
+ * interp->result. Otherwise the value of the expression,
+ * in the appropriate form, is stored at *resultPtr. If
+ * the expression had a result that was incompatible with the
+ * desired form then an error is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+Tcl_ExprLong(interp, string, ptr)
+ Tcl_Interp *interp; /* Context in which to evaluate the
+ * expression. */
+ char *string; /* Expression to evaluate. */
+ long *ptr; /* Where to store result. */
+{
+ Value value;
+ int result;
+
+ result = ExprTopLevel(interp, string, &value);
+ if (result == TCL_OK) {
+ if (value.type == TYPE_INT) {
+ *ptr = value.intValue;
+ } else if (value.type == TYPE_DOUBLE) {
+ *ptr = value.doubleValue;
+ } else {
+ interp->result = "expression didn't have numeric value";
+ result = TCL_ERROR;
+ }
+ }
+ if (value.pv.buffer != value.staticSpace) {
+ ckfree(value.pv.buffer);
+ }
+ return result;
+}
+
+int
+Tcl_ExprDouble(interp, string, ptr)
+ Tcl_Interp *interp; /* Context in which to evaluate the
+ * expression. */
+ char *string; /* Expression to evaluate. */
+ double *ptr; /* Where to store result. */
+{
+ Value value;
+ int result;
+
+ result = ExprTopLevel(interp, string, &value);
+ if (result == TCL_OK) {
+ if (value.type == TYPE_INT) {
+ *ptr = value.intValue;
+ } else if (value.type == TYPE_DOUBLE) {
+ *ptr = value.doubleValue;
+ } else {
+ interp->result = "expression didn't have numeric value";
+ result = TCL_ERROR;
+ }
+ }
+ if (value.pv.buffer != value.staticSpace) {
+ ckfree(value.pv.buffer);
+ }
+ return result;
+}
+
+int
+Tcl_ExprBoolean(interp, string, ptr)
+ Tcl_Interp *interp; /* Context in which to evaluate the
+ * expression. */
+ char *string; /* Expression to evaluate. */
+ int *ptr; /* Where to store 0/1 result. */
+{
+ Value value;
+ int result;
+
+ result = ExprTopLevel(interp, string, &value);
+ if (result == TCL_OK) {
+ if (value.type == TYPE_INT) {
+ *ptr = value.intValue != 0;
+ } else if (value.type == TYPE_DOUBLE) {
+ *ptr = value.doubleValue != 0.0;
+ } else {
+ result = Tcl_GetBoolean(interp, value.pv.buffer, ptr);
+ }
+ }
+ if (value.pv.buffer != value.staticSpace) {
+ ckfree(value.pv.buffer);
+ }
+ return result;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tcl_ExprString --
+ *
+ * Evaluate an expression and return its value in string form.
+ *
+ * Results:
+ * A standard Tcl result. If the result is TCL_OK, then the
+ * interpreter's result is set to the string value of the
+ * expression. If the result is TCL_OK, then interp->result
+ * contains an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+Tcl_ExprString(interp, string)
+ Tcl_Interp *interp; /* Context in which to evaluate the
+ * expression. */
+ char *string; /* Expression to evaluate. */
+{
+ Value value;
+ int result;
+
+ result = ExprTopLevel(interp, string, &value);
+ if (result == TCL_OK) {
+ if (value.type == TYPE_INT) {
+ sprintf(interp->result, "%ld", value.intValue);
+ } else if (value.type == TYPE_DOUBLE) {
+ Tcl_PrintDouble(interp, value.doubleValue, interp->result);
+ } else {
+ if (value.pv.buffer != value.staticSpace) {
+ interp->result = value.pv.buffer;
+ interp->freeProc = (Tcl_FreeProc *) free;
+ value.pv.buffer = value.staticSpace;
+ } else {
+ Tcl_SetResult(interp, value.pv.buffer, TCL_VOLATILE);
+ }
+ }
+ }
+ if (value.pv.buffer != value.staticSpace) {
+ ckfree(value.pv.buffer);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreateMathFunc --
+ *
+ * Creates a new math function for expressions in a given
+ * interpreter.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The function defined by "name" is created; if such a function
+ * already existed then its definition is overriden.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter in which function is
+ * to be available. */
+ char *name; /* Name of function (e.g. "sin"). */
+ int numArgs; /* Nnumber of arguments required by
+ * function. */
+ Tcl_ValueType *argTypes; /* Array of types acceptable for
+ * each argument. */
+ Tcl_MathProc *proc; /* Procedure that implements the
+ * math function. */
+ ClientData clientData; /* Additional value to pass to the
+ * function. */
+{
+ Interp *iPtr = (Interp *) interp;
+ Tcl_HashEntry *hPtr;
+ MathFunc *mathFuncPtr;
+ int new, i;
+
+ hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new);
+ if (new) {
+ Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc)));
+ }
+ mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
+ if (numArgs > MAX_MATH_ARGS) {
+ numArgs = MAX_MATH_ARGS;
+ }
+ mathFuncPtr->numArgs = numArgs;
+ for (i = 0; i < numArgs; i++) {
+ mathFuncPtr->argTypes[i] = argTypes[i];
+ }
+ mathFuncPtr->proc = proc;
+ mathFuncPtr->clientData = clientData;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ExprMathFunc --
+ *
+ * This procedure is invoked to parse a math function from an
+ * expression string, carry out the function, and return the
+ * value computed.
+ *
+ * Results:
+ * TCL_OK is returned if all went well and the function's value
+ * was computed successfully. If an error occurred, TCL_ERROR
+ * is returned and an error message is left in interp->result.
+ * After a successful return infoPtr has been updated to refer
+ * to the character just after the function call, the token is
+ * set to VALUE, and the value is stored in valuePtr.
+ *
+ * Side effects:
+ * Embedded commands could have arbitrary side-effects.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+ExprMathFunc(interp, infoPtr, valuePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error
+ * reporting. */
+ register ExprInfo *infoPtr; /* Describes the state of the parse.
+ * infoPtr->expr must point to the
+ * first character of the function's
+ * name. */
+ register Value *valuePtr; /* Where to store value, if that is
+ * what's parsed from string. Caller
+ * must have initialized pv field
+ * correctly. */
+{
+ Interp *iPtr = (Interp *) interp;
+ MathFunc *mathFuncPtr; /* Info about math function. */
+ Tcl_Value args[MAX_MATH_ARGS]; /* Arguments for function call. */
+ Tcl_Value funcResult; /* Result of function call. */
+ Tcl_HashEntry *hPtr;
+ char *p, *funcName;
+ int i, savedChar, result;
+
+ /*
+ * Find the end of the math function's name and lookup the MathFunc
+ * record for the function.
+ */
+
+ p = funcName = infoPtr->expr;
+ while (isalnum(UCHAR(*p)) || (*p == '_')) {
+ p++;
+ }
+ infoPtr->expr = p;
+ result = ExprLex(interp, infoPtr, valuePtr);
+ if ((result != TCL_OK) || (infoPtr->token != OPEN_PAREN)) {
+ goto syntaxError;
+ }
+ savedChar = *p;
+ *p = 0;
+ hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
+ if (hPtr == NULL) {
+ Tcl_AppendResult(interp, "unknown math function \"", funcName,
+ "\"", (char *) NULL);
+ *p = savedChar;
+ return TCL_ERROR;
+ }
+ *p = savedChar;
+ mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
+
+ /*
+ * Scan off the arguments for the function, if there are any.
+ */
+
+ if (mathFuncPtr->numArgs == 0) {
+ result = ExprLex(interp, infoPtr, valuePtr);
+ if ((result != TCL_OK) || (infoPtr->token != CLOSE_PAREN)) {
+ goto syntaxError;
+ }
+ } else {
+ for (i = 0; ; i++) {
+ valuePtr->pv.next = valuePtr->pv.buffer;
+ result = ExprGetValue(interp, infoPtr, -1, valuePtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (valuePtr->type == TYPE_STRING) {
+ interp->result =
+ "argument to math function didn't have numeric value";
+ return TCL_ERROR;
+ }
+
+ /*
+ * Copy the value to the argument record, converting it if
+ * necessary.
+ */
+
+ if (valuePtr->type == TYPE_INT) {
+ if (mathFuncPtr->argTypes[i] == TCL_DOUBLE) {
+ args[i].type = TCL_DOUBLE;
+ args[i].doubleValue = valuePtr->intValue;
+ } else {
+ args[i].type = TCL_INT;
+ args[i].intValue = valuePtr->intValue;
+ }
+ } else {
+ if (mathFuncPtr->argTypes[i] == TCL_INT) {
+ args[i].type = TCL_INT;
+ args[i].intValue = valuePtr->doubleValue;
+ } else {
+ args[i].type = TCL_DOUBLE;
+ args[i].doubleValue = valuePtr->doubleValue;
+ }
+ }
+
+ /*
+ * Check for a comma separator between arguments or a close-paren
+ * to end the argument list.
+ */
+
+ if (i == (mathFuncPtr->numArgs-1)) {
+ if (infoPtr->token == CLOSE_PAREN) {
+ break;
+ }
+ if (infoPtr->token == COMMA) {
+ interp->result = "too many arguments for math function";
+ return TCL_ERROR;
+ } else {
+ goto syntaxError;
+ }
+ }
+ if (infoPtr->token != COMMA) {
+ if (infoPtr->token == CLOSE_PAREN) {
+ interp->result = "too few arguments for math function";
+ return TCL_ERROR;
+ } else {
+ goto syntaxError;
+ }
+ }
+ }
+ }
+
+ /*
+ * Invoke the function and copy its result back into valuePtr.
+ */
+
+ tcl_MathInProgress++;
+ result = (*mathFuncPtr->proc)(mathFuncPtr->clientData, interp, args,
+ &funcResult);
+ tcl_MathInProgress--;
+ if (result != TCL_OK) {
+ return result;
+ }
+ if (funcResult.type == TCL_INT) {
+ valuePtr->type = TYPE_INT;
+ valuePtr->intValue = funcResult.intValue;
+ } else {
+ valuePtr->type = TYPE_DOUBLE;
+ valuePtr->doubleValue = funcResult.doubleValue;
+ }
+ infoPtr->token = VALUE;
+ return TCL_OK;
+
+ syntaxError:
+ Tcl_AppendResult(interp, "syntax error in expression \"",
+ infoPtr->originalExpr, "\"", (char *) NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ExprFloatError --
+ *
+ * This procedure is called when an error occurs during a
+ * floating-point operation. It reads errno and sets
+ * interp->result accordingly.
+ *
+ * Results:
+ * Interp->result is set to hold an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ExprFloatError(interp, value)
+ Tcl_Interp *interp; /* Where to store error message. */
+ double value; /* Value returned after error; used to
+ * distinguish underflows from overflows. */
+{
+ char buf[20];
+
+ if ((errno == EDOM) || (value != value)) {
+ interp->result = "domain error: argument not in valid range";
+ Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", interp->result,
+ (char *) NULL);
+ } else if ((errno == ERANGE) || IS_INF(value)) {
+ if (value == 0.0) {
+ interp->result = "floating-point value too small to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", interp->result,
+ (char *) NULL);
+ } else {
+ interp->result = "floating-point value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", interp->result,
+ (char *) NULL);
+ }
+ } else {
+ sprintf(buf, "%d", errno);
+ Tcl_AppendResult(interp, "unknown floating-point error, ",
+ "errno = ", buf, (char *) NULL);
+ Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", interp->result,
+ (char *) NULL);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Math Functions --
+ *
+ * This page contains the procedures that implement all of the
+ * built-in math functions for expressions.
+ *
+ * Results:
+ * Each procedure returns TCL_OK if it succeeds and places result
+ * information at *resultPtr. If it fails it returns TCL_ERROR
+ * and leaves an error message in interp->result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+ExprUnaryFunc(clientData, interp, args, resultPtr)
+ ClientData clientData; /* Contains address of procedure that
+ * takes one double argument and
+ * returns a double result. */
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ double (*func)() = (double (*)()) clientData;
+
+ errno = 0;
+ resultPtr->type = TCL_DOUBLE;
+ resultPtr->doubleValue = (*func)(args[0].doubleValue);
+ if (errno != 0) {
+ ExprFloatError(interp, resultPtr->doubleValue);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+static int
+ExprBinaryFunc(clientData, interp, args, resultPtr)
+ ClientData clientData; /* Contains address of procedure that
+ * takes two double arguments and
+ * returns a double result. */
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ double (*func)() = (double (*)()) clientData;
+
+ errno = 0;
+ resultPtr->type = TCL_DOUBLE;
+ resultPtr->doubleValue = (*func)(args[0].doubleValue, args[1].doubleValue);
+ if (errno != 0) {
+ ExprFloatError(interp, resultPtr->doubleValue);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+ /* ARGSUSED */
+static int
+ExprAbsFunc(clientData, interp, args, resultPtr)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ resultPtr->type = TCL_DOUBLE;
+ if (args[0].type == TCL_DOUBLE) {
+ resultPtr->type = TCL_DOUBLE;
+ if (args[0].doubleValue < 0) {
+ resultPtr->doubleValue = -args[0].doubleValue;
+ } else {
+ resultPtr->doubleValue = args[0].doubleValue;
+ }
+ } else {
+ resultPtr->type = TCL_INT;
+ if (args[0].intValue < 0) {
+ resultPtr->intValue = -args[0].intValue;
+ if (resultPtr->intValue < 0) {
+ interp->result = "integer value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", interp->result,
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ } else {
+ resultPtr->intValue = args[0].intValue;
+ }
+ }
+ return TCL_OK;
+}
+
+ /* ARGSUSED */
+static int
+ExprDoubleFunc(clientData, interp, args, resultPtr)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ resultPtr->type = TCL_DOUBLE;
+ if (args[0].type == TCL_DOUBLE) {
+ resultPtr->doubleValue = args[0].doubleValue;
+ } else {
+ resultPtr->doubleValue = args[0].intValue;
+ }
+ return TCL_OK;
+}
+
+ /* ARGSUSED */
+static int
+ExprIntFunc(clientData, interp, args, resultPtr)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ resultPtr->type = TCL_INT;
+ if (args[0].type == TCL_INT) {
+ resultPtr->intValue = args[0].intValue;
+ } else {
+ if (args[0].doubleValue < 0) {
+ if (args[0].doubleValue < (double) (long) LONG_MIN) {
+ tooLarge:
+ interp->result = "integer value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
+ interp->result, (char *) NULL);
+ return TCL_ERROR;
+ }
+ } else {
+ if (args[0].doubleValue > (double) LONG_MAX) {
+ goto tooLarge;
+ }
+ }
+ resultPtr->intValue = args[0].doubleValue;
+ }
+ return TCL_OK;
+}
+
+ /* ARGSUSED */
+static int
+ExprRoundFunc(clientData, interp, args, resultPtr)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ Tcl_Value *args;
+ Tcl_Value *resultPtr;
+{
+ resultPtr->type = TCL_INT;
+ if (args[0].type == TCL_INT) {
+ resultPtr->intValue = args[0].intValue;
+ } else {
+ if (args[0].doubleValue < 0) {
+ if (args[0].doubleValue <= (((double) (long) LONG_MIN) - 0.5)) {
+ tooLarge:
+ interp->result = "integer value too large to represent";
+ Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
+ interp->result, (char *) NULL);
+ return TCL_ERROR;
+ }
+ resultPtr->intValue = (args[0].doubleValue - 0.5);
+ } else {
+ if (args[0].doubleValue >= (((double) LONG_MAX + 0.5))) {
+ goto tooLarge;
+ }
+ resultPtr->intValue = (args[0].doubleValue + 0.5);
+ }
+ }
+ return TCL_OK;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclGet.c b/vendor/x11iraf/obm/Tcl/tclGet.c
new file mode 100644
index 00000000..fe280e6b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclGet.c
@@ -0,0 +1,210 @@
+/*
+ * tclGet.c --
+ *
+ * This file contains procedures to convert strings into
+ * other forms, like integers or floating-point numbers or
+ * booleans, doing syntax checking along the way.
+ *
+ * Copyright (c) 1990-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclGet.c,v 1.14 93/08/18 16:07:24 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetInt --
+ *
+ * Given a string, produce the corresponding integer value.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *intPtr
+ * will be set to the integer value equivalent to string. If
+ * string is improperly formed then TCL_ERROR is returned and
+ * an error message will be left in interp->result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetInt(interp, string, intPtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ char *string; /* String containing a (possibly signed)
+ * integer in a form acceptable to strtol. */
+ int *intPtr; /* Place to store converted result. */
+{
+ char *end, *p;
+ int i;
+
+ /*
+ * Note: use strtoul instead of strtol for integer conversions
+ * to allow full-size unsigned numbers, but don't depend on strtoul
+ * to handle sign characters; it won't in some implementations.
+ */
+
+ for (p = string; isspace(UCHAR(*p)); p++) {
+ /* Empty loop body. */
+ }
+ if (*p == '-') {
+ i = -strtoul(p+1, &end, 0);
+ } else if (*p == '+') {
+ i = strtoul(p+1, &end, 0);
+ } else {
+ i = strtoul(p, &end, 0);
+ }
+ while ((*end != '\0') && isspace(UCHAR(*end))) {
+ end++;
+ }
+ if ((end == string) || (*end != 0)) {
+ Tcl_AppendResult(interp, "expected integer but got \"", string,
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ *intPtr = i;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetDouble --
+ *
+ * Given a string, produce the corresponding double-precision
+ * floating-point value.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *doublePtr
+ * will be set to the double-precision value equivalent to string.
+ * If string is improperly formed then TCL_ERROR is returned and
+ * an error message will be left in interp->result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetDouble(interp, string, doublePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ char *string; /* String containing a floating-point number
+ * in a form acceptable to strtod. */
+ double *doublePtr; /* Place to store converted result. */
+{
+ char *end;
+ double d;
+
+ d = strtod(string, &end);
+ while ((*end != '\0') && isspace(UCHAR(*end))) {
+ end++;
+ }
+ if ((end == string) || (*end != 0)) {
+ Tcl_AppendResult(interp, "expected floating-point number but got \"",
+ string, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ *doublePtr = d;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetBoolean --
+ *
+ * Given a string, return a 0/1 boolean value corresponding
+ * to the string.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *boolPtr
+ * will be set to the 0/1 value equivalent to string. If
+ * string is improperly formed then TCL_ERROR is returned and
+ * an error message will be left in interp->result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetBoolean(interp, string, boolPtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ char *string; /* String containing a boolean number
+ * specified either as 1/0 or true/false or
+ * yes/no. */
+ int *boolPtr; /* Place to store converted result, which
+ * will be 0 or 1. */
+{
+ char c;
+ char lowerCase[10];
+ int i, length;
+
+ /*
+ * Convert the input string to all lower-case.
+ */
+
+ for (i = 0; i < 9; i++) {
+ c = string[i];
+ if (c == 0) {
+ break;
+ }
+ if ((c >= 'A') && (c <= 'Z')) {
+ c += 'a' - 'A';
+ }
+ lowerCase[i] = c;
+ }
+ lowerCase[i] = 0;
+
+ length = strlen(lowerCase);
+ c = lowerCase[0];
+ if ((c == '0') && (lowerCase[1] == '\0')) {
+ *boolPtr = 0;
+ } else if ((c == '1') && (lowerCase[1] == '\0')) {
+ *boolPtr = 1;
+ } else if ((c == 'y') && (strncmp(lowerCase, "yes", length) == 0)) {
+ *boolPtr = 1;
+ } else if ((c == 'n') && (strncmp(lowerCase, "no", length) == 0)) {
+ *boolPtr = 0;
+ } else if ((c == 't') && (strncmp(lowerCase, "true", length) == 0)) {
+ *boolPtr = 1;
+ } else if ((c == 'f') && (strncmp(lowerCase, "false", length) == 0)) {
+ *boolPtr = 0;
+ } else if ((c == 'o') && (length >= 2)) {
+ if (strncmp(lowerCase, "on", length) == 0) {
+ *boolPtr = 1;
+ } else if (strncmp(lowerCase, "off", length) == 0) {
+ *boolPtr = 0;
+ }
+ } else {
+ Tcl_AppendResult(interp, "expected boolean value but got \"",
+ string, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclGlob.c b/vendor/x11iraf/obm/Tcl/tclGlob.c
new file mode 100644
index 00000000..a7f29d3d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclGlob.c
@@ -0,0 +1,455 @@
+/*
+ * tclGlob.c --
+ *
+ * This file provides procedures and commands for file name
+ * manipulation, such as tilde expansion and globbing.
+ *
+ * Copyright (c) 1990-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclGlob.c,v 1.36 93/10/14 15:14:08 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ * The structure below is used to keep track of a globbing result
+ * being built up (i.e. a partial list of file names). The list
+ * grows dynamically to be as big as needed.
+ */
+
+typedef struct {
+ char *result; /* Pointer to result area. */
+ int totalSpace; /* Total number of characters allocated
+ * for result. */
+ int spaceUsed; /* Number of characters currently in use
+ * to hold the partial result (not including
+ * the terminating NULL). */
+ int dynamic; /* 0 means result is static space, 1 means
+ * it's dynamic. */
+} GlobResult;
+
+/*
+ * Declarations for procedures local to this file:
+ */
+
+static int DoGlob _ANSI_ARGS_((Tcl_Interp *interp, char *dir,
+ char *rem));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DoGlob --
+ *
+ * This recursive procedure forms the heart of the globbing
+ * code. It performs a depth-first traversal of the tree
+ * given by the path name to be globbed.
+ *
+ * Results:
+ * The return value is a standard Tcl result indicating whether
+ * an error occurred in globbing. After a normal return the
+ * result in interp will be set to hold all of the file names
+ * given by the dir and rem arguments. After an error the
+ * result in interp will hold an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+DoGlob(interp, dir, rem)
+ Tcl_Interp *interp; /* Interpreter to use for error
+ * reporting (e.g. unmatched brace). */
+ char *dir; /* Name of a directory at which to
+ * start glob expansion. This name
+ * is fixed: it doesn't contain any
+ * globbing chars. */
+ char *rem; /* Path to glob-expand. */
+{
+ /*
+ * When this procedure is entered, the name to be globbed may
+ * already have been partly expanded by ancestor invocations of
+ * DoGlob. The part that's already been expanded is in "dir"
+ * (this may initially be empty), and the part still to expand
+ * is in "rem". This procedure expands "rem" one level, making
+ * recursive calls to itself if there's still more stuff left
+ * in the remainder.
+ */
+
+ Tcl_DString newName; /* Holds new name consisting of
+ * dir plus the first part of rem. */
+ register char *p;
+ register char c;
+ char *openBrace, *closeBrace, *name, *dirName;
+ int gotSpecial, baseLength;
+ int result = TCL_OK;
+ struct stat statBuf;
+
+ /*
+ * Make sure that the directory part of the name really is a
+ * directory. If the directory name is "", use the name "."
+ * instead, because some UNIX systems don't treat "" like "."
+ * automatically. Keep the "" for use in generating file names,
+ * otherwise "glob foo.c" would return "./foo.c".
+ */
+
+ if (*dir == '\0') {
+ dirName = ".";
+ } else {
+ dirName = dir;
+ }
+ if ((stat(dirName, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) {
+ return TCL_OK;
+ }
+ Tcl_DStringInit(&newName);
+
+ /*
+ * First, find the end of the next element in rem, checking
+ * along the way for special globbing characters.
+ */
+
+ gotSpecial = 0;
+ openBrace = closeBrace = NULL;
+ for (p = rem; ; p++) {
+ c = *p;
+ if ((c == '\0') || ((openBrace == NULL) && (c == '/'))) {
+ break;
+ }
+ if ((c == '{') && (openBrace == NULL)) {
+ openBrace = p;
+ }
+ if ((c == '}') && (openBrace != NULL) && (closeBrace == NULL)) {
+ closeBrace = p;
+ }
+ if ((c == '*') || (c == '[') || (c == '\\') || (c == '?')) {
+ gotSpecial = 1;
+ }
+ }
+
+ /*
+ * If there is an open brace in the argument, then make a recursive
+ * call for each element between the braces. In this case, the
+ * recursive call to DoGlob uses the same "dir" that we got.
+ * If there are several brace-pairs in a single name, we just handle
+ * one here, and the others will be handled in recursive calls.
+ */
+
+ if (openBrace != NULL) {
+ char *element;
+
+ if (closeBrace == NULL) {
+ Tcl_ResetResult(interp);
+ interp->result = "unmatched open-brace in file name";
+ result = TCL_ERROR;
+ goto done;
+ }
+ Tcl_DStringAppend(&newName, rem, openBrace-rem);
+ baseLength = newName.length;
+ for (p = openBrace; *p != '}'; ) {
+ element = p+1;
+ for (p = element; ((*p != '}') && (*p != ',')); p++) {
+ /* Empty loop body. */
+ }
+ Tcl_DStringAppend(&newName, element, p-element);
+ Tcl_DStringAppend(&newName, closeBrace+1, -1);
+ result = DoGlob(interp, dir, newName.string);
+ if (result != TCL_OK) {
+ goto done;
+ }
+ newName.length = baseLength;
+ }
+ goto done;
+ }
+
+ /*
+ * Start building up the next-level name with dir plus a slash if
+ * needed to separate it from the next file name.
+ */
+
+ Tcl_DStringAppend(&newName, dir, -1);
+ if ((dir[0] != 0) && (newName.string[newName.length-1] != '/')) {
+ Tcl_DStringAppend(&newName, "/", 1);
+ }
+ baseLength = newName.length;
+
+ /*
+ * If there were any pattern-matching characters, then scan through
+ * the directory to find all the matching names.
+ */
+
+ if (gotSpecial) {
+ DIR *d;
+ struct dirent *entryPtr;
+ char savedChar;
+
+ d = opendir(dirName);
+ if (d == NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "couldn't read directory \"",
+ dirName, "\": ", Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ /*
+ * Temporarily store a null into rem so that the pattern string
+ * is now null-terminated.
+ */
+
+ savedChar = *p;
+ *p = 0;
+
+ while (1) {
+ entryPtr = readdir(d);
+ if (entryPtr == NULL) {
+ break;
+ }
+
+ /*
+ * Don't match names starting with "." unless the "." is
+ * present in the pattern.
+ */
+
+ if ((*entryPtr->d_name == '.') && (*rem != '.')) {
+ continue;
+ }
+ if (Tcl_StringMatch(entryPtr->d_name, rem)) {
+ newName.length = baseLength;
+ Tcl_DStringAppend(&newName, entryPtr->d_name, -1);
+ if (savedChar == 0) {
+ Tcl_AppendElement(interp, newName.string);
+ } else {
+ result = DoGlob(interp, newName.string, p+1);
+ if (result != TCL_OK) {
+ break;
+ }
+ }
+ }
+ }
+ closedir(d);
+ *p = savedChar;
+ goto done;
+ }
+
+ /*
+ * The current element is a simple one with no fancy features. Add
+ * it to the new name. If there are more elements still to come,
+ * then recurse to process them.
+ */
+
+ Tcl_DStringAppend(&newName, rem, p-rem);
+ if (*p != 0) {
+ result = DoGlob(interp, newName.string, p+1);
+ goto done;
+ }
+
+ /*
+ * There are no more elements in the pattern. Check to be sure the
+ * file actually exists, then add its name to the list being formed
+ * in interp-result.
+ */
+
+ name = newName.string;
+ if (*name == 0) {
+ name = ".";
+ }
+ if (access(name, F_OK) != 0) {
+ goto done;
+ }
+ Tcl_AppendElement(interp, name);
+
+ done:
+ Tcl_DStringFree(&newName);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TildeSubst --
+ *
+ * Given a name starting with a tilde, produce a name where
+ * the tilde and following characters have been replaced by
+ * the home directory location for the named user.
+ *
+ * Results:
+ * The result is a pointer to a static string containing
+ * the new name. If there was an error in processing the
+ * tilde, then an error message is left in interp->result
+ * and the return value is NULL. The result may be stored
+ * in bufferPtr; the caller must call Tcl_DStringFree(bufferPtr)
+ * to free the name.
+ *
+ * Side effects:
+ * Information may be left in bufferPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_TildeSubst(interp, name, bufferPtr)
+ Tcl_Interp *interp; /* Interpreter in which to store error
+ * message (if necessary). */
+ char *name; /* File name, which may begin with "~/"
+ * (to indicate current user's home directory)
+ * or "~<user>/" (to indicate any user's
+ * home directory). */
+ Tcl_DString *bufferPtr; /* May be used to hold result. Must not hold
+ * anything at the time of the call, and need
+ * not even be initialized. */
+{
+ char *dir;
+ register char *p;
+
+ Tcl_DStringInit(bufferPtr);
+ if (name[0] != '~') {
+ return name;
+ }
+
+ if ((name[1] == '/') || (name[1] == '\0')) {
+ dir = getenv("HOME");
+ if (dir == NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "couldn't find HOME environment ",
+ "variable to expand \"", name, "\"", (char *) NULL);
+ return NULL;
+ }
+ Tcl_DStringAppend(bufferPtr, dir, -1);
+ Tcl_DStringAppend(bufferPtr, name+1, -1);
+ } else {
+ struct passwd *pwPtr;
+
+ for (p = &name[1]; (*p != 0) && (*p != '/'); p++) {
+ /* Null body; just find end of name. */
+ }
+ Tcl_DStringAppend(bufferPtr, name+1, p - (name+1));
+ pwPtr = getpwnam(bufferPtr->string);
+ if (pwPtr == NULL) {
+ endpwent();
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "user \"", bufferPtr->string,
+ "\" doesn't exist", (char *) NULL);
+ return NULL;
+ }
+ Tcl_DStringFree(bufferPtr);
+ Tcl_DStringAppend(bufferPtr, pwPtr->pw_dir, -1);
+ Tcl_DStringAppend(bufferPtr, p, -1);
+ endpwent();
+ }
+ return bufferPtr->string;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GlobCmd --
+ *
+ * This procedure is invoked to process the "glob" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_GlobCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i, result, noComplain, firstArg;
+
+ if (argc < 2) {
+ notEnoughArgs:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?switches? name ?name ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ noComplain = 0;
+ for (firstArg = 1; (firstArg < argc) && (argv[firstArg][0] == '-');
+ firstArg++) {
+ if (strcmp(argv[firstArg], "-nocomplain") == 0) {
+ noComplain = 1;
+ } else if (strcmp(argv[firstArg], "--") == 0) {
+ firstArg++;
+ break;
+ } else {
+ Tcl_AppendResult(interp, "bad switch \"", argv[firstArg],
+ "\": must be -nocomplain or --", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (firstArg >= argc) {
+ goto notEnoughArgs;
+ }
+
+ for (i = firstArg; i < argc; i++) {
+ char *thisName;
+ Tcl_DString buffer;
+
+ thisName = Tcl_TildeSubst(interp, argv[i], &buffer);
+ if (thisName == NULL) {
+ return TCL_ERROR;
+ }
+ if (*thisName == '/') {
+ if (thisName[1] == '/') {
+ /*
+ * This is a special hack for systems like those from Apollo
+ * where there is a super-root at "//": need to treat the
+ * double-slash as a single name.
+ */
+ result = DoGlob(interp, "//", thisName+2);
+ } else {
+ result = DoGlob(interp, "/", thisName+1);
+ }
+ } else {
+ result = DoGlob(interp, "", thisName);
+ }
+ Tcl_DStringFree(&buffer);
+ if (result != TCL_OK) {
+ return result;
+ }
+ }
+ if ((*interp->result == 0) && !noComplain) {
+ char *sep = "";
+
+ Tcl_AppendResult(interp, "no files matched glob pattern",
+ (argc == 2) ? " \"" : "s \"", (char *) NULL);
+ for (i = firstArg; i < argc; i++) {
+ Tcl_AppendResult(interp, sep, argv[i], (char *) NULL);
+ sep = " ";
+ }
+ Tcl_AppendResult(interp, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclHash.c b/vendor/x11iraf/obm/Tcl/tclHash.c
new file mode 100644
index 00000000..1c4ac37c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclHash.c
@@ -0,0 +1,937 @@
+/*
+ * tclHash.c --
+ *
+ * Implementation of in-memory hash tables for Tcl and Tcl-based
+ * applications.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclHash.c,v 1.13 93/06/02 10:17:13 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+
+/*
+ * When there are this many entries per bucket, on average, rebuild
+ * the hash table to make it larger.
+ */
+
+#define REBUILD_MULTIPLIER 3
+
+
+/*
+ * The following macro takes a preliminary integer hash value and
+ * produces an index into a hash tables bucket list. The idea is
+ * to make it so that preliminary values that are arbitrarily similar
+ * will end up in different buckets. The hash function was taken
+ * from a random-number generator.
+ */
+
+#define RANDOM_INDEX(tablePtr, i) \
+ (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
+
+/*
+ * Procedure prototypes for static procedures in this file:
+ */
+
+static Tcl_HashEntry * ArrayFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key));
+static Tcl_HashEntry * ArrayCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key, int *newPtr));
+static Tcl_HashEntry * BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key));
+static Tcl_HashEntry * BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key, int *newPtr));
+static unsigned int HashString _ANSI_ARGS_((char *string));
+static void RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr));
+static Tcl_HashEntry * StringFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key));
+static Tcl_HashEntry * StringCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key, int *newPtr));
+static Tcl_HashEntry * OneWordFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key));
+static Tcl_HashEntry * OneWordCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
+ char *key, int *newPtr));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_InitHashTable --
+ *
+ * Given storage for a hash table, set up the fields to prepare
+ * the hash table for use.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * TablePtr is now ready to be passed to Tcl_FindHashEntry and
+ * Tcl_CreateHashEntry.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_InitHashTable(tablePtr, keyType)
+ register Tcl_HashTable *tablePtr; /* Pointer to table record, which
+ * is supplied by the caller. */
+ int keyType; /* Type of keys to use in table:
+ * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
+ * or an integer >= 2. */
+{
+ tablePtr->buckets = tablePtr->staticBuckets;
+ tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
+ tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
+ tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
+ tablePtr->numEntries = 0;
+ tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
+ tablePtr->downShift = 28;
+ tablePtr->mask = 3;
+ tablePtr->keyType = keyType;
+ if (keyType == TCL_STRING_KEYS) {
+ tablePtr->findProc = StringFind;
+ tablePtr->createProc = StringCreate;
+ } else if (keyType == TCL_ONE_WORD_KEYS) {
+ tablePtr->findProc = OneWordFind;
+ tablePtr->createProc = OneWordCreate;
+ } else {
+ tablePtr->findProc = ArrayFind;
+ tablePtr->createProc = ArrayCreate;
+ };
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteHashEntry --
+ *
+ * Remove a single entry from a hash table.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The entry given by entryPtr is deleted from its table and
+ * should never again be used by the caller. It is up to the
+ * caller to free the clientData field of the entry, if that
+ * is relevant.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DeleteHashEntry(entryPtr)
+ Tcl_HashEntry *entryPtr;
+{
+ register Tcl_HashEntry *prevPtr;
+
+ if (*entryPtr->bucketPtr == entryPtr) {
+ *entryPtr->bucketPtr = entryPtr->nextPtr;
+ } else {
+ for (prevPtr = *entryPtr->bucketPtr; ; prevPtr = prevPtr->nextPtr) {
+ if (prevPtr == NULL) {
+ panic("malformed bucket chain in Tcl_DeleteHashEntry");
+ }
+ if (prevPtr->nextPtr == entryPtr) {
+ prevPtr->nextPtr = entryPtr->nextPtr;
+ break;
+ }
+ }
+ }
+ entryPtr->tablePtr->numEntries--;
+ ckfree((char *) entryPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteHashTable --
+ *
+ * Free up everything associated with a hash table except for
+ * the record for the table itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The hash table is no longer useable.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DeleteHashTable(tablePtr)
+ register Tcl_HashTable *tablePtr; /* Table to delete. */
+{
+ register Tcl_HashEntry *hPtr, *nextPtr;
+ int i;
+
+ /*
+ * Free up all the entries in the table.
+ */
+
+ for (i = 0; i < tablePtr->numBuckets; i++) {
+ hPtr = tablePtr->buckets[i];
+ while (hPtr != NULL) {
+ nextPtr = hPtr->nextPtr;
+ ckfree((char *) hPtr);
+ hPtr = nextPtr;
+ }
+ }
+
+ /*
+ * Free up the bucket array, if it was dynamically allocated.
+ */
+
+ if (tablePtr->buckets != tablePtr->staticBuckets) {
+ ckfree((char *) tablePtr->buckets);
+ }
+
+ /*
+ * Arrange for panics if the table is used again without
+ * re-initialization.
+ */
+
+ tablePtr->findProc = BogusFind;
+ tablePtr->createProc = BogusCreate;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FirstHashEntry --
+ *
+ * Locate the first entry in a hash table and set up a record
+ * that can be used to step through all the remaining entries
+ * of the table.
+ *
+ * Results:
+ * The return value is a pointer to the first entry in tablePtr,
+ * or NULL if tablePtr has no entries in it. The memory at
+ * *searchPtr is initialized so that subsequent calls to
+ * Tcl_NextHashEntry will return all of the entries in the table,
+ * one at a time.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_HashEntry *
+Tcl_FirstHashEntry(tablePtr, searchPtr)
+ Tcl_HashTable *tablePtr; /* Table to search. */
+ Tcl_HashSearch *searchPtr; /* Place to store information about
+ * progress through the table. */
+{
+ searchPtr->tablePtr = tablePtr;
+ searchPtr->nextIndex = 0;
+ searchPtr->nextEntryPtr = NULL;
+ return Tcl_NextHashEntry(searchPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_NextHashEntry --
+ *
+ * Once a hash table enumeration has been initiated by calling
+ * Tcl_FirstHashEntry, this procedure may be called to return
+ * successive elements of the table.
+ *
+ * Results:
+ * The return value is the next entry in the hash table being
+ * enumerated, or NULL if the end of the table is reached.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_HashEntry *
+Tcl_NextHashEntry(searchPtr)
+ register Tcl_HashSearch *searchPtr; /* Place to store information about
+ * progress through the table. Must
+ * have been initialized by calling
+ * Tcl_FirstHashEntry. */
+{
+ Tcl_HashEntry *hPtr;
+
+ while (searchPtr->nextEntryPtr == NULL) {
+ if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) {
+ return NULL;
+ }
+ searchPtr->nextEntryPtr =
+ searchPtr->tablePtr->buckets[searchPtr->nextIndex];
+ searchPtr->nextIndex++;
+ }
+ hPtr = searchPtr->nextEntryPtr;
+ searchPtr->nextEntryPtr = hPtr->nextPtr;
+ return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_HashStats --
+ *
+ * Return statistics describing the layout of the hash table
+ * in its hash buckets.
+ *
+ * Results:
+ * The return value is a malloc-ed string containing information
+ * about tablePtr. It is the caller's responsibility to free
+ * this string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_HashStats(tablePtr)
+ Tcl_HashTable *tablePtr; /* Table for which to produce stats. */
+{
+#define NUM_COUNTERS 10
+ int count[NUM_COUNTERS], overflow, i, j;
+ double average, tmp;
+ register Tcl_HashEntry *hPtr;
+ char *result, *p;
+
+ /*
+ * Compute a histogram of bucket usage.
+ */
+
+ for (i = 0; i < NUM_COUNTERS; i++) {
+ count[i] = 0;
+ }
+ overflow = 0;
+ average = 0.0;
+ for (i = 0; i < tablePtr->numBuckets; i++) {
+ j = 0;
+ for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) {
+ j++;
+ }
+ if (j < NUM_COUNTERS) {
+ count[j]++;
+ } else {
+ overflow++;
+ }
+ tmp = j;
+ average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
+ }
+
+ /*
+ * Print out the histogram and a few other pieces of information.
+ */
+
+ result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));
+ sprintf(result, "%d entries in table, %d buckets\n",
+ tablePtr->numEntries, tablePtr->numBuckets);
+ p = result + strlen(result);
+ for (i = 0; i < NUM_COUNTERS; i++) {
+ sprintf(p, "number of buckets with %d entries: %d\n",
+ i, count[i]);
+ p += strlen(p);
+ }
+ sprintf(p, "number of buckets with %d or more entries: %d\n",
+ NUM_COUNTERS, overflow);
+ p += strlen(p);
+ sprintf(p, "average search distance for entry: %.1f", average);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HashString --
+ *
+ * Compute a one-word summary of a text string, which can be
+ * used to generate a hash index.
+ *
+ * Results:
+ * The return value is a one-word summary of the information in
+ * string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static unsigned int
+HashString(string)
+ register char *string; /* String from which to compute hash value. */
+{
+ register unsigned int result;
+ register int c;
+
+ /*
+ * I tried a zillion different hash functions and asked many other
+ * people for advice. Many people had their own favorite functions,
+ * all different, but no-one had much idea why they were good ones.
+ * I chose the one below (multiply by 9 and add new character)
+ * because of the following reasons:
+ *
+ * 1. Multiplying by 10 is perfect for keys that are decimal strings,
+ * and multiplying by 9 is just about as good.
+ * 2. Times-9 is (shift-left-3) plus (old). This means that each
+ * character's bits hang around in the low-order bits of the
+ * hash value for ever, plus they spread fairly rapidly up to
+ * the high-order bits to fill out the hash value. This seems
+ * works well both for decimal and non-decimal strings.
+ */
+
+ result = 0;
+ while (1) {
+ c = *string;
+ string++;
+ if (c == 0) {
+ break;
+ }
+ result += (result<<3) + c;
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringFind --
+ *
+ * Given a hash table with string keys, and a string key, find
+ * the entry with a matching key.
+ *
+ * Results:
+ * The return value is a token for the matching entry in the
+ * hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+StringFind(tablePtr, key)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ char *key; /* Key to use to find matching entry. */
+{
+ register Tcl_HashEntry *hPtr;
+ register char *p1, *p2;
+ int index;
+
+ index = HashString(key) & tablePtr->mask;
+
+ /*
+ * Search all of the entries in the appropriate bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
+ if (*p1 != *p2) {
+ break;
+ }
+ if (*p1 == '\0') {
+ return hPtr;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringCreate --
+ *
+ * Given a hash table with string keys, and a string key, find
+ * the entry with a matching key. If there is no matching entry,
+ * then create a new entry that does match.
+ *
+ * Results:
+ * The return value is a pointer to the matching entry. If this
+ * is a newly-created entry, then *newPtr will be set to a non-zero
+ * value; otherwise *newPtr will be set to 0. If this is a new
+ * entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ * A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+StringCreate(tablePtr, key, newPtr)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ char *key; /* Key to use to find or create matching
+ * entry. */
+ int *newPtr; /* Store info here telling whether a new
+ * entry was created. */
+{
+ register Tcl_HashEntry *hPtr;
+ register char *p1, *p2;
+ int index;
+
+ index = HashString(key) & tablePtr->mask;
+
+ /*
+ * Search all of the entries in this bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
+ if (*p1 != *p2) {
+ break;
+ }
+ if (*p1 == '\0') {
+ *newPtr = 0;
+ return hPtr;
+ }
+ }
+ }
+
+ /*
+ * Entry not found. Add a new one to the bucket.
+ */
+
+ *newPtr = 1;
+ hPtr = (Tcl_HashEntry *) ckalloc((unsigned)
+ (sizeof(Tcl_HashEntry) + strlen(key) - (sizeof(hPtr->key) -1)));
+ hPtr->tablePtr = tablePtr;
+ hPtr->bucketPtr = &(tablePtr->buckets[index]);
+ hPtr->nextPtr = *hPtr->bucketPtr;
+ hPtr->clientData = 0;
+ strcpy(hPtr->key.string, key);
+ *hPtr->bucketPtr = hPtr;
+ tablePtr->numEntries++;
+
+ /*
+ * If the table has exceeded a decent size, rebuild it with many
+ * more buckets.
+ */
+
+ if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+ RebuildTable(tablePtr);
+ }
+ return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * OneWordFind --
+ *
+ * Given a hash table with one-word keys, and a one-word key, find
+ * the entry with a matching key.
+ *
+ * Results:
+ * The return value is a token for the matching entry in the
+ * hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+OneWordFind(tablePtr, key)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ register char *key; /* Key to use to find matching entry. */
+{
+ register Tcl_HashEntry *hPtr;
+ int index;
+
+ index = RANDOM_INDEX(tablePtr, key);
+
+ /*
+ * Search all of the entries in the appropriate bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ if (hPtr->key.oneWordValue == key) {
+ return hPtr;
+ }
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * OneWordCreate --
+ *
+ * Given a hash table with one-word keys, and a one-word key, find
+ * the entry with a matching key. If there is no matching entry,
+ * then create a new entry that does match.
+ *
+ * Results:
+ * The return value is a pointer to the matching entry. If this
+ * is a newly-created entry, then *newPtr will be set to a non-zero
+ * value; otherwise *newPtr will be set to 0. If this is a new
+ * entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ * A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+OneWordCreate(tablePtr, key, newPtr)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ register char *key; /* Key to use to find or create matching
+ * entry. */
+ int *newPtr; /* Store info here telling whether a new
+ * entry was created. */
+{
+ register Tcl_HashEntry *hPtr;
+ int index;
+
+ index = RANDOM_INDEX(tablePtr, key);
+
+ /*
+ * Search all of the entries in this bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ if (hPtr->key.oneWordValue == key) {
+ *newPtr = 0;
+ return hPtr;
+ }
+ }
+
+ /*
+ * Entry not found. Add a new one to the bucket.
+ */
+
+ *newPtr = 1;
+ hPtr = (Tcl_HashEntry *) ckalloc(sizeof(Tcl_HashEntry));
+ hPtr->tablePtr = tablePtr;
+ hPtr->bucketPtr = &(tablePtr->buckets[index]);
+ hPtr->nextPtr = *hPtr->bucketPtr;
+ hPtr->clientData = 0;
+ hPtr->key.oneWordValue = key;
+ *hPtr->bucketPtr = hPtr;
+ tablePtr->numEntries++;
+
+ /*
+ * If the table has exceeded a decent size, rebuild it with many
+ * more buckets.
+ */
+
+ if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+ RebuildTable(tablePtr);
+ }
+ return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArrayFind --
+ *
+ * Given a hash table with array-of-int keys, and a key, find
+ * the entry with a matching key.
+ *
+ * Results:
+ * The return value is a token for the matching entry in the
+ * hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+ArrayFind(tablePtr, key)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ char *key; /* Key to use to find matching entry. */
+{
+ register Tcl_HashEntry *hPtr;
+ int *arrayPtr = (int *) key;
+ register int *iPtr1, *iPtr2;
+ int index, count;
+
+ for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
+ count > 0; count--, iPtr1++) {
+ index += *iPtr1;
+ }
+ index = RANDOM_INDEX(tablePtr, index);
+
+ /*
+ * Search all of the entries in the appropriate bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words,
+ count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
+ if (count == 0) {
+ return hPtr;
+ }
+ if (*iPtr1 != *iPtr2) {
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArrayCreate --
+ *
+ * Given a hash table with one-word keys, and a one-word key, find
+ * the entry with a matching key. If there is no matching entry,
+ * then create a new entry that does match.
+ *
+ * Results:
+ * The return value is a pointer to the matching entry. If this
+ * is a newly-created entry, then *newPtr will be set to a non-zero
+ * value; otherwise *newPtr will be set to 0. If this is a new
+ * entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ * A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashEntry *
+ArrayCreate(tablePtr, key, newPtr)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ register char *key; /* Key to use to find or create matching
+ * entry. */
+ int *newPtr; /* Store info here telling whether a new
+ * entry was created. */
+{
+ register Tcl_HashEntry *hPtr;
+ int *arrayPtr = (int *) key;
+ register int *iPtr1, *iPtr2;
+ int index, count;
+
+ for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
+ count > 0; count--, iPtr1++) {
+ index += *iPtr1;
+ }
+ index = RANDOM_INDEX(tablePtr, index);
+
+ /*
+ * Search all of the entries in the appropriate bucket.
+ */
+
+ for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
+ hPtr = hPtr->nextPtr) {
+ for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words,
+ count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
+ if (count == 0) {
+ *newPtr = 0;
+ return hPtr;
+ }
+ if (*iPtr1 != *iPtr2) {
+ break;
+ }
+ }
+ }
+
+ /*
+ * Entry not found. Add a new one to the bucket.
+ */
+
+ *newPtr = 1;
+ hPtr = (Tcl_HashEntry *) ckalloc((unsigned) (sizeof(Tcl_HashEntry)
+ + (tablePtr->keyType*sizeof(int)) - 4));
+ hPtr->tablePtr = tablePtr;
+ hPtr->bucketPtr = &(tablePtr->buckets[index]);
+ hPtr->nextPtr = *hPtr->bucketPtr;
+ hPtr->clientData = 0;
+ for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words, count = tablePtr->keyType;
+ count > 0; count--, iPtr1++, iPtr2++) {
+ *iPtr2 = *iPtr1;
+ }
+ *hPtr->bucketPtr = hPtr;
+ tablePtr->numEntries++;
+
+ /*
+ * If the table has exceeded a decent size, rebuild it with many
+ * more buckets.
+ */
+
+ if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+ RebuildTable(tablePtr);
+ }
+ return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BogusFind --
+ *
+ * This procedure is invoked when an Tcl_FindHashEntry is called
+ * on a table that has been deleted.
+ *
+ * Results:
+ * If panic returns (which it shouldn't) this procedure returns
+ * NULL.
+ *
+ * Side effects:
+ * Generates a panic.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static Tcl_HashEntry *
+BogusFind(tablePtr, key)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ char *key; /* Key to use to find matching entry. */
+{
+ panic("called Tcl_FindHashEntry on deleted table");
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BogusCreate --
+ *
+ * This procedure is invoked when an Tcl_CreateHashEntry is called
+ * on a table that has been deleted.
+ *
+ * Results:
+ * If panic returns (which it shouldn't) this procedure returns
+ * NULL.
+ *
+ * Side effects:
+ * Generates a panic.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static Tcl_HashEntry *
+BogusCreate(tablePtr, key, newPtr)
+ Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
+ char *key; /* Key to use to find or create matching
+ * entry. */
+ int *newPtr; /* Store info here telling whether a new
+ * entry was created. */
+{
+ panic("called Tcl_CreateHashEntry on deleted table");
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * RebuildTable --
+ *
+ * This procedure is invoked when the ratio of entries to hash
+ * buckets becomes too large. It creates a new table with a
+ * larger bucket array and moves all of the entries into the
+ * new table.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory gets reallocated and entries get re-hashed to new
+ * buckets.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+RebuildTable(tablePtr)
+ register Tcl_HashTable *tablePtr; /* Table to enlarge. */
+{
+ int oldSize, count, index;
+ Tcl_HashEntry **oldBuckets;
+ register Tcl_HashEntry **oldChainPtr, **newChainPtr;
+ register Tcl_HashEntry *hPtr;
+
+ oldSize = tablePtr->numBuckets;
+ oldBuckets = tablePtr->buckets;
+
+ /*
+ * Allocate and initialize the new bucket array, and set up
+ * hashing constants for new array size.
+ */
+
+ tablePtr->numBuckets *= 4;
+ tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
+ (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
+ for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
+ count > 0; count--, newChainPtr++) {
+ *newChainPtr = NULL;
+ }
+ tablePtr->rebuildSize *= 4;
+ tablePtr->downShift -= 2;
+ tablePtr->mask = (tablePtr->mask << 2) + 3;
+
+ /*
+ * Rehash all of the existing entries into the new bucket array.
+ */
+
+ for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
+ for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
+ *oldChainPtr = hPtr->nextPtr;
+ if (tablePtr->keyType == TCL_STRING_KEYS) {
+ index = HashString(hPtr->key.string) & tablePtr->mask;
+ } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
+ index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
+ } else {
+ register int *iPtr;
+ int count;
+
+ for (index = 0, count = tablePtr->keyType,
+ iPtr = hPtr->key.words; count > 0; count--, iPtr++) {
+ index += *iPtr;
+ }
+ index = RANDOM_INDEX(tablePtr, index);
+ }
+ hPtr->bucketPtr = &(tablePtr->buckets[index]);
+ hPtr->nextPtr = *hPtr->bucketPtr;
+ *hPtr->bucketPtr = hPtr;
+ }
+ }
+
+ /*
+ * Free up the old bucket array, if it was dynamically allocated.
+ */
+
+ if (oldBuckets != tablePtr->staticBuckets) {
+ ckfree((char *) oldBuckets);
+ }
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclHistory.c b/vendor/x11iraf/obm/Tcl/tclHistory.c
new file mode 100644
index 00000000..5a4cadac
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclHistory.c
@@ -0,0 +1,1109 @@
+/*
+ * tclHistory.c --
+ *
+ * This module implements history as an optional addition to Tcl.
+ * It can be called to record commands ("events") before they are
+ * executed, and it provides a command that may be used to perform
+ * history substitutions.
+ *
+ * Copyright (c) 1990-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclHistory.c,v 1.30 93/10/13 13:05:38 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+
+/*
+ * This history stuff is mostly straightforward, except for one thing
+ * that makes everything very complicated. Suppose that the following
+ * commands get executed:
+ * echo foo
+ * history redo
+ * It's important that the history event recorded for the second command
+ * be "echo foo", not "history redo". Otherwise, if another "history redo"
+ * command is typed, it will result in infinite recursions on the
+ * "history redo" command. Thus, the actual recorded history must be
+ * echo foo
+ * echo foo
+ * To do this, the history command revises recorded history as part of
+ * its execution. In the example above, when "history redo" starts
+ * execution, the current event is "history redo", but the history
+ * command arranges for the current event to be changed to "echo foo".
+ *
+ * There are three additional complications. The first is that history
+ * substitution may only be part of a command, as in the following
+ * command sequence:
+ * echo foo bar
+ * echo [history word 3]
+ * In this case, the second event should be recorded as "echo bar". Only
+ * part of the recorded event is to be modified. Fortunately, Tcl_Eval
+ * helps with this by recording (in the evalFirst and evalLast fields of
+ * the intepreter) the location of the command being executed, so the
+ * history module can replace exactly the range of bytes corresponding
+ * to the history substitution command.
+ *
+ * The second complication is that there are two ways to revise history:
+ * replace a command, and replace the result of a command. Consider the
+ * two examples below:
+ * format {result is %d} $num | format {result is %d} $num
+ * print [history redo] | print [history word 3]
+ * Recorded history for these two cases should be as follows:
+ * format {result is %d} $num | format {result is %d} $num
+ * print [format {result is %d} $num] | print $num
+ * In the left case, the history command was replaced with another command
+ * to be executed (the brackets were retained), but in the case on the
+ * right the result of executing the history command was replaced (i.e.
+ * brackets were replaced too).
+ *
+ * The third complication is that there could potentially be many
+ * history substitutions within a single command, as in:
+ * echo [history word 3] [history word 2]
+ * There could even be nested history substitutions, as in:
+ * history subs abc [history word 2]
+ * If history revisions were made immediately during each "history" command
+ * invocations, it would be very difficult to produce the correct cumulative
+ * effect from several substitutions in the same command. To get around
+ * this problem, the actual history revision isn't made during the execution
+ * of the "history" command. Information about the changes is just recorded,
+ * in xxx records, and the actual changes are made during the next call to
+ * Tcl_RecordHistory (when we know that execution of the previous command
+ * has finished).
+ */
+
+/*
+ * Default space allocation for command strings:
+ */
+
+#define INITIAL_CMD_SIZE 40
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+
+static void DoRevs _ANSI_ARGS_((Interp *iPtr));
+static HistoryEvent * GetEvent _ANSI_ARGS_((Interp *iPtr, char *string));
+static char * GetWords _ANSI_ARGS_((Interp *iPtr, char *command,
+ char *words));
+static void InitHistory _ANSI_ARGS_((Interp *iPtr));
+static void InsertRev _ANSI_ARGS_((Interp *iPtr,
+ HistoryRev *revPtr));
+static void MakeSpace _ANSI_ARGS_((HistoryEvent *hPtr, int size));
+static void RevCommand _ANSI_ARGS_((Interp *iPtr, char *string));
+static void RevResult _ANSI_ARGS_((Interp *iPtr, char *string));
+static int SubsAndEval _ANSI_ARGS_((Interp *iPtr, char *cmd,
+ char *old, char *new));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitHistory --
+ *
+ * Initialize history-related state in an interpreter.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * History info is initialized in iPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+InitHistory(iPtr)
+ register Interp *iPtr; /* Interpreter to initialize. */
+{
+ int i;
+
+ if (iPtr->numEvents != 0) {
+ return;
+ }
+ iPtr->numEvents = 20;
+ iPtr->events = (HistoryEvent *)
+ ckalloc((unsigned) (iPtr->numEvents * sizeof(HistoryEvent)));
+ for (i = 0; i < iPtr->numEvents; i++) {
+ iPtr->events[i].command = (char *) ckalloc(INITIAL_CMD_SIZE);
+ *iPtr->events[i].command = 0;
+ iPtr->events[i].bytesAvl = INITIAL_CMD_SIZE;
+ }
+ iPtr->curEvent = 0;
+ iPtr->curEventNum = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RecordAndEval --
+ *
+ * This procedure adds its command argument to the current list of
+ * recorded events and then executes the command by calling Tcl_Eval.
+ *
+ * Results:
+ * The return value is a standard Tcl return value, the result of
+ * executing cmd.
+ *
+ * Side effects:
+ * The command is recorded and executed. In addition, pending history
+ * revisions are carried out, and information is set up to enable
+ * Tcl_Eval to identify history command ranges. This procedure also
+ * initializes history information for the interpreter, if it hasn't
+ * already been initialized.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_RecordAndEval(interp, cmd, flags)
+ Tcl_Interp *interp; /* Token for interpreter in which command
+ * will be executed. */
+ char *cmd; /* Command to record. */
+ int flags; /* Additional flags to pass to Tcl_Eval.
+ * TCL_NO_EVAL means only record: don't
+ * execute command. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ register HistoryEvent *eventPtr;
+ int length, result;
+
+ if (iPtr->numEvents == 0) {
+ InitHistory(iPtr);
+ }
+ DoRevs(iPtr);
+
+ /*
+ * Don't record empty commands.
+ */
+
+ while (isspace(UCHAR(*cmd))) {
+ cmd++;
+ }
+ if (*cmd == '\0') {
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+ }
+
+ iPtr->curEventNum++;
+ iPtr->curEvent++;
+ if (iPtr->curEvent >= iPtr->numEvents) {
+ iPtr->curEvent = 0;
+ }
+ eventPtr = &iPtr->events[iPtr->curEvent];
+
+ /*
+ * Chop off trailing newlines before recording the command.
+ */
+
+ length = strlen(cmd);
+ while (cmd[length-1] == '\n') {
+ length--;
+ }
+ MakeSpace(eventPtr, length + 1);
+ strncpy(eventPtr->command, cmd, length);
+ eventPtr->command[length] = 0;
+
+ /*
+ * Execute the command. Note: history revision isn't possible after
+ * a nested call to this procedure, because the event at the top of
+ * the history list no longer corresponds to what's going on when
+ * a nested call here returns. Thus, must leave history revision
+ * disabled when we return.
+ */
+
+ result = TCL_OK;
+ if (flags != TCL_NO_EVAL) {
+ iPtr->historyFirst = cmd;
+ iPtr->revDisables = 0;
+ iPtr->evalFlags = flags | TCL_RECORD_BOUNDS;
+ result = Tcl_Eval(interp, cmd);
+ }
+ iPtr->revDisables = 1;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_HistoryCmd --
+ *
+ * This procedure is invoked to process the "history" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_HistoryCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ register HistoryEvent *eventPtr;
+ int length;
+ char c;
+
+ if (iPtr->numEvents == 0) {
+ InitHistory(iPtr);
+ }
+
+ /*
+ * If no arguments, treat the same as "history info".
+ */
+
+ if (argc == 1) {
+ goto infoCmd;
+ }
+
+ c = argv[1][0];
+ length = strlen(argv[1]);
+
+ if ((c == 'a') && (strncmp(argv[1], "add", length)) == 0) {
+ if ((argc != 3) && (argc != 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " add event ?exec?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 4) {
+ if (strncmp(argv[3], "exec", strlen(argv[3])) != 0) {
+ Tcl_AppendResult(interp, "bad argument \"", argv[3],
+ "\": should be \"exec\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return Tcl_RecordAndEval(interp, argv[2], 0);
+ }
+ return Tcl_RecordAndEval(interp, argv[2], TCL_NO_EVAL);
+ } else if ((c == 'c') && (strncmp(argv[1], "change", length)) == 0) {
+ if ((argc != 3) && (argc != 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " change newValue ?event?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 3) {
+ eventPtr = &iPtr->events[iPtr->curEvent];
+ iPtr->revDisables += 1;
+ while (iPtr->revPtr != NULL) {
+ HistoryRev *nextPtr;
+
+ ckfree(iPtr->revPtr->newBytes);
+ nextPtr = iPtr->revPtr->nextPtr;
+ ckfree((char *) iPtr->revPtr);
+ iPtr->revPtr = nextPtr;
+ }
+ } else {
+ eventPtr = GetEvent(iPtr, argv[3]);
+ if (eventPtr == NULL) {
+ return TCL_ERROR;
+ }
+ }
+ MakeSpace(eventPtr, strlen(argv[2]) + 1);
+ strcpy(eventPtr->command, argv[2]);
+ return TCL_OK;
+ } else if ((c == 'e') && (strncmp(argv[1], "event", length)) == 0) {
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " event ?event?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ eventPtr = GetEvent(iPtr, argc==2 ? "-1" : argv[2]);
+ if (eventPtr == NULL) {
+ return TCL_ERROR;
+ }
+ RevResult(iPtr, eventPtr->command);
+ Tcl_SetResult(interp, eventPtr->command, TCL_VOLATILE);
+ return TCL_OK;
+ } else if ((c == 'i') && (strncmp(argv[1], "info", length)) == 0) {
+ int count, indx, i;
+ char *newline;
+
+ if ((argc != 2) && (argc != 3)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " info ?count?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ infoCmd:
+ if (argc == 3) {
+ if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (count > iPtr->numEvents) {
+ count = iPtr->numEvents;
+ }
+ } else {
+ count = iPtr->numEvents;
+ }
+ newline = "";
+ for (i = 0, indx = iPtr->curEvent + 1 + iPtr->numEvents - count;
+ i < count; i++, indx++) {
+ char *cur, *next, savedChar;
+ char serial[20];
+
+ if (indx >= iPtr->numEvents) {
+ indx -= iPtr->numEvents;
+ }
+ cur = iPtr->events[indx].command;
+ if (*cur == '\0') {
+ continue; /* No command recorded here. */
+ }
+ sprintf(serial, "%6d ", iPtr->curEventNum + 1 - (count - i));
+ Tcl_AppendResult(interp, newline, serial, (char *) NULL);
+ newline = "\n";
+
+ /*
+ * Tricky formatting here: for multi-line commands, indent
+ * the continuation lines.
+ */
+
+ while (1) {
+ next = strchr(cur, '\n');
+ if (next == NULL) {
+ break;
+ }
+ next++;
+ savedChar = *next;
+ *next = 0;
+ Tcl_AppendResult(interp, cur, "\t", (char *) NULL);
+ *next = savedChar;
+ cur = next;
+ }
+ Tcl_AppendResult(interp, cur, (char *) NULL);
+ }
+ return TCL_OK;
+ } else if ((c == 'k') && (strncmp(argv[1], "keep", length)) == 0) {
+ int count, i, src;
+ HistoryEvent *events;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " keep number\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if ((count <= 0) || (count > 1000)) {
+ Tcl_AppendResult(interp, "illegal keep count \"", argv[2],
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Create a new history array and copy as much existing history
+ * as possible from the old array.
+ */
+
+ events = (HistoryEvent *)
+ ckalloc((unsigned) (count * sizeof(HistoryEvent)));
+ if (count < iPtr->numEvents) {
+ src = iPtr->curEvent + 1 - count;
+ if (src < 0) {
+ src += iPtr->numEvents;
+ }
+ } else {
+ src = iPtr->curEvent + 1;
+ }
+ for (i = 0; i < count; i++, src++) {
+ if (src >= iPtr->numEvents) {
+ src = 0;
+ }
+ if (i < iPtr->numEvents) {
+ events[i] = iPtr->events[src];
+ iPtr->events[src].command = NULL;
+ } else {
+ events[i].command = (char *) ckalloc(INITIAL_CMD_SIZE);
+ events[i].command[0] = 0;
+ events[i].bytesAvl = INITIAL_CMD_SIZE;
+ }
+ }
+
+ /*
+ * Throw away everything left in the old history array, and
+ * substitute the new one for the old one.
+ */
+
+ for (i = 0; i < iPtr->numEvents; i++) {
+ if (iPtr->events[i].command != NULL) {
+ ckfree(iPtr->events[i].command);
+ }
+ }
+ ckfree((char *) iPtr->events);
+ iPtr->events = events;
+ if (count < iPtr->numEvents) {
+ iPtr->curEvent = count-1;
+ } else {
+ iPtr->curEvent = iPtr->numEvents-1;
+ }
+ iPtr->numEvents = count;
+ return TCL_OK;
+ } else if ((c == 'n') && (strncmp(argv[1], "nextid", length)) == 0) {
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " nextid\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ sprintf(iPtr->result, "%d", iPtr->curEventNum+1);
+ return TCL_OK;
+ } else if ((c == 'r') && (strncmp(argv[1], "redo", length)) == 0) {
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " redo ?event?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ eventPtr = GetEvent(iPtr, argc==2 ? "-1" : argv[2]);
+ if (eventPtr == NULL) {
+ return TCL_ERROR;
+ }
+ RevCommand(iPtr, eventPtr->command);
+ return Tcl_Eval(interp, eventPtr->command);
+ } else if ((c == 's') && (strncmp(argv[1], "substitute", length)) == 0) {
+ if ((argc > 5) || (argc < 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " substitute old new ?event?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ eventPtr = GetEvent(iPtr, argc==4 ? "-1" : argv[4]);
+ if (eventPtr == NULL) {
+ return TCL_ERROR;
+ }
+ return SubsAndEval(iPtr, eventPtr->command, argv[2], argv[3]);
+ } else if ((c == 'w') && (strncmp(argv[1], "words", length)) == 0) {
+ char *words;
+
+ if ((argc != 3) && (argc != 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " words num-num/pat ?event?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ eventPtr = GetEvent(iPtr, argc==3 ? "-1" : argv[3]);
+ if (eventPtr == NULL) {
+ return TCL_ERROR;
+ }
+ words = GetWords(iPtr, eventPtr->command, argv[2]);
+ if (words == NULL) {
+ return TCL_ERROR;
+ }
+ RevResult(iPtr, words);
+ iPtr->result = words;
+ iPtr->freeProc = (Tcl_FreeProc *) free;
+ return TCL_OK;
+ }
+
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be add, change, event, info, keep, nextid, ",
+ "redo, substitute, or words", (char *) NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MakeSpace --
+ *
+ * Given a history event, make sure it has enough space for
+ * a string of a given length (enlarge the string area if
+ * necessary).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * More memory may get allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MakeSpace(hPtr, size)
+ HistoryEvent *hPtr;
+ int size; /* # of bytes needed in hPtr. */
+{
+ if (hPtr->bytesAvl < size) {
+ ckfree(hPtr->command);
+ hPtr->command = (char *) ckalloc((unsigned) size);
+ hPtr->bytesAvl = size;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InsertRev --
+ *
+ * Add a new revision to the list of those pending for iPtr.
+ * Do it in a way that keeps the revision list sorted in
+ * increasing order of firstIndex. Also, eliminate revisions
+ * that are subsets of other revisions.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * RevPtr is added to iPtr's revision list.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+InsertRev(iPtr, revPtr)
+ Interp *iPtr; /* Interpreter to use. */
+ register HistoryRev *revPtr; /* Revision to add to iPtr's list. */
+{
+ register HistoryRev *curPtr;
+ register HistoryRev *prevPtr;
+
+ for (curPtr = iPtr->revPtr, prevPtr = NULL; curPtr != NULL;
+ prevPtr = curPtr, curPtr = curPtr->nextPtr) {
+ /*
+ * If this revision includes the new one (or vice versa) then
+ * just eliminate the one that is a subset of the other.
+ */
+
+ if ((revPtr->firstIndex <= curPtr->firstIndex)
+ && (revPtr->lastIndex >= curPtr->firstIndex)) {
+ curPtr->firstIndex = revPtr->firstIndex;
+ curPtr->lastIndex = revPtr->lastIndex;
+ curPtr->newSize = revPtr->newSize;
+ ckfree(curPtr->newBytes);
+ curPtr->newBytes = revPtr->newBytes;
+ ckfree((char *) revPtr);
+ return;
+ }
+ if ((revPtr->firstIndex >= curPtr->firstIndex)
+ && (revPtr->lastIndex <= curPtr->lastIndex)) {
+ ckfree(revPtr->newBytes);
+ ckfree((char *) revPtr);
+ return;
+ }
+
+ if (revPtr->firstIndex < curPtr->firstIndex) {
+ break;
+ }
+ }
+
+ /*
+ * Insert revPtr just after prevPtr.
+ */
+
+ if (prevPtr == NULL) {
+ revPtr->nextPtr = iPtr->revPtr;
+ iPtr->revPtr = revPtr;
+ } else {
+ revPtr->nextPtr = prevPtr->nextPtr;
+ prevPtr->nextPtr = revPtr;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * RevCommand --
+ *
+ * This procedure is invoked by the "history" command to record
+ * a command revision. See the comments at the beginning of the
+ * file for more information about revisions.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Revision information is recorded.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+RevCommand(iPtr, string)
+ register Interp *iPtr; /* Interpreter in which to perform the
+ * substitution. */
+ char *string; /* String to substitute. */
+{
+ register HistoryRev *revPtr;
+
+ if ((iPtr->evalFirst == NULL) || (iPtr->revDisables > 0)) {
+ return;
+ }
+ revPtr = (HistoryRev *) ckalloc(sizeof(HistoryRev));
+ revPtr->firstIndex = iPtr->evalFirst - iPtr->historyFirst;
+ revPtr->lastIndex = iPtr->evalLast - iPtr->historyFirst;
+ revPtr->newSize = strlen(string);
+ revPtr->newBytes = (char *) ckalloc((unsigned) (revPtr->newSize+1));
+ strcpy(revPtr->newBytes, string);
+ InsertRev(iPtr, revPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * RevResult --
+ *
+ * This procedure is invoked by the "history" command to record
+ * a result revision. See the comments at the beginning of the
+ * file for more information about revisions.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Revision information is recorded.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+RevResult(iPtr, string)
+ register Interp *iPtr; /* Interpreter in which to perform the
+ * substitution. */
+ char *string; /* String to substitute. */
+{
+ register HistoryRev *revPtr;
+ char *evalFirst, *evalLast;
+ char *argv[2];
+
+ if ((iPtr->evalFirst == NULL) || (iPtr->revDisables > 0)) {
+ return;
+ }
+
+ /*
+ * Expand the replacement range to include the brackets that surround
+ * the command. If there aren't any brackets (i.e. this command was
+ * invoked at top-level) then don't do any revision. Also, if there
+ * are several commands in brackets, of which this is just one,
+ * then don't do any revision.
+ */
+
+ evalFirst = iPtr->evalFirst;
+ evalLast = iPtr->evalLast + 1;
+ while (1) {
+ if (evalFirst == iPtr->historyFirst) {
+ return;
+ }
+ evalFirst--;
+ if (*evalFirst == '[') {
+ break;
+ }
+ if (!isspace(UCHAR(*evalFirst))) {
+ return;
+ }
+ }
+ if (*evalLast != ']') {
+ return;
+ }
+
+ revPtr = (HistoryRev *) ckalloc(sizeof(HistoryRev));
+ revPtr->firstIndex = evalFirst - iPtr->historyFirst;
+ revPtr->lastIndex = evalLast - iPtr->historyFirst;
+ argv[0] = string;
+ revPtr->newBytes = Tcl_Merge(1, argv);
+ revPtr->newSize = strlen(revPtr->newBytes);
+ InsertRev(iPtr, revPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DoRevs --
+ *
+ * This procedure is called to apply the history revisions that
+ * have been recorded in iPtr.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The most recent entry in the history for iPtr may be modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DoRevs(iPtr)
+ register Interp *iPtr; /* Interpreter whose history is to
+ * be modified. */
+{
+ register HistoryRev *revPtr;
+ register HistoryEvent *eventPtr;
+ char *newCommand, *p;
+ unsigned int size;
+ int bytesSeen, count;
+
+ if (iPtr->revPtr == NULL) {
+ return;
+ }
+
+ /*
+ * The revision is done in two passes. The first pass computes the
+ * amount of space needed for the revised event, and the second pass
+ * pieces together the new event and frees up the revisions.
+ */
+
+ eventPtr = &iPtr->events[iPtr->curEvent];
+ size = strlen(eventPtr->command) + 1;
+ for (revPtr = iPtr->revPtr; revPtr != NULL; revPtr = revPtr->nextPtr) {
+ size -= revPtr->lastIndex + 1 - revPtr->firstIndex;
+ size += revPtr->newSize;
+ }
+
+ newCommand = (char *) ckalloc(size);
+ p = newCommand;
+ bytesSeen = 0;
+ for (revPtr = iPtr->revPtr; revPtr != NULL; ) {
+ HistoryRev *nextPtr = revPtr->nextPtr;
+
+ count = revPtr->firstIndex - bytesSeen;
+ if (count > 0) {
+ strncpy(p, eventPtr->command + bytesSeen, count);
+ p += count;
+ }
+ strncpy(p, revPtr->newBytes, revPtr->newSize);
+ p += revPtr->newSize;
+ bytesSeen = revPtr->lastIndex+1;
+ ckfree(revPtr->newBytes);
+ ckfree((char *) revPtr);
+ revPtr = nextPtr;
+ }
+ if (&p[strlen(&eventPtr->command[bytesSeen]) + 1] >
+ &newCommand[size]) {
+ printf("Assertion failed!\n");
+ }
+ strcpy(p, eventPtr->command + bytesSeen);
+
+ /*
+ * Replace the command in the event.
+ */
+
+ ckfree(eventPtr->command);
+ eventPtr->command = newCommand;
+ eventPtr->bytesAvl = size;
+ iPtr->revPtr = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetEvent --
+ *
+ * Given a textual description of an event (see the manual page
+ * for legal values) find the corresponding event and return its
+ * command string.
+ *
+ * Results:
+ * The return value is a pointer to the event named by "string".
+ * If no such event exists, then NULL is returned and an error
+ * message is left in iPtr.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static HistoryEvent *
+GetEvent(iPtr, string)
+ register Interp *iPtr; /* Interpreter in which to look. */
+ char *string; /* Description of event. */
+{
+ int eventNum, index;
+ register HistoryEvent *eventPtr;
+ int length;
+
+ /*
+ * First check for a numeric specification of an event.
+ */
+
+ if (isdigit(UCHAR(*string)) || (*string == '-')) {
+ if (Tcl_GetInt((Tcl_Interp *) iPtr, string, &eventNum) != TCL_OK) {
+ return NULL;
+ }
+ if (eventNum < 0) {
+ eventNum += iPtr->curEventNum;
+ }
+ if (eventNum > iPtr->curEventNum) {
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "event \"", string,
+ "\" hasn't occurred yet", (char *) NULL);
+ return NULL;
+ }
+ if ((eventNum <= iPtr->curEventNum-iPtr->numEvents)
+ || (eventNum <= 0)) {
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "event \"", string,
+ "\" is too far in the past", (char *) NULL);
+ return NULL;
+ }
+ index = iPtr->curEvent + (eventNum - iPtr->curEventNum);
+ if (index < 0) {
+ index += iPtr->numEvents;
+ }
+ return &iPtr->events[index];
+ }
+
+ /*
+ * Next, check for an event that contains the string as a prefix or
+ * that matches the string in the sense of Tcl_StringMatch.
+ */
+
+ length = strlen(string);
+ for (index = iPtr->curEvent - 1; ; index--) {
+ if (index < 0) {
+ index += iPtr->numEvents;
+ }
+ if (index == iPtr->curEvent) {
+ break;
+ }
+ eventPtr = &iPtr->events[index];
+ if ((strncmp(eventPtr->command, string, length) == 0)
+ || Tcl_StringMatch(eventPtr->command, string)) {
+ return eventPtr;
+ }
+ }
+
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "no event matches \"", string,
+ "\"", (char *) NULL);
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SubsAndEval --
+ *
+ * Generate a new command by making a textual substitution in
+ * the "cmd" argument. Then execute the new command.
+ *
+ * Results:
+ * The return value is a standard Tcl error.
+ *
+ * Side effects:
+ * History gets revised if the substitution is occurring on
+ * a recorded command line. Also, the re-executed command
+ * may produce side-effects.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+SubsAndEval(iPtr, cmd, old, new)
+ register Interp *iPtr; /* Interpreter in which to execute
+ * new command. */
+ char *cmd; /* Command in which to substitute. */
+ char *old; /* String to search for in command. */
+ char *new; /* Replacement string for "old". */
+{
+ char *src, *dst, *newCmd;
+ int count, oldLength, newLength, length, result;
+
+ /*
+ * Figure out how much space it will take to hold the
+ * substituted command (and complain if the old string
+ * doesn't appear in the original command).
+ */
+
+ oldLength = strlen(old);
+ newLength = strlen(new);
+ src = cmd;
+ count = 0;
+ while (1) {
+ src = strstr(src, old);
+ if (src == NULL) {
+ break;
+ }
+ src += oldLength;
+ count++;
+ }
+ if (count == 0) {
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "\"", old,
+ "\" doesn't appear in event", (char *) NULL);
+ return TCL_ERROR;
+ }
+ length = strlen(cmd) + count*(newLength - oldLength);
+
+ /*
+ * Generate a substituted command.
+ */
+
+ newCmd = (char *) ckalloc((unsigned) (length + 1));
+ dst = newCmd;
+ while (1) {
+ src = strstr(cmd, old);
+ if (src == NULL) {
+ strcpy(dst, cmd);
+ break;
+ }
+ strncpy(dst, cmd, src-cmd);
+ dst += src-cmd;
+ strcpy(dst, new);
+ dst += newLength;
+ cmd = src + oldLength;
+ }
+
+ RevCommand(iPtr, newCmd);
+ result = Tcl_Eval((Tcl_Interp *) iPtr, newCmd);
+ ckfree(newCmd);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetWords --
+ *
+ * Given a command string, return one or more words from the
+ * command string.
+ *
+ * Results:
+ * The return value is a pointer to a dynamically-allocated
+ * string containing the words of command specified by "words".
+ * If the word specifier has improper syntax then an error
+ * message is placed in iPtr->result and NULL is returned.
+ *
+ * Side effects:
+ * Memory is allocated. It is the caller's responsibilty to
+ * free the returned string..
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+GetWords(iPtr, command, words)
+ register Interp *iPtr; /* Tcl interpreter in which to place
+ * an error message if needed. */
+ char *command; /* Command string. */
+ char *words; /* Description of which words to extract
+ * from the command. Either num[-num] or
+ * a pattern. */
+{
+ char *result;
+ char *start, *end, *dst;
+ register char *next;
+ int first; /* First word desired. -1 means last word
+ * only. */
+ int last; /* Last word desired. -1 means use everything
+ * up to the end. */
+ int index; /* Index of current word. */
+ char *pattern;
+
+ /*
+ * Figure out whether we're looking for a numerical range or for
+ * a pattern.
+ */
+
+ pattern = NULL;
+ first = 0;
+ last = -1;
+ if (*words == '$') {
+ if (words[1] != '\0') {
+ goto error;
+ }
+ first = -1;
+ } else if (isdigit(UCHAR(*words))) {
+ first = strtoul(words, &start, 0);
+ if (*start == 0) {
+ last = first;
+ } else if (*start == '-') {
+ start++;
+ if (*start == '$') {
+ start++;
+ } else if (isdigit(UCHAR(*start))) {
+ last = strtoul(start, &start, 0);
+ } else {
+ goto error;
+ }
+ if (*start != 0) {
+ goto error;
+ }
+ }
+ if ((first > last) && (last != -1)) {
+ goto error;
+ }
+ } else {
+ pattern = words;
+ }
+
+ /*
+ * Scan through the words one at a time, copying those that are
+ * relevant into the result string. Allocate a result area large
+ * enough to hold all the words if necessary.
+ */
+
+ result = (char *) ckalloc((unsigned) (strlen(command) + 1));
+ dst = result;
+ for (next = command; isspace(UCHAR(*next)); next++) {
+ /* Empty loop body: just find start of first word. */
+ }
+ for (index = 0; *next != 0; index++) {
+ start = next;
+ end = TclWordEnd(next, 0, (int *) NULL);
+ if (*end != 0) {
+ end++;
+ for (next = end; isspace(UCHAR(*next)); next++) {
+ /* Empty loop body: just find start of next word. */
+ }
+ }
+ if ((first > index) || ((first == -1) && (*next != 0))) {
+ continue;
+ }
+ if ((last != -1) && (last < index)) {
+ continue;
+ }
+ if (pattern != NULL) {
+ int match;
+ char savedChar = *end;
+
+ *end = 0;
+ match = Tcl_StringMatch(start, pattern);
+ *end = savedChar;
+ if (!match) {
+ continue;
+ }
+ }
+ if (dst != result) {
+ *dst = ' ';
+ dst++;
+ }
+ strncpy(dst, start, (end-start));
+ dst += end-start;
+ }
+ *dst = 0;
+
+ /*
+ * Check for an out-of-range argument index.
+ */
+
+ if ((last >= index) || (first >= index)) {
+ ckfree(result);
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "word selector \"", words,
+ "\" specified non-existent words", (char *) NULL);
+ return NULL;
+ }
+ return result;
+
+ error:
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "bad word selector \"", words,
+ "\": should be num-num or pattern", (char *) NULL);
+ return NULL;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclInt.h b/vendor/x11iraf/obm/Tcl/tclInt.h
new file mode 100644
index 00000000..1f59a065
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclInt.h
@@ -0,0 +1,947 @@
+/*
+ * tclInt.h --
+ *
+ * Declarations of things used internally by the Tcl interpreter.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/RCS/tclInt.h,v 1.94 93/10/15 16:36:51 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _TCLINT
+#define _TCLINT
+
+/*
+ * Common include files needed by most of the Tcl source files are
+ * included here, so that system-dependent personalizations for the
+ * include files only have to be made in once place. This results
+ * in a few extra includes, but greater modularity. The order of
+ * the three groups of #includes is important. For example, stdio.h
+ * is needed by tcl.h, and the _ANSI_ARGS_ declaration in tcl.h is
+ * needed by stdlib.h in some configurations.
+ */
+
+#include <stdio.h>
+
+#ifndef _TCL
+#include "tcl.h"
+#endif
+#ifndef _REGEXP
+#include "tclRegexp.h"
+#endif
+
+#include <ctype.h>
+#ifdef NO_LIMITS_H
+# include "compat/limits.h"
+#else
+# include <limits.h>
+#endif
+#ifdef NO_STDLIB_H
+# include "compat/stdlib.h"
+#else
+# include <stdlib.h>
+#endif
+#ifdef NO_STRING_H
+#include "compat/string.h"
+#else
+#include <string.h>
+#endif
+
+/*
+*/
+#if defined(__DARWIN__) || defined(USE_STDARG)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/* Workaround for our old varargs handling on LinuxPPC systems.
+#if defined(linux) && defined(__powerpc__)
+#undef va_start
+#undef va_alist
+#undef va_dcl
+
+#define va_start(AP) __va_start_common (AP, 1)
+#define va_alist __va_1st_arg
+#define va_dcl register int va_alist; ...
+#endif
+*/
+
+
+/*
+ * At present (12/91) not all stdlib.h implementations declare strtod.
+ * The declaration below is here to ensure that it's declared, so that
+ * the compiler won't take the default approach of assuming it returns
+ * an int. There's no ANSI prototype for it because there would end
+ * up being too many conflicts with slightly-different prototypes.
+ */
+
+extern double strtod();
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to variables. These are used primarily
+ * in tclVar.c
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The following structure defines a variable trace, which is used to
+ * invoke a specific C procedure whenever certain operations are performed
+ * on a variable.
+ */
+
+typedef struct VarTrace {
+ Tcl_VarTraceProc *traceProc;/* Procedure to call when operations given
+ * by flags are performed on variable. */
+ ClientData clientData; /* Argument to pass to proc. */
+ int flags; /* What events the trace procedure is
+ * interested in: OR-ed combination of
+ * TCL_TRACE_READS, TCL_TRACE_WRITES, and
+ * TCL_TRACE_UNSETS. */
+ struct VarTrace *nextPtr; /* Next in list of traces associated with
+ * a particular variable. */
+} VarTrace;
+
+/*
+ * When a variable trace is active (i.e. its associated procedure is
+ * executing), one of the following structures is linked into a list
+ * associated with the variable's interpreter. The information in
+ * the structure is needed in order for Tcl to behave reasonably
+ * if traces are deleted while traces are active.
+ */
+
+typedef struct ActiveVarTrace {
+ struct Var *varPtr; /* Variable that's being traced. */
+ struct ActiveVarTrace *nextPtr;
+ /* Next in list of all active variable
+ * traces for the interpreter, or NULL
+ * if no more. */
+ VarTrace *nextTracePtr; /* Next trace to check after current
+ * trace procedure returns; if this
+ * trace gets deleted, must update pointer
+ * to avoid using free'd memory. */
+} ActiveVarTrace;
+
+/*
+ * The following structure describes an enumerative search in progress on
+ * an array variable; this are invoked with options to the "array"
+ * command.
+ */
+
+typedef struct ArraySearch {
+ int id; /* Integer id used to distinguish among
+ * multiple concurrent searches for the
+ * same array. */
+ struct Var *varPtr; /* Pointer to array variable that's being
+ * searched. */
+ Tcl_HashSearch search; /* Info kept by the hash module about
+ * progress through the array. */
+ Tcl_HashEntry *nextEntry; /* Non-null means this is the next element
+ * to be enumerated (it's leftover from
+ * the Tcl_FirstHashEntry call or from
+ * an "array anymore" command). NULL
+ * means must call Tcl_NextHashEntry
+ * to get value to return. */
+ struct ArraySearch *nextPtr;/* Next in list of all active searches
+ * for this variable, or NULL if this is
+ * the last one. */
+} ArraySearch;
+
+/*
+ * The structure below defines a variable, which associates a string name
+ * with a string value. Pointers to these structures are kept as the
+ * values of hash table entries, and the name of each variable is stored
+ * in the hash entry.
+ */
+
+typedef struct Var {
+ int valueLength; /* Holds the number of non-null bytes
+ * actually occupied by the variable's
+ * current value in value.string (extra
+ * space is sometimes left for expansion).
+ * For array and global variables this is
+ * meaningless. */
+ int valueSpace; /* Total number of bytes of space allocated
+ * at value.string. 0 means there is no
+ * space allocated. */
+ union {
+ char *string; /* String value of variable, used for scalar
+ * variables and array elements. Malloc-ed. */
+ Tcl_HashTable *tablePtr;/* For array variables, this points to
+ * information about the hash table used
+ * to implement the associative array.
+ * Points to malloc-ed data. */
+ struct Var *upvarPtr; /* If this is a global variable being
+ * referred to in a procedure, or a variable
+ * created by "upvar", this field points to
+ * the record for the higher-level variable. */
+ } value;
+ Tcl_HashEntry *hPtr; /* Hash table entry that refers to this
+ * variable, or NULL if the variable has
+ * been detached from its hash table (e.g.
+ * an array is deleted, but some of its
+ * elements are still referred to in upvars). */
+ int refCount; /* Counts number of active uses of this
+ * variable, not including its main hash
+ * table entry: 1 for each additional variable
+ * whose upVarPtr points here, 1 for each
+ * nested trace active on variable. This
+ * record can't be deleted until refCount
+ * becomes 0. */
+ VarTrace *tracePtr; /* First in list of all traces set for this
+ * variable. */
+ ArraySearch *searchPtr; /* First in list of all searches active
+ * for this variable, or NULL if none. */
+ int flags; /* Miscellaneous bits of information about
+ * variable. See below for definitions. */
+} Var;
+
+/*
+ * Flag bits for variables:
+ *
+ * VAR_ARRAY - 1 means this is an array variable rather
+ * than a scalar variable.
+ * VAR_UPVAR - 1 means this variable just contains a
+ * pointer to another variable that has the
+ * real value. Variables like this come
+ * about through the "upvar" and "global"
+ * commands.
+ * VAR_UNDEFINED - 1 means that the variable is currently
+ * undefined. Undefined variables usually
+ * go away completely, but if an undefined
+ * variable has a trace on it, or if it is
+ * a global variable being used by a procedure,
+ * then it stays around even when undefined.
+ * VAR_TRACE_ACTIVE - 1 means that trace processing is currently
+ * underway for a read or write access, so
+ * new read or write accesses should not cause
+ * trace procedures to be called and the
+ * variable can't be deleted.
+ */
+
+#define VAR_ARRAY 1
+#define VAR_UPVAR 2
+#define VAR_UNDEFINED 4
+#define VAR_TRACE_ACTIVE 0x10
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to procedures. These are used primarily
+ * in tclProc.c
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The structure below defines an argument to a procedure, which
+ * consists of a name and an (optional) default value.
+ */
+
+typedef struct Arg {
+ struct Arg *nextPtr; /* Next argument for this procedure,
+ * or NULL if this is the last argument. */
+ char *defValue; /* Pointer to arg's default value, or NULL
+ * if no default value. */
+ char name[4]; /* Name of argument starts here. The name
+ * is followed by space for the default,
+ * if there is one. The actual size of this
+ * field will be as large as necessary to
+ * hold both name and default value. THIS
+ * MUST BE THE LAST FIELD IN THE STRUCTURE!! */
+} Arg;
+
+/*
+ * The structure below defines a command procedure, which consists of
+ * a collection of Tcl commands plus information about arguments and
+ * variables.
+ */
+
+typedef struct Proc {
+ struct Interp *iPtr; /* Interpreter for which this command
+ * is defined. */
+ int refCount; /* Reference count: 1 if still present
+ * in command table plus 1 for each call
+ * to the procedure that is currently
+ * active. This structure can be freed
+ * when refCount becomes zero. */
+ char *command; /* Command that constitutes the body of
+ * the procedure (dynamically allocated). */
+ Arg *argPtr; /* Pointer to first of procedure's formal
+ * arguments, or NULL if none. */
+} Proc;
+
+/*
+ * The structure below defines a command trace. This is used to allow Tcl
+ * clients to find out whenever a command is about to be executed.
+ */
+
+typedef struct Trace {
+ int level; /* Only trace commands at nesting level
+ * less than or equal to this. */
+ Tcl_CmdTraceProc *proc; /* Procedure to call to trace command. */
+ ClientData clientData; /* Arbitrary value to pass to proc. */
+ struct Trace *nextPtr; /* Next in list of traces for this interp. */
+} Trace;
+
+/*
+ * The stucture below defines a deletion callback, which is
+ * a procedure to invoke just before an interpreter is deleted.
+ */
+
+typedef struct DeleteCallback {
+ Tcl_InterpDeleteProc *proc; /* Procedure to call. */
+ ClientData clientData; /* Value to pass to procedure. */
+ struct DeleteCallback *nextPtr;
+ /* Next in list of callbacks for this
+ * interpreter (or NULL for end of list). */
+} DeleteCallback;
+
+/*
+ * The structure below defines a frame, which is a procedure invocation.
+ * These structures exist only while procedures are being executed, and
+ * provide a sort of call stack.
+ */
+
+typedef struct CallFrame {
+ Tcl_HashTable varTable; /* Hash table containing all of procedure's
+ * local variables. */
+ int level; /* Level of this procedure, for "uplevel"
+ * purposes (i.e. corresponds to nesting of
+ * callerVarPtr's, not callerPtr's). 1 means
+ * outer-most procedure, 0 means top-level. */
+ int argc; /* This and argv below describe name and
+ * arguments for this procedure invocation. */
+ char **argv; /* Array of arguments. */
+ struct CallFrame *callerPtr;
+ /* Value of interp->framePtr when this
+ * procedure was invoked (i.e. next in
+ * stack of all active procedures). */
+ struct CallFrame *callerVarPtr;
+ /* Value of interp->varFramePtr when this
+ * procedure was invoked (i.e. determines
+ * variable scoping within caller; same
+ * as callerPtr unless an "uplevel" command
+ * or something equivalent was active in
+ * the caller). */
+} CallFrame;
+
+/*
+ * The structure below defines one history event (a previously-executed
+ * command that can be re-executed in whole or in part).
+ */
+
+typedef struct {
+ char *command; /* String containing previously-executed
+ * command. */
+ int bytesAvl; /* Total # of bytes available at *event (not
+ * all are necessarily in use now). */
+} HistoryEvent;
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to history. These are used primarily
+ * in tclHistory.c
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The structure below defines a pending revision to the most recent
+ * history event. Changes are linked together into a list and applied
+ * during the next call to Tcl_RecordHistory. See the comments at the
+ * beginning of tclHistory.c for information on revisions.
+ */
+
+typedef struct HistoryRev {
+ int firstIndex; /* Index of the first byte to replace in
+ * current history event. */
+ int lastIndex; /* Index of last byte to replace in
+ * current history event. */
+ int newSize; /* Number of bytes in newBytes. */
+ char *newBytes; /* Replacement for the range given by
+ * firstIndex and lastIndex. */
+ struct HistoryRev *nextPtr; /* Next in chain of revisions to apply, or
+ * NULL for end of list. */
+} HistoryRev;
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to files. These are used primarily in
+ * tclUnixUtil.c and tclUnixAZ.c.
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The data structure below defines an open file (or connection to
+ * a process pipeline) as returned by the "open" command.
+ */
+
+typedef struct OpenFile {
+ FILE *f; /* Stdio file to use for reading and/or
+ * writing. */
+ FILE *f2; /* Normally NULL. In the special case of
+ * a command pipeline with pipes for both
+ * input and output, this is a stdio file
+ * to use for writing to the pipeline. */
+ int permissions; /* OR-ed combination of TCL_FILE_READABLE
+ * and TCL_FILE_WRITABLE. */
+ int numPids; /* If this is a connection to a process
+ * pipeline, gives number of processes
+ * in pidPtr array below; otherwise it
+ * is 0. */
+ int *pidPtr; /* Pointer to malloc-ed array of child
+ * process ids (numPids of them), or NULL
+ * if this isn't a connection to a process
+ * pipeline. */
+ int errorId; /* File id of file that receives error
+ * output from pipeline. -1 means not
+ * used (i.e. this is a normal file). */
+} OpenFile;
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to expressions. These are used only in
+ * tclExpr.c.
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The data structure below defines a math function (e.g. sin or hypot)
+ * for use in Tcl expressions.
+ */
+
+#define MAX_MATH_ARGS 5
+typedef struct MathFunc {
+ int numArgs; /* Number of arguments for function. */
+ Tcl_ValueType argTypes[MAX_MATH_ARGS];
+ /* Acceptable types for each argument. */
+ Tcl_MathProc *proc; /* Procedure that implements this function. */
+ ClientData clientData; /* Additional argument to pass to the function
+ * when invoking it. */
+} MathFunc;
+
+/*
+ *----------------------------------------------------------------
+ * This structure defines an interpreter, which is a collection of
+ * commands plus other state information related to interpreting
+ * commands, such as variable storage. Primary responsibility for
+ * this data structure is in tclBasic.c, but almost every Tcl
+ * source file uses something in here.
+ *----------------------------------------------------------------
+ */
+
+typedef struct Command {
+ Tcl_CmdProc *proc; /* Procedure to process command. */
+ ClientData clientData; /* Arbitrary value to pass to proc. */
+ Tcl_CmdDeleteProc *deleteProc;
+ /* Procedure to invoke when deleting
+ * command. */
+ ClientData deleteData; /* Arbitrary value to pass to deleteProc
+ * (usually the same as clientData). */
+} Command;
+
+#define CMD_SIZE(nameLength) ((unsigned) sizeof(Command) + nameLength - 3)
+
+typedef struct Interp {
+
+ /*
+ * Note: the first three fields must match exactly the fields in
+ * a Tcl_Interp struct (see tcl.h). If you change one, be sure to
+ * change the other.
+ */
+
+ char *result; /* Points to result returned by last
+ * command. */
+ Tcl_FreeProc *freeProc; /* Zero means result is statically allocated.
+ * If non-zero, gives address of procedure
+ * to invoke to free the result. Must be
+ * freed by Tcl_Eval before executing next
+ * command. */
+ int errorLine; /* When TCL_ERROR is returned, this gives
+ * the line number within the command where
+ * the error occurred (1 means first line). */
+ Tcl_HashTable commandTable; /* Contains all of the commands currently
+ * registered in this interpreter. Indexed
+ * by strings; values have type (Command *). */
+ Tcl_HashTable mathFuncTable;/* Contains all of the math functions currently
+ * defined for the interpreter. Indexed by
+ * strings (function names); values have
+ * type (MathFunc *). */
+
+ /*
+ * Information related to procedures and variables. See tclProc.c
+ * and tclvar.c for usage.
+ */
+
+ Tcl_HashTable globalTable; /* Contains all global variables for
+ * interpreter. */
+ int numLevels; /* Keeps track of how many nested calls to
+ * Tcl_Eval are in progress for this
+ * interpreter. It's used to delay deletion
+ * of the table until all Tcl_Eval invocations
+ * are completed. */
+ int maxNestingDepth; /* If numLevels exceeds this value then Tcl
+ * assumes that infinite recursion has
+ * occurred and it generates an error. */
+ CallFrame *framePtr; /* Points to top-most in stack of all nested
+ * procedure invocations. NULL means there
+ * are no active procedures. */
+ CallFrame *varFramePtr; /* Points to the call frame whose variables
+ * are currently in use (same as framePtr
+ * unless an "uplevel" command is being
+ * executed). NULL means no procedure is
+ * active or "uplevel 0" is being exec'ed. */
+ ActiveVarTrace *activeTracePtr;
+ /* First in list of active traces for interp,
+ * or NULL if no active traces. */
+ int returnCode; /* Completion code to return if current
+ * procedure exits with a TCL_RETURN code. */
+ char *errorInfo; /* Value to store in errorInfo if returnCode
+ * is TCL_ERROR. Malloc'ed, may be NULL */
+ char *errorCode; /* Value to store in errorCode if returnCode
+ * is TCL_ERROR. Malloc'ed, may be NULL */
+
+ /*
+ * Information related to history:
+ */
+
+ int numEvents; /* Number of previously-executed commands
+ * to retain. */
+ HistoryEvent *events; /* Array containing numEvents entries
+ * (dynamically allocated). */
+ int curEvent; /* Index into events of place where current
+ * (or most recent) command is recorded. */
+ int curEventNum; /* Event number associated with the slot
+ * given by curEvent. */
+ HistoryRev *revPtr; /* First in list of pending revisions. */
+ char *historyFirst; /* First char. of current command executed
+ * from history module or NULL if none. */
+ int revDisables; /* 0 means history revision OK; > 0 gives
+ * a count of number of times revision has
+ * been disabled. */
+ char *evalFirst; /* If TCL_RECORD_BOUNDS flag set, Tcl_Eval
+ * sets this field to point to the first
+ * char. of text from which the current
+ * command came. Otherwise Tcl_Eval sets
+ * this to NULL. */
+ char *evalLast; /* Similar to evalFirst, except points to
+ * last character of current command. */
+
+ /*
+ * Information used by Tcl_AppendResult to keep track of partial
+ * results. See Tcl_AppendResult code for details.
+ */
+
+ char *appendResult; /* Storage space for results generated
+ * by Tcl_AppendResult. Malloc-ed. NULL
+ * means not yet allocated. */
+ int appendAvl; /* Total amount of space available at
+ * partialResult. */
+ int appendUsed; /* Number of non-null bytes currently
+ * stored at partialResult. */
+
+ /*
+ * A cache of compiled regular expressions. See TclCompileRegexp
+ * in tclUtil.c for details.
+ */
+
+#define NUM_REGEXPS 5
+ char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled
+ * regular expression patterns. NULL
+ * means that this slot isn't used.
+ * Malloc-ed. */
+ int patLengths[NUM_REGEXPS];/* Number of non-null characters in
+ * corresponding entry in patterns.
+ * -1 means entry isn't used. */
+ regexp *regexps[NUM_REGEXPS];
+ /* Compiled forms of above strings. Also
+ * malloc-ed, or NULL if not in use yet. */
+
+ /*
+ * Information used by Tcl_PrintDouble:
+ */
+
+ char pdFormat[10]; /* Format string used by Tcl_PrintDouble. */
+ int pdPrec; /* Current precision (used to restore the
+ * the tcl_precision variable after a bogus
+ * value has been put into it). */
+
+ /*
+ * Miscellaneous information:
+ */
+
+ int cmdCount; /* Total number of times a command procedure
+ * has been called for this interpreter. */
+ int noEval; /* Non-zero means no commands should actually
+ * be executed: just parse only. Used in
+ * expressions when the result is already
+ * determined. */
+ int evalFlags; /* Flags to control next call to Tcl_Eval.
+ * Normally zero, but may be set before
+ * calling Tcl_Eval to an OR'ed combination
+ * of TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
+ char *termPtr; /* Character just after the last one in
+ * a command. Set by Tcl_Eval before
+ * returning. */
+ char *scriptFile; /* NULL means there is no nested source
+ * command active; otherwise this points to
+ * the name of the file being sourced (it's
+ * not malloc-ed: it points to an argument
+ * to Tcl_EvalFile. */
+ int flags; /* Various flag bits. See below. */
+ Trace *tracePtr; /* List of traces for this interpreter. */
+ DeleteCallback *deleteCallbackPtr;
+ /* First in list of callbacks to invoke when
+ * interpreter is deleted. */
+ char resultSpace[TCL_RESULT_SIZE+1];
+ /* Static space for storing small results. */
+} Interp;
+
+/*
+ * Flag bits for Interp structures:
+ *
+ * DELETED: Non-zero means the interpreter has been deleted:
+ * don't process any more commands for it, and destroy
+ * the structure as soon as all nested invocations of
+ * Tcl_Eval are done.
+ * ERR_IN_PROGRESS: Non-zero means an error unwind is already in progress.
+ * Zero means a command proc has been invoked since last
+ * error occured.
+ * ERR_ALREADY_LOGGED: Non-zero means information has already been logged
+ * in $errorInfo for the current Tcl_Eval instance,
+ * so Tcl_Eval needn't log it (used to implement the
+ * "error message log" command).
+ * ERROR_CODE_SET: Non-zero means that Tcl_SetErrorCode has been
+ * called to record information for the current
+ * error. Zero means Tcl_Eval must clear the
+ * errorCode variable if an error is returned.
+ * EXPR_INITIALIZED: 1 means initialization specific to expressions has
+ * been carried out.
+ */
+
+#define DELETED 1
+#define ERR_IN_PROGRESS 2
+#define ERR_ALREADY_LOGGED 4
+#define ERROR_CODE_SET 8
+#define EXPR_INITIALIZED 0x10
+
+/*
+ * Default value for the pdPrec and pdFormat fields of interpreters:
+ */
+
+#define DEFAULT_PD_PREC 6
+#define DEFAULT_PD_FORMAT "%g"
+
+/*
+ *----------------------------------------------------------------
+ * Data structures related to command parsing. These are used in
+ * tclParse.c and its clients.
+ *----------------------------------------------------------------
+ */
+
+/*
+ * The following data structure is used by various parsing procedures
+ * to hold information about where to store the results of parsing
+ * (e.g. the substituted contents of a quoted argument, or the result
+ * of a nested command). At any given time, the space available
+ * for output is fixed, but a procedure may be called to expand the
+ * space available if the current space runs out.
+ */
+
+typedef struct ParseValue {
+ char *buffer; /* Address of first character in
+ * output buffer. */
+ char *next; /* Place to store next character in
+ * output buffer. */
+ char *end; /* Address of the last usable character
+ * in the buffer. */
+ void (*expandProc) _ANSI_ARGS_((struct ParseValue *pvPtr, int needed));
+ /* Procedure to call when space runs out;
+ * it will make more space. */
+ ClientData clientData; /* Arbitrary information for use of
+ * expandProc. */
+} ParseValue;
+
+/*
+ * A table used to classify input characters to assist in parsing
+ * Tcl commands. The table should be indexed with a signed character
+ * using the CHAR_TYPE macro. The character may have a negative
+ * value.
+ */
+
+extern char tclTypeTable[];
+#define CHAR_TYPE(c) (tclTypeTable+128)[c]
+
+/*
+ * Possible values returned by CHAR_TYPE:
+ *
+ * TCL_NORMAL - All characters that don't have special significance
+ * to the Tcl language.
+ * TCL_SPACE - Character is space, tab, or return.
+ * TCL_COMMAND_END - Character is newline or null or semicolon or
+ * close-bracket.
+ * TCL_QUOTE - Character is a double-quote.
+ * TCL_OPEN_BRACKET - Character is a "[".
+ * TCL_OPEN_BRACE - Character is a "{".
+ * TCL_CLOSE_BRACE - Character is a "}".
+ * TCL_BACKSLASH - Character is a "\".
+ * TCL_DOLLAR - Character is a "$".
+ */
+
+#define TCL_NORMAL 0
+#define TCL_SPACE 1
+#define TCL_COMMAND_END 2
+#define TCL_QUOTE 3
+#define TCL_OPEN_BRACKET 4
+#define TCL_OPEN_BRACE 5
+#define TCL_CLOSE_BRACE 6
+#define TCL_BACKSLASH 7
+#define TCL_DOLLAR 8
+
+/*
+ * Additional flags passed to Tcl_Eval. See tcl.h for other flags to
+ * Tcl_Eval; these ones are only used internally by Tcl.
+ *
+ * TCL_RECORD_BOUNDS Tells Tcl_Eval to record information in the
+ * evalFirst and evalLast fields for each command
+ * executed directly from the string (top-level
+ * commands and those from command substitution).
+ */
+
+#define TCL_RECORD_BOUNDS 0x100
+
+/*
+ * Maximum number of levels of nesting permitted in Tcl commands (used
+ * to catch infinite recursion).
+ */
+
+#define MAX_NESTING_DEPTH 1000
+
+/*
+ * The macro below is used to modify a "char" value (e.g. by casting
+ * it to an unsigned character) so that it can be used safely with
+ * macros such as isspace.
+ */
+
+#define UCHAR(c) ((unsigned char) (c))
+
+/*
+ * Given a size or address, the macro below "aligns" it to the machine's
+ * memory unit size (e.g. an 8-byte boundary) so that anything can be
+ * placed at the aligned address without fear of an alignment error.
+ */
+
+#define TCL_ALIGN(x) ((x + 7) & ~7)
+
+/*
+ * Variables shared among Tcl modules but not used by the outside
+ * world:
+ */
+
+extern int tclNumFiles;
+extern OpenFile ** tclOpenFiles;
+extern char * tclRegexpError;
+
+/*
+ *----------------------------------------------------------------
+ * Procedures shared among Tcl modules but not used by the outside
+ * world:
+ *----------------------------------------------------------------
+ */
+
+extern void panic();
+extern regexp * TclCompileRegexp _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string));
+extern void TclCopyAndCollapse _ANSI_ARGS_((int count, char *src,
+ char *dst));
+extern void TclDeleteVars _ANSI_ARGS_((Interp *iPtr,
+ Tcl_HashTable *tablePtr));
+extern void TclExpandParseValue _ANSI_ARGS_((ParseValue *pvPtr,
+ int needed));
+extern int TclFindElement _ANSI_ARGS_((Tcl_Interp *interp,
+ char *list, char **elementPtr, char **nextPtr,
+ int *sizePtr, int *bracePtr));
+extern Proc * TclFindProc _ANSI_ARGS_((Interp *iPtr,
+ char *procName));
+extern int TclGetFrame _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, CallFrame **framePtrPtr));
+extern int TclGetListIndex _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int *indexPtr));
+extern Proc * TclIsProc _ANSI_ARGS_((Command *cmdPtr));
+extern int TclParseBraces _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, char **termPtr, ParseValue *pvPtr));
+extern int TclParseNestedCmd _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int flags, char **termPtr,
+ ParseValue *pvPtr));
+extern int TclParseQuotes _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int termChar, int flags,
+ char **termPtr, ParseValue *pvPtr));
+extern int TclParseWords _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int flags, int maxWords,
+ char **termPtr, int *argcPtr, char **argv,
+ ParseValue *pvPtr));
+extern char * TclPrecTraceProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *name1, char *name2,
+ int flags));
+extern void TclSetupEnv _ANSI_ARGS_((Tcl_Interp *interp));
+extern char * TclWordEnd _ANSI_ARGS_((char *start, int nested,
+ int *semiPtr));
+
+/*
+ *----------------------------------------------------------------
+ * Command procedures in the generic core:
+ *----------------------------------------------------------------
+ */
+
+extern int Tcl_AppendCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ArrayCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_BreakCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_CaseCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_CatchCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ConcatCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ContinueCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ErrorCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_EvalCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ExprCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ForCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ForeachCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_FormatCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_GlobalCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_HistoryCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_IfCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_IncrCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_InfoCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_JoinCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LappendCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LindexCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LinsertCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LlengthCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ListCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LrangeCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LreplaceCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LsearchCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_LsortCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ProcCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_RegexpCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_RegsubCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_RenameCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ReturnCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ScanCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_SetCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_SplitCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_StringCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_SwitchCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_TraceCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_UnsetCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_UplevelCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_UpvarCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_WhileCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_Cmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_Cmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+
+/*
+ *----------------------------------------------------------------
+ * Command procedures in the UNIX core:
+ *----------------------------------------------------------------
+ */
+
+extern int Tcl_CdCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_CloseCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_EofCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ExecCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ExitCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_FileCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_FlushCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_GetsCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_GlobCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_OpenCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_PutsCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_PidCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_PwdCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_ReadCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_SeekCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_SourceCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_TellCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+extern int Tcl_TimeCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+
+#endif /* _TCLINT */
diff --git a/vendor/x11iraf/obm/Tcl/tclLink.c b/vendor/x11iraf/obm/Tcl/tclLink.c
new file mode 100644
index 00000000..887d9766
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclLink.c
@@ -0,0 +1,361 @@
+/*
+ * tclLink.c --
+ *
+ * This file implements linked variables (a C variable that is
+ * tied to a Tcl variable). The idea of linked variables was
+ * first suggested by Andreas Stocke and this implementation is
+ * based heavily on a prototype implementation provided by
+ * him.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclLink.c,v 1.4 93/07/29 15:24:05 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+
+/*
+ * For each linked variable there is a data structure of the following
+ * type, which describes the link and is the clientData for the trace
+ * set on the Tcl variable.
+ */
+
+typedef struct Link {
+ Tcl_Interp *interp; /* Interpreter containing Tcl variable. */
+ char *addr; /* Location of C variable. */
+ int type; /* Type of link (TCL_LINK_INT, etc.). */
+ int writable; /* Zero means Tcl variable is read-only. */
+ union {
+ int i;
+ double d;
+ } lastValue; /* Last known value of C variable; used to
+ * avoid string conversions. */
+} Link;
+
+/*
+ * Forward references to procedures defined later in this file:
+ */
+
+static char * LinkTraceProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *name1, char *name2,
+ int flags));
+static char * StringValue _ANSI_ARGS_((Link *linkPtr,
+ char *buffer));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LinkVar --
+ *
+ * Link a C variable to a Tcl variable so that changes to either
+ * one causes the other to change.
+ *
+ * Results:
+ * The return value is TCL_OK if everything went well or TCL_ERROR
+ * if an error occurred (interp->result is also set after errors).
+ *
+ * Side effects:
+ * The value at *addr is linked to the Tcl variable "varName",
+ * using "type" to convert between string values for Tcl and
+ * binary values for *addr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_LinkVar(interp, varName, addr, type)
+ Tcl_Interp *interp; /* Interpreter in which varName exists. */
+ char *varName; /* Name of a global variable in interp. */
+ char *addr; /* Address of a C variable to be linked
+ * to varName. */
+ int type; /* Type of C variable: TCL_LINK_INT, etc.
+ * Also may have TCL_LINK_READ_ONLY
+ * OR'ed in. */
+{
+ Link *linkPtr;
+ char buffer[TCL_DOUBLE_SPACE];
+ int code;
+
+ linkPtr = (Link *) ckalloc(sizeof(Link));
+ linkPtr->interp = interp;
+ linkPtr->addr = addr;
+ linkPtr->type = type & ~TCL_LINK_READ_ONLY;
+ linkPtr->writable = (type & TCL_LINK_READ_ONLY) == 0;
+ if (Tcl_SetVar(interp, varName, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
+ ckfree((char *) linkPtr);
+ return TCL_ERROR;
+ }
+ code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS
+ |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc,
+ (ClientData) linkPtr);
+ if (code != TCL_OK) {
+ ckfree((char *) linkPtr);
+ }
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UnlinkVar --
+ *
+ * Destroy the link between a Tcl variable and a C variable.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If "varName" was previously linked to a C variable, the link
+ * is broken to make the variable independent. If there was no
+ * previous link for "varName" then nothing happens.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_UnlinkVar(interp, varName)
+ Tcl_Interp *interp; /* Interpreter containing variable to unlink. */
+ char *varName; /* Global variable in interp to unlink. */
+{
+ Link *linkPtr;
+
+ linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
+ LinkTraceProc, (ClientData) NULL);
+ if (linkPtr == NULL) {
+ return;
+ }
+ Tcl_UntraceVar(interp, varName,
+ TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ LinkTraceProc, (ClientData) linkPtr);
+ ckfree((char *) linkPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * LinkTraceProc --
+ *
+ * This procedure is invoked when a linked Tcl variable is read,
+ * written, or unset from Tcl. It's responsible for keeping the
+ * C variable in sync with the Tcl variable.
+ *
+ * Results:
+ * If all goes well, NULL is returned; otherwise an error message
+ * is returned.
+ *
+ * Side effects:
+ * The C variable may be updated to make it consistent with the
+ * Tcl variable, or the Tcl variable may be overwritten to reject
+ * a modification.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+LinkTraceProc(clientData, interp, name1, name2, flags)
+ ClientData clientData; /* Contains information about the link. */
+ Tcl_Interp *interp; /* Interpreter containing Tcl variable. */
+ char *name1; /* First part of variable name. */
+ char *name2; /* Second part of variable name. */
+ int flags; /* Miscellaneous additional information. */
+{
+ Link *linkPtr = (Link *) clientData;
+ int changed;
+ char buffer[TCL_DOUBLE_SPACE];
+ char *value, **pp;
+ Tcl_DString savedResult;
+
+ /*
+ * If the variable is being unset, then just re-create it (with a
+ * trace) unless the whole interpreter is going away.
+ */
+
+ if (flags & TCL_TRACE_UNSETS) {
+ if (flags & TCL_INTERP_DESTROYED) {
+ ckfree((char *) linkPtr);
+ }
+ if (flags & TCL_TRACE_DESTROYED) {
+ Tcl_SetVar2(interp, name1, name2,
+ StringValue(linkPtr, buffer), TCL_GLOBAL_ONLY);
+ Tcl_TraceVar2(interp, name1, name2, TCL_GLOBAL_ONLY
+ |TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ LinkTraceProc, (ClientData) linkPtr);
+ }
+ return NULL;
+ }
+
+ /*
+ * For read accesses, update the Tcl variable if the C variable
+ * has changed since the last time we updated the Tcl variable.
+ */
+
+ if (flags & TCL_TRACE_READS) {
+ switch (linkPtr->type) {
+ case TCL_LINK_INT:
+ case TCL_LINK_BOOLEAN:
+ changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i;
+ break;
+ case TCL_LINK_DOUBLE:
+ changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d;
+ break;
+ case TCL_LINK_STRING:
+ changed = 1;
+ break;
+ default:
+ return "internal error: bad linked variable type";
+ }
+ if (changed) {
+ Tcl_SetVar2(interp, name1, name2, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY);
+ }
+ return NULL;
+ }
+
+ /*
+ * For writes, first make sure that the variable is writable. Then
+ * convert the Tcl value to C if possible. If the variable isn't
+ * writable or can't be converted, then restore the varaible's old
+ * value and return an error. Another tricky thing: we have to save
+ * and restore the interpreter's result, since the variable access
+ * could occur when the result has been partially set.
+ */
+
+ if (!linkPtr->writable) {
+ Tcl_SetVar2(interp, name1, name2, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY);
+ return "linked variable is read-only";
+ }
+ value = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
+ if (value == NULL) {
+ /*
+ * This shouldn't ever happen.
+ */
+ return "internal error: linked variable couldn't be read";
+ }
+ Tcl_DStringInit(&savedResult);
+ Tcl_DStringAppend(&savedResult, interp->result, -1);
+ Tcl_ResetResult(interp);
+ switch (linkPtr->type) {
+ case TCL_LINK_INT:
+ if (Tcl_GetInt(interp, value, &linkPtr->lastValue.i) != TCL_OK) {
+ Tcl_DStringResult(interp, &savedResult);
+ Tcl_SetVar2(interp, name1, name2, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY);
+ return "variable must have integer value";
+ }
+ *(int *)(linkPtr->addr) = linkPtr->lastValue.i;
+ break;
+ case TCL_LINK_DOUBLE:
+ if (Tcl_GetDouble(interp, value, &linkPtr->lastValue.d)
+ != TCL_OK) {
+ Tcl_DStringResult(interp, &savedResult);
+ Tcl_SetVar2(interp, name1, name2, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY);
+ return "variable must have real value";
+ }
+ *(double *)(linkPtr->addr) = linkPtr->lastValue.d;
+ break;
+ case TCL_LINK_BOOLEAN:
+ if (Tcl_GetBoolean(interp, value, &linkPtr->lastValue.i)
+ != TCL_OK) {
+ Tcl_DStringResult(interp, &savedResult);
+ Tcl_SetVar2(interp, name1, name2, StringValue(linkPtr, buffer),
+ TCL_GLOBAL_ONLY);
+ return "variable must have boolean value";
+ }
+ *(int *)(linkPtr->addr) = linkPtr->lastValue.i;
+ break;
+ case TCL_LINK_STRING:
+ pp = (char **)(linkPtr->addr);
+ if (*pp != NULL) {
+ ckfree(*pp);
+ }
+ *pp = ckalloc((unsigned) (strlen(value) + 1));
+ strcpy(*pp, value);
+ break;
+ default:
+ return "internal error: bad linked variable type";
+ }
+ Tcl_DStringResult(interp, &savedResult);
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringValue --
+ *
+ * Converts the value of a C variable to a string for use in a
+ * Tcl variable to which it is linked.
+ *
+ * Results:
+ * The return value is a pointer
+ to a string that represents
+ * the value of the C variable given by linkPtr.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+StringValue(linkPtr, buffer)
+ Link *linkPtr; /* Structure describing linked variable. */
+ char *buffer; /* Small buffer to use for converting
+ * values. Must have TCL_DOUBLE_SPACE
+ * bytes or more. */
+{
+ char *p;
+
+ switch (linkPtr->type) {
+ case TCL_LINK_INT:
+ linkPtr->lastValue.i = *(int *)(linkPtr->addr);
+ sprintf(buffer, "%d", linkPtr->lastValue.i);
+ return buffer;
+ case TCL_LINK_DOUBLE:
+ linkPtr->lastValue.d = *(double *)(linkPtr->addr);
+ Tcl_PrintDouble(linkPtr->interp, linkPtr->lastValue.d, buffer);
+ return buffer;
+ case TCL_LINK_BOOLEAN:
+ linkPtr->lastValue.i = *(int *)(linkPtr->addr);
+ if (linkPtr->lastValue.i != 0) {
+ return "1";
+ }
+ return "0";
+ case TCL_LINK_STRING:
+ p = *(char **)(linkPtr->addr);
+ if (p == NULL) {
+ return "NULL";
+ }
+ return p;
+ }
+
+ /*
+ * This code only gets executed if the link type is unknown
+ * (shouldn't ever happen).
+ */
+
+ return "??";
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclMain.c b/vendor/x11iraf/obm/Tcl/tclMain.c
new file mode 100644
index 00000000..f080dcd2
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclMain.c
@@ -0,0 +1,296 @@
+/*
+ * main.c --
+ *
+ * Main program for Tcl shells and other Tcl-based applications.
+ *
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclMain.c,v 1.12 93/11/11 09:35:10 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include <stdio.h>
+#include <tcl.h>
+#include <errno.h>
+
+/*
+ * Declarations for various library procedures and variables (don't want
+ * to include tclUnix.h here, because people might copy this file out of
+ * the Tcl source directory to make their own modified versions).
+ */
+
+extern int errno;
+extern void exit _ANSI_ARGS_((int status));
+extern int isatty _ANSI_ARGS_((int fd));
+extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src));
+
+static Tcl_Interp *interp; /* Interpreter for application. */
+static Tcl_DString command; /* Used to buffer incomplete commands being
+ * read from stdin. */
+char *tcl_RcFileName = NULL; /* Name of a user-specific startup script
+ * to source if the application is being run
+ * interactively (e.g. "~/.tclshrc"). Set
+ * by Tcl_AppInit. NULL means don't source
+ * anything ever. */
+#ifdef TCL_MEM_DEBUG
+static char dumpFile[100]; /* Records where to dump memory allocation
+ * information. */
+static int quitFlag = 0; /* 1 means the "checkmem" command was
+ * invoked, so the application should quit
+ * and dump memory allocation information. */
+#endif
+
+/*
+ * Forward references for procedures defined later in this file:
+ */
+
+static int CheckmemCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char *argv[]));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * main --
+ *
+ * This is the main program for a Tcl-based shell that reads
+ * Tcl commands from standard input.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Can be almost arbitrary, depending on what the Tcl commands do.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+main(argc, argv)
+ int argc; /* Number of arguments. */
+ char **argv; /* Array of argument strings. */
+{
+ char buffer[1000], *cmd, *args, *fileName;
+ int code, gotPartial, tty;
+ int exitCode = 0;
+
+ interp = Tcl_CreateInterp();
+#ifdef TCL_MEM_DEBUG
+ Tcl_InitMemory(interp);
+ Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+#endif
+
+ /*
+ * Make command-line arguments available in the Tcl variables "argc"
+ * and "argv". If the first argument doesn't start with a "-" then
+ * strip it off and use it as the name of a script file to process.
+ */
+
+ fileName = NULL;
+ if ((argc > 1) && (argv[1][0] != '-')) {
+ fileName = argv[1];
+ argc--;
+ argv++;
+ }
+ args = Tcl_Merge(argc-1, argv+1);
+ Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
+ ckfree(args);
+ sprintf(buffer, "%d", argc-1);
+ Tcl_SetVar(interp, "argc", buffer, TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
+ TCL_GLOBAL_ONLY);
+
+ /*
+ * Set the "tcl_interactive" variable.
+ */
+
+ tty = isatty(0);
+ Tcl_SetVar(interp, "tcl_interactive",
+ ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY);
+
+ /*
+ * Invoke application-specific initialization.
+ */
+
+ if (Tcl_AppInit(interp) != TCL_OK) {
+ fprintf(stderr, "Tcl_AppInit failed: %s\n", interp->result);
+ }
+
+ /*
+ * If a script file was specified then just source that file
+ * and quit.
+ */
+
+ if (fileName != NULL) {
+ code = Tcl_EvalFile(interp, fileName);
+ if (code != TCL_OK) {
+ fprintf(stderr, "%s\n", interp->result);
+ exitCode = 1;
+ }
+ goto done;
+ }
+
+ /*
+ * We're running interactively. Source a user-specific startup
+ * file if Tcl_AppInit specified one and if the file exists.
+ */
+
+ if (tcl_RcFileName != NULL) {
+ Tcl_DString buffer;
+ char *fullName;
+ FILE *f;
+
+ fullName = Tcl_TildeSubst(interp, tcl_RcFileName, &buffer);
+ if (fullName == NULL) {
+ fprintf(stderr, "%s\n", interp->result);
+ } else {
+ f = fopen(fullName, "r");
+ if (f != NULL) {
+ code = Tcl_EvalFile(interp, fullName);
+ if (code != TCL_OK) {
+ fprintf(stderr, "%s\n", interp->result);
+ }
+ fclose(f);
+ }
+ }
+ Tcl_DStringFree(&buffer);
+ }
+
+ /*
+ * Process commands from stdin until there's an end-of-file.
+ */
+
+ gotPartial = 0;
+ Tcl_DStringInit(&command);
+ while (1) {
+ clearerr(stdin);
+ if (tty) {
+ char *promptCmd;
+
+ promptCmd = Tcl_GetVar(interp,
+ gotPartial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY);
+ if (promptCmd == NULL) {
+ defaultPrompt:
+ if (!gotPartial) {
+ fputs("% ", stdout);
+ }
+ } else {
+ code = Tcl_Eval(interp, promptCmd);
+ if (code != TCL_OK) {
+ fprintf(stderr, "%s\n", interp->result);
+ Tcl_AddErrorInfo(interp,
+ "\n (script that generates prompt)");
+ goto defaultPrompt;
+ }
+ }
+ fflush(stdout);
+ }
+ if (fgets(buffer, 1000, stdin) == NULL) {
+ if (ferror(stdin)) {
+ if (errno == EINTR) {
+ if (tcl_AsyncReady) {
+ (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
+ }
+ clearerr(stdin);
+ } else {
+ goto done;
+ }
+ } else {
+ if (!gotPartial) {
+ goto done;
+ }
+ }
+ buffer[0] = 0;
+ }
+ cmd = Tcl_DStringAppend(&command, buffer, -1);
+ if ((buffer[0] != 0) && !Tcl_CommandComplete(cmd)) {
+ gotPartial = 1;
+ continue;
+ }
+
+ gotPartial = 0;
+ code = Tcl_RecordAndEval(interp, cmd, 0);
+ Tcl_DStringFree(&command);
+ if (code != TCL_OK) {
+ fprintf(stderr, "%s\n", interp->result);
+ } else if (tty && (*interp->result != 0)) {
+ printf("%s\n", interp->result);
+ }
+#ifdef TCL_MEM_DEBUG
+ if (quitFlag) {
+ Tcl_DeleteInterp(interp);
+ Tcl_DumpActiveMemory(dumpFile);
+ exit(0);
+ }
+#endif
+ }
+
+ /*
+ * Rather than calling exit, invoke the "exit" command so that
+ * users can replace "exit" with some other command to do additional
+ * cleanup on exit. The Tcl_Eval call should never return.
+ */
+
+ done:
+ sprintf(buffer, "exit %d", exitCode);
+ Tcl_Eval(interp, buffer);
+ return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CheckmemCmd --
+ *
+ * This is the command procedure for the "checkmem" command, which
+ * causes the application to exit after printing information about
+ * memory usage to the file passed to this command as its first
+ * argument.
+ *
+ * Results:
+ * Returns a standard Tcl completion code.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+#ifdef TCL_MEM_DEBUG
+
+ /* ARGSUSED */
+static int
+CheckmemCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Not used. */
+ Tcl_Interp *interp; /* Interpreter for evaluation. */
+ int argc; /* Number of arguments. */
+ char *argv[]; /* String values of arguments. */
+{
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ strcpy(dumpFile, argv[1]);
+ quitFlag = 1;
+ return TCL_OK;
+}
+#endif
diff --git a/vendor/x11iraf/obm/Tcl/tclMtherr.c b/vendor/x11iraf/obm/Tcl/tclMtherr.c
new file mode 100644
index 00000000..81c14ac5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclMtherr.c
@@ -0,0 +1,89 @@
+/*
+ * tclMatherr.c --
+ *
+ * This function provides a default implementation of the
+ * "matherr" function, for SYS-V systems where it's needed.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclMtherr.c,v 1.7 93/10/31 16:19:31 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include <math.h>
+
+#ifndef TCL_GENERIC_ONLY
+#include "tclUnix.h"
+#else
+#define NO_ERRNO_H
+#endif
+
+#ifdef NO_ERRNO_H
+extern int errno; /* Use errno from tclExpr.c. */
+#define EDOM 33
+#define ERANGE 34
+#endif
+
+/*
+ * The following variable is secretly shared with Tcl so we can
+ * tell if expression evaluation is in progress. If not, matherr
+ * just emulates the default behavior, which includes printing
+ * a message.
+ */
+
+extern int tcl_MathInProgress;
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * matherr --
+ *
+ * This procedure is invoked on Sys-V systems when certain
+ * errors occur in mathematical functions. Type "man matherr"
+ * for more information on how this function works.
+ *
+ * Results:
+ * Returns 1 to indicate that we've handled the error
+ * locally.
+ *
+ * Side effects:
+ * Sets errno based on what's in xPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+matherr(xPtr)
+ struct exception *xPtr; /* Describes error that occurred. */
+{
+ if (!tcl_MathInProgress) {
+ return 0;
+ }
+ if ((xPtr->type == DOMAIN) || (xPtr->type == SING)) {
+ errno = EDOM;
+ } else {
+ errno = ERANGE;
+ }
+ return 1;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclParse.c b/vendor/x11iraf/obm/Tcl/tclParse.c
new file mode 100644
index 00000000..433e0544
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclParse.c
@@ -0,0 +1,1284 @@
+/*
+ * tclParse.c --
+ *
+ * This file contains a collection of procedures that are used
+ * to parse Tcl commands or parts of commands (like quoted
+ * strings or nested sub-commands).
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclParse.c,v 1.37 93/10/14 15:14:06 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+/* Slackware/RedHat4.2 compatibility hack. */
+#if defined(linux) && defined(isalnum)
+#undef isalnum
+#define isalnum(c) (isalpha(c)||isdigit(c))
+#endif
+
+
+/*
+ * The following table assigns a type to each character. Only types
+ * meaningful to Tcl parsing are represented here. The table indexes
+ * all 256 characters, with the negative ones first, then the positive
+ * ones.
+ */
+
+char tclTypeTable[] = {
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE,
+ TCL_SPACE, TCL_SPACE, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL,
+ TCL_DOLLAR, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_COMMAND_END,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACKET,
+ TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
+ TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE,
+ TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL,
+};
+
+/*
+ * Function prototypes for procedures local to this file:
+ */
+
+static char * QuoteEnd _ANSI_ARGS_((char *string, int term));
+static char * VarNameEnd _ANSI_ARGS_((char *string));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_Backslash --
+ *
+ * Figure out how to handle a backslash sequence.
+ *
+ * Results:
+ * The return value is the character that should be substituted
+ * in place of the backslash sequence that starts at src. If
+ * readPtr isn't NULL then it is filled in with a count of the
+ * number of characters in the backslash sequence.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char
+Tcl_Backslash(src, readPtr)
+ char *src; /* Points to the backslash character of
+ * a backslash sequence. */
+ int *readPtr; /* Fill in with number of characters read
+ * from src, unless NULL. */
+{
+ register char *p = src+1;
+ char result;
+ int count;
+
+ count = 2;
+
+ switch (*p) {
+ case 'a':
+ result = 0x7; /* Don't say '\a' here, since some compilers */
+ break; /* don't support it. */
+ case 'b':
+ result = '\b';
+ break;
+ case 'f':
+ result = '\f';
+ break;
+ case 'n':
+ result = '\n';
+ break;
+ case 'r':
+ result = '\r';
+ break;
+ case 't':
+ result = '\t';
+ break;
+ case 'v':
+ result = '\v';
+ break;
+ case 'x':
+ if (isxdigit(UCHAR(p[1]))) {
+ char *end;
+
+ result = strtoul(p+1, &end, 16);
+ count = end - src;
+ } else {
+ count = 2;
+ result = 'x';
+ }
+ break;
+ case '\n':
+ do {
+ p++;
+ } while (isspace(UCHAR(*p)));
+ result = ' ';
+ count = p - src;
+ break;
+ case 0:
+ result = '\\';
+ count = 1;
+ break;
+ default:
+ if (isdigit(UCHAR(*p))) {
+ result = *p - '0';
+ p++;
+ if (!isdigit(UCHAR(*p))) {
+ break;
+ }
+ count = 3;
+ result = (result << 3) + (*p - '0');
+ p++;
+ if (!isdigit(UCHAR(*p))) {
+ break;
+ }
+ count = 4;
+ result = (result << 3) + (*p - '0');
+ break;
+ }
+ result = *p;
+ count = 2;
+ break;
+ }
+
+ if (readPtr != NULL) {
+ *readPtr = count;
+ }
+ return result;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TclParseQuotes --
+ *
+ * This procedure parses a double-quoted string such as a
+ * quoted Tcl command argument or a quoted value in a Tcl
+ * expression. This procedure is also used to parse array
+ * element names within parentheses, or anything else that
+ * needs all the substitutions that happen in quotes.
+ *
+ * Results:
+ * The return value is a standard Tcl result, which is
+ * TCL_OK unless there was an error while parsing the
+ * quoted string. If an error occurs then interp->result
+ * contains a standard error message. *TermPtr is filled
+ * in with the address of the character just after the
+ * last one successfully processed; this is usually the
+ * character just after the matching close-quote. The
+ * fully-substituted contents of the quotes are stored in
+ * standard fashion in *pvPtr, null-terminated with
+ * pvPtr->next pointing to the terminating null character.
+ *
+ * Side effects:
+ * The buffer space in pvPtr may be enlarged by calling its
+ * expandProc.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TclParseQuotes(interp, string, termChar, flags, termPtr, pvPtr)
+ Tcl_Interp *interp; /* Interpreter to use for nested command
+ * evaluations and error messages. */
+ char *string; /* Character just after opening double-
+ * quote. */
+ int termChar; /* Character that terminates "quoted" string
+ * (usually double-quote, but sometimes
+ * right-paren or something else). */
+ int flags; /* Flags to pass to nested Tcl_Eval calls. */
+ char **termPtr; /* Store address of terminating character
+ * here. */
+ ParseValue *pvPtr; /* Information about where to place
+ * fully-substituted result of parse. */
+{
+ register char *src, *dst, c;
+
+ src = string;
+ dst = pvPtr->next;
+
+ while (1) {
+ if (dst == pvPtr->end) {
+ /*
+ * Target buffer space is about to run out. Make more space.
+ */
+
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, 1);
+ dst = pvPtr->next;
+ }
+
+ c = *src;
+ src++;
+ if (c == termChar) {
+ *dst = '\0';
+ pvPtr->next = dst;
+ *termPtr = src;
+ return TCL_OK;
+ } else if (CHAR_TYPE(c) == TCL_NORMAL) {
+ copy:
+ *dst = c;
+ dst++;
+ continue;
+ } else if (c == '$') {
+ int length;
+ char *value;
+
+ value = Tcl_ParseVar(interp, src-1, termPtr);
+ if (value == NULL) {
+ return TCL_ERROR;
+ }
+ src = *termPtr;
+ length = strlen(value);
+ if ((pvPtr->end - dst) <= length) {
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, length);
+ dst = pvPtr->next;
+ }
+ strcpy(dst, value);
+ dst += length;
+ continue;
+ } else if (c == '[') {
+ int result;
+
+ pvPtr->next = dst;
+ result = TclParseNestedCmd(interp, src, flags, termPtr, pvPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ src = *termPtr;
+ dst = pvPtr->next;
+ continue;
+ } else if (c == '\\') {
+ int numRead;
+
+ src--;
+ *dst = Tcl_Backslash(src, &numRead);
+ dst++;
+ src += numRead;
+ continue;
+ } else if (c == '\0') {
+ Tcl_ResetResult(interp);
+ sprintf(interp->result, "missing %c", termChar);
+ *termPtr = string-1;
+ return TCL_ERROR;
+ } else {
+ goto copy;
+ }
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TclParseNestedCmd --
+ *
+ * This procedure parses a nested Tcl command between
+ * brackets, returning the result of the command.
+ *
+ * Results:
+ * The return value is a standard Tcl result, which is
+ * TCL_OK unless there was an error while executing the
+ * nested command. If an error occurs then interp->result
+ * contains a standard error message. *TermPtr is filled
+ * in with the address of the character just after the
+ * last one processed; this is usually the character just
+ * after the matching close-bracket, or the null character
+ * at the end of the string if the close-bracket was missing
+ * (a missing close bracket is an error). The result returned
+ * by the command is stored in standard fashion in *pvPtr,
+ * null-terminated, with pvPtr->next pointing to the null
+ * character.
+ *
+ * Side effects:
+ * The storage space at *pvPtr may be expanded.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TclParseNestedCmd(interp, string, flags, termPtr, pvPtr)
+ Tcl_Interp *interp; /* Interpreter to use for nested command
+ * evaluations and error messages. */
+ char *string; /* Character just after opening bracket. */
+ int flags; /* Flags to pass to nested Tcl_Eval. */
+ char **termPtr; /* Store address of terminating character
+ * here. */
+ register ParseValue *pvPtr; /* Information about where to place
+ * result of command. */
+{
+ int result, length, shortfall;
+ Interp *iPtr = (Interp *) interp;
+
+ iPtr->evalFlags = flags | TCL_BRACKET_TERM;
+ result = Tcl_Eval(interp, string);
+ *termPtr = iPtr->termPtr;
+ if (result != TCL_OK) {
+ /*
+ * The increment below results in slightly cleaner message in
+ * the errorInfo variable (the close-bracket will appear).
+ */
+
+ if (**termPtr == ']') {
+ *termPtr += 1;
+ }
+ return result;
+ }
+ (*termPtr) += 1;
+ length = strlen(iPtr->result);
+ shortfall = length + 1 - (pvPtr->end - pvPtr->next);
+ if (shortfall > 0) {
+ (*pvPtr->expandProc)(pvPtr, shortfall);
+ }
+ strcpy(pvPtr->next, iPtr->result);
+ pvPtr->next += length;
+ Tcl_FreeResult(iPtr);
+ iPtr->result = iPtr->resultSpace;
+ iPtr->resultSpace[0] = '\0';
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TclParseBraces --
+ *
+ * This procedure scans the information between matching
+ * curly braces.
+ *
+ * Results:
+ * The return value is a standard Tcl result, which is
+ * TCL_OK unless there was an error while parsing string.
+ * If an error occurs then interp->result contains a
+ * standard error message. *TermPtr is filled
+ * in with the address of the character just after the
+ * last one successfully processed; this is usually the
+ * character just after the matching close-brace. The
+ * information between curly braces is stored in standard
+ * fashion in *pvPtr, null-terminated with pvPtr->next
+ * pointing to the terminating null character.
+ *
+ * Side effects:
+ * The storage space at *pvPtr may be expanded.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TclParseBraces(interp, string, termPtr, pvPtr)
+ Tcl_Interp *interp; /* Interpreter to use for nested command
+ * evaluations and error messages. */
+ char *string; /* Character just after opening bracket. */
+ char **termPtr; /* Store address of terminating character
+ * here. */
+ register ParseValue *pvPtr; /* Information about where to place
+ * result of command. */
+{
+ int level;
+ register char *src, *dst, *end;
+ register char c;
+
+ src = string;
+ dst = pvPtr->next;
+ end = pvPtr->end;
+ level = 1;
+
+ /*
+ * Copy the characters one at a time to the result area, stopping
+ * when the matching close-brace is found.
+ */
+
+ while (1) {
+ c = *src;
+ src++;
+ if (dst == end) {
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, 20);
+ dst = pvPtr->next;
+ end = pvPtr->end;
+ }
+ *dst = c;
+ dst++;
+ if (CHAR_TYPE(c) == TCL_NORMAL) {
+ continue;
+ } else if (c == '{') {
+ level++;
+ } else if (c == '}') {
+ level--;
+ if (level == 0) {
+ dst--; /* Don't copy the last close brace. */
+ break;
+ }
+ } else if (c == '\\') {
+ int count;
+
+ /*
+ * Must always squish out backslash-newlines, even when in
+ * braces. This is needed so that this sequence can appear
+ * anywhere in a command, such as the middle of an expression.
+ */
+
+ if (*src == '\n') {
+ dst[-1] = Tcl_Backslash(src-1, &count);
+ src += count - 1;
+ } else {
+ (void) Tcl_Backslash(src-1, &count);
+ while (count > 1) {
+ if (dst == end) {
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, 20);
+ dst = pvPtr->next;
+ end = pvPtr->end;
+ }
+ *dst = *src;
+ dst++;
+ src++;
+ count--;
+ }
+ }
+ } else if (c == '\0') {
+ Tcl_SetResult(interp, "missing close-brace", TCL_STATIC);
+ *termPtr = string-1;
+ return TCL_ERROR;
+ }
+ }
+
+ *dst = '\0';
+ pvPtr->next = dst;
+ *termPtr = src;
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TclParseWords --
+ *
+ * This procedure parses one or more words from a command
+ * string and creates argv-style pointers to fully-substituted
+ * copies of those words.
+ *
+ * Results:
+ * The return value is a standard Tcl result.
+ *
+ * *argcPtr is modified to hold a count of the number of words
+ * successfully parsed, which may be 0. At most maxWords words
+ * will be parsed. If 0 <= *argcPtr < maxWords then it
+ * means that a command separator was seen. If *argcPtr
+ * is maxWords then it means that a command separator was
+ * not seen yet.
+ *
+ * *TermPtr is filled in with the address of the character
+ * just after the last one successfully processed in the
+ * last word. This is either the command terminator (if
+ * *argcPtr < maxWords), the character just after the last
+ * one in a word (if *argcPtr is maxWords), or the vicinity
+ * of an error (if the result is not TCL_OK).
+ *
+ * The pointers at *argv are filled in with pointers to the
+ * fully-substituted words, and the actual contents of the
+ * words are copied to the buffer at pvPtr.
+ *
+ * If an error occurrs then an error message is left in
+ * interp->result and the information at *argv, *argcPtr,
+ * and *pvPtr may be incomplete.
+ *
+ * Side effects:
+ * The buffer space in pvPtr may be enlarged by calling its
+ * expandProc.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TclParseWords(interp, string, flags, maxWords, termPtr, argcPtr, argv, pvPtr)
+ Tcl_Interp *interp; /* Interpreter to use for nested command
+ * evaluations and error messages. */
+ char *string; /* First character of word. */
+ int flags; /* Flags to control parsing (same values as
+ * passed to Tcl_Eval). */
+ int maxWords; /* Maximum number of words to parse. */
+ char **termPtr; /* Store address of terminating character
+ * here. */
+ int *argcPtr; /* Filled in with actual number of words
+ * parsed. */
+ char **argv; /* Store addresses of individual words here. */
+ register ParseValue *pvPtr; /* Information about where to place
+ * fully-substituted word. */
+{
+ register char *src, *dst;
+ register char c;
+ int type, result, argc;
+ char *oldBuffer; /* Used to detect when pvPtr's buffer gets
+ * reallocated, so we can adjust all of the
+ * argv pointers. */
+
+ src = string;
+ oldBuffer = pvPtr->buffer;
+ dst = pvPtr->next;
+ for (argc = 0; argc < maxWords; argc++) {
+ argv[argc] = dst;
+
+ /*
+ * Skip leading space.
+ */
+
+ skipSpace:
+ c = *src;
+ type = CHAR_TYPE(c);
+ while (type == TCL_SPACE) {
+ src++;
+ c = *src;
+ type = CHAR_TYPE(c);
+ }
+
+ /*
+ * Handle the normal case (i.e. no leading double-quote or brace).
+ */
+
+ if (type == TCL_NORMAL) {
+ normalArg:
+ while (1) {
+ if (dst == pvPtr->end) {
+ /*
+ * Target buffer space is about to run out. Make
+ * more space.
+ */
+
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, 1);
+ dst = pvPtr->next;
+ }
+
+ if (type == TCL_NORMAL) {
+ copy:
+ *dst = c;
+ dst++;
+ src++;
+ } else if (type == TCL_SPACE) {
+ goto wordEnd;
+ } else if (type == TCL_DOLLAR) {
+ int length;
+ char *value;
+
+ value = Tcl_ParseVar(interp, src, termPtr);
+ if (value == NULL) {
+ return TCL_ERROR;
+ }
+ src = *termPtr;
+ length = strlen(value);
+ if ((pvPtr->end - dst) <= length) {
+ pvPtr->next = dst;
+ (*pvPtr->expandProc)(pvPtr, length);
+ dst = pvPtr->next;
+ }
+ strcpy(dst, value);
+ dst += length;
+ } else if (type == TCL_COMMAND_END) {
+ if ((c == ']') && !(flags & TCL_BRACKET_TERM)) {
+ goto copy;
+ }
+
+ /*
+ * End of command; simulate a word-end first, so
+ * that the end-of-command can be processed as the
+ * first thing in a new word.
+ */
+
+ goto wordEnd;
+ } else if (type == TCL_OPEN_BRACKET) {
+ pvPtr->next = dst;
+ result = TclParseNestedCmd(interp, src+1, flags, termPtr,
+ pvPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ src = *termPtr;
+ dst = pvPtr->next;
+ } else if (type == TCL_BACKSLASH) {
+ int numRead;
+
+ *dst = Tcl_Backslash(src, &numRead);
+
+ /*
+ * The following special check allows a backslash-newline
+ * to be treated as a word-separator, as if the backslash
+ * and newline had been collapsed before command parsing
+ * began.
+ */
+
+ if (src[1] == '\n') {
+ src += numRead;
+ goto wordEnd;
+ }
+ src += numRead;
+ dst++;
+ } else {
+ goto copy;
+ }
+ c = *src;
+ type = CHAR_TYPE(c);
+ }
+ } else {
+
+ /*
+ * Check for the end of the command.
+ */
+
+ if (type == TCL_COMMAND_END) {
+ if (flags & TCL_BRACKET_TERM) {
+ if (c == '\0') {
+ Tcl_SetResult(interp, "missing close-bracket",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ } else {
+ if (c == ']') {
+ goto normalArg;
+ }
+ }
+ goto done;
+ }
+
+ /*
+ * Now handle the special cases: open braces, double-quotes,
+ * and backslash-newline.
+ */
+
+ pvPtr->next = dst;
+ if (type == TCL_QUOTE) {
+ result = TclParseQuotes(interp, src+1, '"', flags,
+ termPtr, pvPtr);
+ } else if (type == TCL_OPEN_BRACE) {
+ result = TclParseBraces(interp, src+1, termPtr, pvPtr);
+ } else if ((type == TCL_BACKSLASH) && (src[1] == '\n')) {
+ /*
+ * This code is needed so that a backslash-newline at the
+ * very beginning of a word is treated as part of the white
+ * space between words and not as a space within the word.
+ */
+
+ src += 2;
+ goto skipSpace;
+ } else {
+ goto normalArg;
+ }
+ if (result != TCL_OK) {
+ return result;
+ }
+
+ /*
+ * Back from quotes or braces; make sure that the terminating
+ * character was the end of the word. Have to be careful here
+ * to handle continuation lines (i.e. lines ending in backslash).
+ */
+
+ c = **termPtr;
+ if ((c == '\\') && ((*termPtr)[1] == '\n')) {
+ c = (*termPtr)[2];
+ }
+ type = CHAR_TYPE(c);
+ if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
+ if (*src == '"') {
+ Tcl_SetResult(interp, "extra characters after close-quote",
+ TCL_STATIC);
+ } else {
+ Tcl_SetResult(interp, "extra characters after close-brace",
+ TCL_STATIC);
+ }
+ return TCL_ERROR;
+ }
+ src = *termPtr;
+ dst = pvPtr->next;
+
+ }
+
+ /*
+ * We're at the end of a word, so add a null terminator. Then
+ * see if the buffer was re-allocated during this word. If so,
+ * update all of the argv pointers.
+ */
+
+ wordEnd:
+ *dst = '\0';
+ dst++;
+ if (oldBuffer != pvPtr->buffer) {
+ int i;
+
+ for (i = 0; i <= argc; i++) {
+ argv[i] = pvPtr->buffer + (argv[i] - oldBuffer);
+ }
+ oldBuffer = pvPtr->buffer;
+ }
+ }
+
+ done:
+ pvPtr->next = dst;
+ *termPtr = src;
+ *argcPtr = argc;
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TclExpandParseValue --
+ *
+ * This procedure is commonly used as the value of the
+ * expandProc in a ParseValue. It uses malloc to allocate
+ * more space for the result of a parse.
+ *
+ * Results:
+ * The buffer space in *pvPtr is reallocated to something
+ * larger, and if pvPtr->clientData is non-zero the old
+ * buffer is freed. Information is copied from the old
+ * buffer to the new one.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TclExpandParseValue(pvPtr, needed)
+ register ParseValue *pvPtr; /* Information about buffer that
+ * must be expanded. If the clientData
+ * in the structure is non-zero, it
+ * means that the current buffer is
+ * dynamically allocated. */
+ int needed; /* Minimum amount of additional space
+ * to allocate. */
+{
+ int newSpace;
+ char *new;
+
+ /*
+ * Either double the size of the buffer or add enough new space
+ * to meet the demand, whichever produces a larger new buffer.
+ */
+
+ newSpace = (pvPtr->end - pvPtr->buffer) + 1;
+ if (newSpace < needed) {
+ newSpace += needed;
+ } else {
+ newSpace += newSpace;
+ }
+ new = (char *) ckalloc((unsigned) newSpace);
+
+ /*
+ * Copy from old buffer to new, free old buffer if needed, and
+ * mark new buffer as malloc-ed.
+ */
+
+ memcpy((VOID *) new, (VOID *) pvPtr->buffer, pvPtr->next - pvPtr->buffer);
+ pvPtr->next = new + (pvPtr->next - pvPtr->buffer);
+ if (pvPtr->clientData != 0) {
+ ckfree(pvPtr->buffer);
+ }
+ pvPtr->buffer = new;
+ pvPtr->end = new + newSpace - 1;
+ pvPtr->clientData = (ClientData) 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclWordEnd --
+ *
+ * Given a pointer into a Tcl command, find the end of the next
+ * word of the command.
+ *
+ * Results:
+ * The return value is a pointer to the last character that's part
+ * of the word pointed to by "start". If the word doesn't end
+ * properly within the string then the return value is the address
+ * of the null character at the end of the string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+TclWordEnd(start, nested, semiPtr)
+ char *start; /* Beginning of a word of a Tcl command. */
+ int nested; /* Zero means this is a top-level command.
+ * One means this is a nested command (close
+ * brace is a word terminator). */
+ int *semiPtr; /* Set to 1 if word ends with a command-
+ * terminating semi-colon, zero otherwise.
+ * If NULL then ignored. */
+{
+ register char *p;
+ int count;
+
+ if (semiPtr != NULL) {
+ *semiPtr = 0;
+ }
+
+ /*
+ * Skip leading white space (backslash-newline must be treated like
+ * white-space, except that it better not be the last thing in the
+ * command).
+ */
+
+ for (p = start; ; p++) {
+ if (isspace(UCHAR(*p))) {
+ continue;
+ }
+ if ((p[0] == '\\') && (p[1] == '\n')) {
+ if (p[2] == 0) {
+ return p+2;
+ }
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Handle words beginning with a double-quote or a brace.
+ */
+
+ if (*p == '"') {
+ p = QuoteEnd(p+1, '"');
+ if (*p == 0) {
+ return p;
+ }
+ p++;
+ } else if (*p == '{') {
+ int braces = 1;
+ while (braces != 0) {
+ p++;
+ while (*p == '\\') {
+ (void) Tcl_Backslash(p, &count);
+ p += count;
+ }
+ if (*p == '}') {
+ braces--;
+ } else if (*p == '{') {
+ braces++;
+ } else if (*p == 0) {
+ return p;
+ }
+ }
+ p++;
+ }
+
+ /*
+ * Handle words that don't start with a brace or double-quote.
+ * This code is also invoked if the word starts with a brace or
+ * double-quote and there is garbage after the closing brace or
+ * quote. This is an error as far as Tcl_Eval is concerned, but
+ * for here the garbage is treated as part of the word.
+ */
+
+ while (1) {
+ if (*p == '[') {
+ for (p++; *p != ']'; p++) {
+ p = TclWordEnd(p, 1, (int *) NULL);
+ if (*p == 0) {
+ return p;
+ }
+ }
+ p++;
+ } else if (*p == '\\') {
+ (void) Tcl_Backslash(p, &count);
+ p += count;
+ if ((*p == 0) && (count == 2) && (p[-1] == '\n')) {
+ return p;
+ }
+ } else if (*p == '$') {
+ p = VarNameEnd(p);
+ if (*p == 0) {
+ return p;
+ }
+ p++;
+ } else if (*p == ';') {
+ /*
+ * Include the semi-colon in the word that is returned.
+ */
+
+ if (semiPtr != NULL) {
+ *semiPtr = 1;
+ }
+ return p;
+ } else if (isspace(UCHAR(*p))) {
+ return p-1;
+ } else if ((*p == ']') && nested) {
+ return p-1;
+ } else if (*p == 0) {
+ if (nested) {
+ /*
+ * Nested commands can't end because of the end of the
+ * string.
+ */
+ return p;
+ }
+ return p-1;
+ } else {
+ p++;
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * QuoteEnd --
+ *
+ * Given a pointer to a string that obeys the parsing conventions
+ * for quoted things in Tcl, find the end of that quoted thing.
+ * The actual thing may be a quoted argument or a parenthesized
+ * index name.
+ *
+ * Results:
+ * The return value is a pointer to the last character that is
+ * part of the quoted string (i.e the character that's equal to
+ * term). If the quoted string doesn't terminate properly then
+ * the return value is a pointer to the null character at the
+ * end of the string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+QuoteEnd(string, term)
+ char *string; /* Pointer to character just after opening
+ * "quote". */
+ int term; /* This character will terminate the
+ * quoted string (e.g. '"' or ')'). */
+{
+ register char *p = string;
+ int count;
+
+ while (*p != term) {
+ if (*p == '\\') {
+ (void) Tcl_Backslash(p, &count);
+ p += count;
+ } else if (*p == '[') {
+ for (p++; *p != ']'; p++) {
+ p = TclWordEnd(p, 1, (int *) NULL);
+ if (*p == 0) {
+ return p;
+ }
+ }
+ p++;
+ } else if (*p == '$') {
+ p = VarNameEnd(p);
+ if (*p == 0) {
+ return p;
+ }
+ p++;
+ } else if (*p == 0) {
+ return p;
+ } else {
+ p++;
+ }
+ }
+ return p-1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VarNameEnd --
+ *
+ * Given a pointer to a variable reference using $-notation, find
+ * the end of the variable name spec.
+ *
+ * Results:
+ * The return value is a pointer to the last character that
+ * is part of the variable name. If the variable name doesn't
+ * terminate properly then the return value is a pointer to the
+ * null character at the end of the string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+VarNameEnd(string)
+ char *string; /* Pointer to dollar-sign character. */
+{
+ register char *p = string+1;
+
+ if (*p == '{') {
+ for (p++; (*p != '}') && (*p != 0); p++) {
+ /* Empty loop body. */
+ }
+ return p;
+ }
+ while (isalnum(UCHAR(*p)) || (*p == '_')) {
+ p++;
+ }
+ if ((*p == '(') && (p != string+1)) {
+ return QuoteEnd(p+1, ')');
+ }
+ return p-1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ParseVar --
+ *
+ * Given a string starting with a $ sign, parse off a variable
+ * name and return its value.
+ *
+ * Results:
+ * The return value is the contents of the variable given by
+ * the leading characters of string. If termPtr isn't NULL,
+ * *termPtr gets filled in with the address of the character
+ * just after the last one in the variable specifier. If the
+ * variable doesn't exist, then the return value is NULL and
+ * an error message will be left in interp->result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_ParseVar(interp, string, termPtr)
+ Tcl_Interp *interp; /* Context for looking up variable. */
+ register char *string; /* String containing variable name.
+ * First character must be "$". */
+ char **termPtr; /* If non-NULL, points to word to fill
+ * in with character just after last
+ * one in the variable specifier. */
+
+{
+ char *name1, *name1End, c, *result;
+ register char *name2;
+#define NUM_CHARS 200
+ char copyStorage[NUM_CHARS];
+ ParseValue pv;
+
+ /*
+ * There are three cases:
+ * 1. The $ sign is followed by an open curly brace. Then the variable
+ * name is everything up to the next close curly brace, and the
+ * variable is a scalar variable.
+ * 2. The $ sign is not followed by an open curly brace. Then the
+ * variable name is everything up to the next character that isn't
+ * a letter, digit, or underscore. If the following character is an
+ * open parenthesis, then the information between parentheses is
+ * the array element name, which can include any of the substitutions
+ * permissible between quotes.
+ * 3. The $ sign is followed by something that isn't a letter, digit,
+ * or underscore: in this case, there is no variable name, and "$"
+ * is returned.
+ */
+
+ name2 = NULL;
+ string++;
+ if (*string == '{') {
+ string++;
+ name1 = string;
+ while (*string != '}') {
+ if (*string == 0) {
+ Tcl_SetResult(interp, "missing close-brace for variable name",
+ TCL_STATIC);
+ if (termPtr != 0) {
+ *termPtr = string;
+ }
+ return NULL;
+ }
+ string++;
+ }
+ name1End = string;
+ string++;
+ } else {
+ name1 = string;
+ while (isalnum(UCHAR(*string)) || (*string == '_')) {
+ string++;
+ }
+ if (string == name1) {
+ if (termPtr != 0) {
+ *termPtr = string;
+ }
+ return "$";
+ }
+ name1End = string;
+ if (*string == '(') {
+ char *end;
+
+ /*
+ * Perform substitutions on the array element name, just as
+ * is done for quotes.
+ */
+
+ pv.buffer = pv.next = copyStorage;
+ pv.end = copyStorage + NUM_CHARS - 1;
+ pv.expandProc = TclExpandParseValue;
+ pv.clientData = (ClientData) NULL;
+ if (TclParseQuotes(interp, string+1, ')', 0, &end, &pv)
+ != TCL_OK) {
+ char msg[100];
+ sprintf(msg, "\n (parsing index for array \"%.*s\")",
+ string-name1, name1);
+ Tcl_AddErrorInfo(interp, msg);
+ result = NULL;
+ name2 = pv.buffer;
+ if (termPtr != 0) {
+ *termPtr = end;
+ }
+ goto done;
+ }
+ Tcl_ResetResult(interp);
+ string = end;
+ name2 = pv.buffer;
+ }
+ }
+ if (termPtr != 0) {
+ *termPtr = string;
+ }
+
+ if (((Interp *) interp)->noEval) {
+ return "";
+ }
+ c = *name1End;
+ *name1End = 0;
+ result = Tcl_GetVar2(interp, name1, name2, TCL_LEAVE_ERR_MSG);
+ *name1End = c;
+
+ done:
+ if ((name2 != NULL) && (pv.buffer != copyStorage)) {
+ ckfree(pv.buffer);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CommandComplete --
+ *
+ * Given a partial or complete Tcl command, this procedure
+ * determines whether the command is complete in the sense
+ * of having matched braces and quotes and brackets.
+ *
+ * Results:
+ * 1 is returned if the command is complete, 0 otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_CommandComplete(cmd)
+ char *cmd; /* Command to check. */
+{
+ register char *p = cmd;
+ int commentOK = 1;
+
+ while (1) {
+ while (isspace(UCHAR(*p))) {
+ if (*p == '\n') {
+ commentOK = 1;
+ }
+ p++;
+ }
+ if ((*p == '#') && commentOK) {
+ do {
+ p++;
+ } while ((*p != '\n') && (*p != 0));
+ continue;
+ }
+ if (*p == 0) {
+ return 1;
+ }
+ p = TclWordEnd(p, 0, &commentOK);
+ if (*p == 0) {
+ return 0;
+ }
+ p++;
+ }
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclProc.c b/vendor/x11iraf/obm/Tcl/tclProc.c
new file mode 100644
index 00000000..6d290c51
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclProc.c
@@ -0,0 +1,625 @@
+/*
+ * tclProc.c --
+ *
+ * This file contains routines that implement Tcl procedures,
+ * including the "proc" and "uplevel" commands.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclProc.c,v 1.68 93/10/14 15:13:55 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+/*
+ * Forward references to procedures defined later in this file:
+ */
+
+static void CleanupProc _ANSI_ARGS_((Proc *procPtr));
+static int InterpProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+static void ProcDeleteProc _ANSI_ARGS_((ClientData clientData));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ProcCmd --
+ *
+ * This procedure is invoked to process the "proc" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * A new procedure gets created.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ProcCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ register Proc *procPtr;
+ int result, argCount, i;
+ char **argArray = NULL;
+ Arg *lastArgPtr;
+ register Arg *argPtr = NULL; /* Initialization not needed, but
+ * prevents compiler warning. */
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " name args body\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ procPtr = (Proc *) ckalloc(sizeof(Proc));
+ procPtr->iPtr = iPtr;
+ procPtr->refCount = 1;
+ procPtr->command = (char *) ckalloc((unsigned) strlen(argv[3]) + 1);
+ strcpy(procPtr->command, argv[3]);
+ procPtr->argPtr = NULL;
+
+ /*
+ * Break up the argument list into argument specifiers, then process
+ * each argument specifier.
+ */
+
+ result = Tcl_SplitList(interp, argv[2], &argCount, &argArray);
+ if (result != TCL_OK) {
+ goto procError;
+ }
+ lastArgPtr = NULL;
+ for (i = 0; i < argCount; i++) {
+ int fieldCount, nameLength, valueLength;
+ char **fieldValues;
+
+ /*
+ * Now divide the specifier up into name and default.
+ */
+
+ result = Tcl_SplitList(interp, argArray[i], &fieldCount,
+ &fieldValues);
+ if (result != TCL_OK) {
+ goto procError;
+ }
+ if (fieldCount > 2) {
+ ckfree((char *) fieldValues);
+ Tcl_AppendResult(interp,
+ "too many fields in argument specifier \"",
+ argArray[i], "\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto procError;
+ }
+ if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
+ ckfree((char *) fieldValues);
+ Tcl_AppendResult(interp, "procedure \"", argv[1],
+ "\" has argument with no name", (char *) NULL);
+ result = TCL_ERROR;
+ goto procError;
+ }
+ nameLength = strlen(fieldValues[0]) + 1;
+ if (fieldCount == 2) {
+ valueLength = strlen(fieldValues[1]) + 1;
+ } else {
+ valueLength = 0;
+ }
+ argPtr = (Arg *) ckalloc((unsigned)
+ (sizeof(Arg) - sizeof(argPtr->name) + nameLength
+ + valueLength));
+ if (lastArgPtr == NULL) {
+ procPtr->argPtr = argPtr;
+ } else {
+ lastArgPtr->nextPtr = argPtr;
+ }
+ lastArgPtr = argPtr;
+ argPtr->nextPtr = NULL;
+ strcpy(argPtr->name, fieldValues[0]);
+ if (fieldCount == 2) {
+ argPtr->defValue = argPtr->name + nameLength;
+ strcpy(argPtr->defValue, fieldValues[1]);
+ } else {
+ argPtr->defValue = NULL;
+ }
+ ckfree((char *) fieldValues);
+ }
+
+ Tcl_CreateCommand(interp, argv[1], InterpProc, (ClientData) procPtr,
+ ProcDeleteProc);
+ ckfree((char *) argArray);
+ return TCL_OK;
+
+ procError:
+ ckfree(procPtr->command);
+ while (procPtr->argPtr != NULL) {
+ argPtr = procPtr->argPtr;
+ procPtr->argPtr = argPtr->nextPtr;
+ ckfree((char *) argPtr);
+ }
+ ckfree((char *) procPtr);
+ if (argArray != NULL) {
+ ckfree((char *) argArray);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGetFrame --
+ *
+ * Given a description of a procedure frame, such as the first
+ * argument to an "uplevel" or "upvar" command, locate the
+ * call frame for the appropriate level of procedure.
+ *
+ * Results:
+ * The return value is -1 if an error occurred in finding the
+ * frame (in this case an error message is left in interp->result).
+ * 1 is returned if string was either a number or a number preceded
+ * by "#" and it specified a valid frame. 0 is returned if string
+ * isn't one of the two things above (in this case, the lookup
+ * acts as if string were "1"). The variable pointed to by
+ * framePtrPtr is filled in with the address of the desired frame
+ * (unless an error occurs, in which case it isn't modified).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclGetFrame(interp, string, framePtrPtr)
+ Tcl_Interp *interp; /* Interpreter in which to find frame. */
+ char *string; /* String describing frame. */
+ CallFrame **framePtrPtr; /* Store pointer to frame here (or NULL
+ * if global frame indicated). */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int curLevel, level, result;
+ CallFrame *framePtr;
+
+ /*
+ * Parse string to figure out which level number to go to.
+ */
+
+ result = 1;
+ curLevel = (iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level;
+ if (*string == '#') {
+ if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) {
+ return -1;
+ }
+ if (level < 0) {
+ levelError:
+ Tcl_AppendResult(interp, "bad level \"", string, "\"",
+ (char *) NULL);
+ return -1;
+ }
+ } else if (isdigit(UCHAR(*string))) {
+ if (Tcl_GetInt(interp, string, &level) != TCL_OK) {
+ return -1;
+ }
+ level = curLevel - level;
+ } else {
+ level = curLevel - 1;
+ result = 0;
+ }
+
+ /*
+ * Figure out which frame to use, and modify the interpreter so
+ * its variables come from that frame.
+ */
+
+ if (level == 0) {
+ framePtr = NULL;
+ } else {
+ for (framePtr = iPtr->varFramePtr; framePtr != NULL;
+ framePtr = framePtr->callerVarPtr) {
+ if (framePtr->level == level) {
+ break;
+ }
+ }
+ if (framePtr == NULL) {
+ goto levelError;
+ }
+ }
+ *framePtrPtr = framePtr;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UplevelCmd --
+ *
+ * This procedure is invoked to process the "uplevel" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_UplevelCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int result;
+ CallFrame *savedVarFramePtr, *framePtr;
+
+ if (argc < 2) {
+ uplevelSyntax:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?level? command ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Find the level to use for executing the command.
+ */
+
+ result = TclGetFrame(interp, argv[1], &framePtr);
+ if (result == -1) {
+ return TCL_ERROR;
+ }
+ argc -= (result+1);
+ if (argc == 0) {
+ goto uplevelSyntax;
+ }
+ argv += (result+1);
+
+ /*
+ * Modify the interpreter state to execute in the given frame.
+ */
+
+ savedVarFramePtr = iPtr->varFramePtr;
+ iPtr->varFramePtr = framePtr;
+
+ /*
+ * Execute the residual arguments as a command.
+ */
+
+ if (argc == 1) {
+ result = Tcl_Eval(interp, argv[0]);
+ } else {
+ char *cmd;
+
+ cmd = Tcl_Concat(argc, argv);
+ result = Tcl_Eval(interp, cmd);
+ ckfree(cmd);
+ }
+ if (result == TCL_ERROR) {
+ char msg[60];
+ sprintf(msg, "\n (\"uplevel\" body line %d)", interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+
+ /*
+ * Restore the variable frame, and return.
+ */
+
+ iPtr->varFramePtr = savedVarFramePtr;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclFindProc --
+ *
+ * Given the name of a procedure, return a pointer to the
+ * record describing the procedure.
+ *
+ * Results:
+ * NULL is returned if the name doesn't correspond to any
+ * procedure. Otherwise the return value is a pointer to
+ * the procedure's record.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Proc *
+TclFindProc(iPtr, procName)
+ Interp *iPtr; /* Interpreter in which to look. */
+ char *procName; /* Name of desired procedure. */
+{
+ Tcl_HashEntry *hPtr;
+ Command *cmdPtr;
+
+ hPtr = Tcl_FindHashEntry(&iPtr->commandTable, procName);
+ if (hPtr == NULL) {
+ return NULL;
+ }
+ cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
+ if (cmdPtr->proc != InterpProc) {
+ return NULL;
+ }
+ return (Proc *) cmdPtr->clientData;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclIsProc --
+ *
+ * Tells whether a command is a Tcl procedure or not.
+ *
+ * Results:
+ * If the given command is actuall a Tcl procedure, the
+ * return value is the address of the record describing
+ * the procedure. Otherwise the return value is 0.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Proc *
+TclIsProc(cmdPtr)
+ Command *cmdPtr; /* Command to test. */
+{
+ if (cmdPtr->proc == InterpProc) {
+ return (Proc *) cmdPtr->clientData;
+ }
+ return (Proc *) 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InterpProc --
+ *
+ * When a Tcl procedure gets invoked, this routine gets invoked
+ * to interpret the procedure.
+ *
+ * Results:
+ * A standard Tcl result value, usually TCL_OK.
+ *
+ * Side effects:
+ * Depends on the commands in the procedure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+InterpProc(clientData, interp, argc, argv)
+ ClientData clientData; /* Record describing procedure to be
+ * interpreted. */
+ Tcl_Interp *interp; /* Interpreter in which procedure was
+ * invoked. */
+ int argc; /* Count of number of arguments to this
+ * procedure. */
+ char **argv; /* Argument values. */
+{
+ register Proc *procPtr = (Proc *) clientData;
+ register Arg *argPtr;
+ register Interp *iPtr;
+ char **args;
+ CallFrame frame;
+ char *value;
+ int result;
+
+ /*
+ * Set up a call frame for the new procedure invocation.
+ */
+
+ iPtr = procPtr->iPtr;
+ Tcl_InitHashTable(&frame.varTable, TCL_STRING_KEYS);
+ if (iPtr->varFramePtr != NULL) {
+ frame.level = iPtr->varFramePtr->level + 1;
+ } else {
+ frame.level = 1;
+ }
+ frame.argc = argc;
+ frame.argv = argv;
+ frame.callerPtr = iPtr->framePtr;
+ frame.callerVarPtr = iPtr->varFramePtr;
+ iPtr->framePtr = &frame;
+ iPtr->varFramePtr = &frame;
+ iPtr->returnCode = TCL_OK;
+
+ /*
+ * Match the actual arguments against the procedure's formal
+ * parameters to compute local variables.
+ */
+
+ for (argPtr = procPtr->argPtr, args = argv+1, argc -= 1;
+ argPtr != NULL;
+ argPtr = argPtr->nextPtr, args++, argc--) {
+
+ /*
+ * Handle the special case of the last formal being "args". When
+ * it occurs, assign it a list consisting of all the remaining
+ * actual arguments.
+ */
+
+ if ((argPtr->nextPtr == NULL)
+ && (strcmp(argPtr->name, "args") == 0)) {
+ if (argc < 0) {
+ argc = 0;
+ }
+ value = Tcl_Merge(argc, args);
+ Tcl_SetVar(interp, argPtr->name, value, 0);
+ ckfree(value);
+ argc = 0;
+ break;
+ } else if (argc > 0) {
+ value = *args;
+ } else if (argPtr->defValue != NULL) {
+ value = argPtr->defValue;
+ } else {
+ Tcl_AppendResult(interp, "no value given for parameter \"",
+ argPtr->name, "\" to \"", argv[0], "\"",
+ (char *) NULL);
+ result = TCL_ERROR;
+ goto procDone;
+ }
+ Tcl_SetVar(interp, argPtr->name, value, 0);
+ }
+ if (argc > 0) {
+ Tcl_AppendResult(interp, "called \"", argv[0],
+ "\" with too many arguments", (char *) NULL);
+ result = TCL_ERROR;
+ goto procDone;
+ }
+
+ /*
+ * Invoke the commands in the procedure's body.
+ */
+
+ procPtr->refCount++;
+ result = Tcl_Eval(interp, procPtr->command);
+ procPtr->refCount--;
+ if (procPtr->refCount <= 0) {
+ CleanupProc(procPtr);
+ }
+ if (result == TCL_RETURN) {
+ result = iPtr->returnCode;
+ iPtr->returnCode = TCL_OK;
+ if (result == TCL_ERROR) {
+ Tcl_SetVar2(interp, "errorCode", (char *) NULL,
+ (iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE",
+ TCL_GLOBAL_ONLY);
+ iPtr->flags |= ERROR_CODE_SET;
+ if (iPtr->errorInfo != NULL) {
+ Tcl_SetVar2(interp, "errorInfo", (char *) NULL,
+ iPtr->errorInfo, TCL_GLOBAL_ONLY);
+ iPtr->flags |= ERR_IN_PROGRESS;
+ }
+ }
+ } else if (result == TCL_ERROR) {
+ char msg[100];
+
+ /*
+ * Record information telling where the error occurred.
+ */
+
+ sprintf(msg, "\n (procedure \"%.50s\" line %d)", argv[0],
+ iPtr->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ } else if (result == TCL_BREAK) {
+ iPtr->result = "invoked \"break\" outside of a loop";
+ result = TCL_ERROR;
+ } else if (result == TCL_CONTINUE) {
+ iPtr->result = "invoked \"continue\" outside of a loop";
+ result = TCL_ERROR;
+ }
+
+ /*
+ * Delete the call frame for this procedure invocation (it's
+ * important to remove the call frame from the interpreter
+ * before deleting it, so that traces invoked during the
+ * deletion don't see the partially-deleted frame).
+ */
+
+ procDone:
+ iPtr->framePtr = frame.callerPtr;
+ iPtr->varFramePtr = frame.callerVarPtr;
+ TclDeleteVars(iPtr, &frame.varTable);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ProcDeleteProc --
+ *
+ * This procedure is invoked just before a command procedure is
+ * removed from an interpreter. Its job is to release all the
+ * resources allocated to the procedure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory gets freed, unless the procedure is actively being
+ * executed. In this case the cleanup is delayed until the
+ * last call to the current procedure completes.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ProcDeleteProc(clientData)
+ ClientData clientData; /* Procedure to be deleted. */
+{
+ Proc *procPtr = (Proc *) clientData;
+
+ procPtr->refCount--;
+ if (procPtr->refCount <= 0) {
+ CleanupProc(procPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CleanupProc --
+ *
+ * This procedure does all the real work of freeing up a Proc
+ * structure. It's called only when the structure's reference
+ * count becomes zero.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory gets freed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+CleanupProc(procPtr)
+ register Proc *procPtr; /* Procedure to be deleted. */
+{
+ register Arg *argPtr;
+
+ ckfree((char *) procPtr->command);
+ for (argPtr = procPtr->argPtr; argPtr != NULL; ) {
+ Arg *nextPtr = argPtr->nextPtr;
+
+ ckfree((char *) argPtr);
+ argPtr = nextPtr;
+ }
+ ckfree((char *) procPtr);
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclRegexp.h b/vendor/x11iraf/obm/Tcl/tclRegexp.h
new file mode 100644
index 00000000..c3460006
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclRegexp.h
@@ -0,0 +1,30 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+
+#ifndef _TCL
+#include "tcl.h"
+#endif
+#ifndef _REGEXP
+#define _REGEXP 1
+
+#define NSUBEXP 10
+typedef struct regexp {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+extern regexp *TclRegComp _ANSI_ARGS_((char *exp));
+extern int TclRegExec _ANSI_ARGS_((regexp *prog, char *string, char *start));
+extern void TclRegSub _ANSI_ARGS_((regexp *prog, char *source, char *dest));
+extern void TclRegError _ANSI_ARGS_((char *msg));
+
+#endif /* REGEXP */
diff --git a/vendor/x11iraf/obm/Tcl/tclTest.c b/vendor/x11iraf/obm/Tcl/tclTest.c
new file mode 100644
index 00000000..c3b19f35
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclTest.c
@@ -0,0 +1,786 @@
+/*
+ * tclTest.c --
+ *
+ * This file contains C command procedures for a bunch of additional
+ * Tcl commands that are used for testing out Tcl's C interfaces.
+ * These commands are not normally included in Tcl applications;
+ * they're only used for testing.
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclTest.c,v 1.15 93/09/09 16:46:52 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ * The following variable is a special hack that allows applications
+ * to be linked using the procedure "main" from the Tcl library. The
+ * variable generates a reference to "main", which causes main to
+ * be brought in from the library (and all of Tcl with it).
+ */
+
+extern int main();
+int *tclDummyMainPtr = (int *) main;
+
+/*
+ * Dynamic string shared by TestdcallCmd and DelCallbackProc; used
+ * to collect the results of the various deletion callbacks.
+ */
+
+static Tcl_DString delString;
+static Tcl_Interp *delInterp;
+
+/*
+ * One of the following structures exists for each asynchronous
+ * handler created by the "testasync" command".
+ */
+
+typedef struct TestAsyncHandler {
+ int id; /* Identifier for this handler. */
+ Tcl_AsyncHandler handler; /* Tcl's token for the handler. */
+ char *command; /* Command to invoke when the
+ * handler is invoked. */
+ struct TestAsyncHandler *nextPtr; /* Next is list of handlers. */
+} TestAsyncHandler;
+
+static TestAsyncHandler *firstHandler = NULL;
+
+/*
+ * The variable below is a token for an asynchronous handler for
+ * interrupt signals, or NULL if none exists.
+ */
+
+static Tcl_AsyncHandler intHandler;
+
+/*
+ * The dynamic string below is used by the "testdstring" command
+ * to test the dynamic string facilities.
+ */
+
+static Tcl_DString dstring;
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+
+static int AsyncHandlerProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int code));
+static void CmdDelProc1 _ANSI_ARGS_((ClientData clientData));
+static void CmdDelProc2 _ANSI_ARGS_((ClientData clientData));
+static int CmdProc1 _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+static int CmdProc2 _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+static void DelCallbackProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp));
+static int IntHandlerProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int code));
+static void IntProc();
+static int TestasyncCmd _ANSI_ARGS_((ClientData dummy,
+ Tcl_Interp *interp, int argc, char **argv));
+static int TestcmdinfoCmd _ANSI_ARGS_((ClientData dummy,
+ Tcl_Interp *interp, int argc, char **argv));
+static int TestdcallCmd _ANSI_ARGS_((ClientData dummy,
+ Tcl_Interp *interp, int argc, char **argv));
+static int TestdstringCmd _ANSI_ARGS_((ClientData dummy,
+ Tcl_Interp *interp, int argc, char **argv));
+static int TestlinkCmd _ANSI_ARGS_((ClientData dummy,
+ Tcl_Interp *interp, int argc, char **argv));
+static int TestMathFunc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tcl_Value *args,
+ Tcl_Value *resultPtr));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppInit --
+ *
+ * This procedure performs application-specific initialization.
+ * Most applications, especially those that incorporate additional
+ * packages, will have their own version of this procedure.
+ *
+ * Results:
+ * Returns a standard Tcl completion code, and leaves an error
+ * message in interp->result if an error occurs.
+ *
+ * Side effects:
+ * Depends on the startup script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_AppInit(interp)
+ Tcl_Interp *interp; /* Interpreter for application. */
+{
+ /*
+ * Call the init procedures for included packages. Each call should
+ * look like this:
+ *
+ * if (Mod_Init(interp) == TCL_ERROR) {
+ * return TCL_ERROR;
+ * }
+ *
+ * where "Mod" is the name of the module.
+ */
+
+ if (Tcl_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Create additional commands and math functions for testing Tcl.
+ */
+
+ Tcl_CreateCommand(interp, "testasync", TestasyncCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateCommand(interp, "testcmdinfo", TestcmdinfoCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateCommand(interp, "testdcall", TestdcallCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+ Tcl_DStringInit(&dstring);
+ Tcl_CreateCommand(interp, "testdstring", TestdstringCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateCommand(interp, "testlink", TestlinkCmd, (ClientData) 0,
+ (Tcl_CmdDeleteProc *) NULL);
+ Tcl_CreateMathFunc(interp, "T1", 0, (Tcl_ValueType *) NULL, TestMathFunc,
+ (ClientData) 123);
+ Tcl_CreateMathFunc(interp, "T2", 0, (Tcl_ValueType *) NULL, TestMathFunc,
+ (ClientData) 345);
+
+ /*
+ * Specify a user-specific startup file to invoke if the application
+ * is run interactively. If this line is deleted then no user-specific
+ * startup file will be run under any conditions.
+ */
+
+ tcl_RcFileName = "~/.tclshrc";
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestasyncCmd --
+ *
+ * This procedure implements the "testasync" command. It is used
+ * to test the asynchronous handler facilities of Tcl.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Creates, deletes, and invokes handlers.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestasyncCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ TestAsyncHandler *asyncPtr, *prevPtr;
+ int id, code;
+ static int nextId = 1;
+
+ if (argc < 2) {
+ wrongNumArgs:
+ interp->result = "wrong # args";
+ return TCL_ERROR;
+ }
+ if (strcmp(argv[1], "create") == 0) {
+ if (argc != 3) {
+ goto wrongNumArgs;
+ }
+ asyncPtr = (TestAsyncHandler *) ckalloc(sizeof(TestAsyncHandler));
+ asyncPtr->id = nextId;
+ nextId++;
+ asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc,
+ (ClientData) asyncPtr);
+ asyncPtr->command = ckalloc((unsigned) (strlen(argv[2]) + 1));
+ strcpy(asyncPtr->command, argv[2]);
+ asyncPtr->nextPtr = firstHandler;
+ firstHandler = asyncPtr;
+ sprintf(interp->result, "%d", asyncPtr->id);
+ } else if (strcmp(argv[1], "delete") == 0) {
+ if (argc == 2) {
+ while (firstHandler != NULL) {
+ asyncPtr = firstHandler;
+ firstHandler = asyncPtr->nextPtr;
+ Tcl_AsyncDelete(asyncPtr->handler);
+ ckfree(asyncPtr->command);
+ ckfree((char *) asyncPtr);
+ }
+ return TCL_OK;
+ }
+ if (argc != 3) {
+ goto wrongNumArgs;
+ }
+ if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL;
+ prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) {
+ if (asyncPtr->id != id) {
+ continue;
+ }
+ if (prevPtr == NULL) {
+ firstHandler = asyncPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = asyncPtr->nextPtr;
+ }
+ Tcl_AsyncDelete(asyncPtr->handler);
+ ckfree(asyncPtr->command);
+ ckfree((char *) asyncPtr);
+ break;
+ }
+ } else if (strcmp(argv[1], "int") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ intHandler = Tcl_AsyncCreate(IntHandlerProc, (ClientData) interp);
+ signal(SIGINT, IntProc);
+ } else if (strcmp(argv[1], "mark") == 0) {
+ if (argc != 5) {
+ goto wrongNumArgs;
+ }
+ if ((Tcl_GetInt(interp, argv[2], &id) != TCL_OK)
+ || (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) {
+ return TCL_ERROR;
+ }
+ for (asyncPtr = firstHandler; asyncPtr != NULL;
+ asyncPtr = asyncPtr->nextPtr) {
+ if (asyncPtr->id == id) {
+ Tcl_AsyncMark(asyncPtr->handler);
+ break;
+ }
+ }
+ Tcl_SetResult(interp, argv[3], TCL_VOLATILE);
+ return code;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be create, delete, int, or mark",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+static int
+AsyncHandlerProc(clientData, interp, code)
+ ClientData clientData; /* Pointer to TestAsyncHandler structure. */
+ Tcl_Interp *interp; /* Interpreter in which command was
+ * executed, or NULL. */
+ int code; /* Current return code from command. */
+{
+ TestAsyncHandler *asyncPtr = (TestAsyncHandler *) clientData;
+ char *listArgv[4];
+ char string[20], *cmd;
+
+ sprintf(string, "%d", code);
+ listArgv[0] = asyncPtr->command;
+ listArgv[1] = interp->result;
+ listArgv[2] = string;
+ listArgv[3] = NULL;
+ cmd = Tcl_Merge(3, listArgv);
+ code = Tcl_Eval(interp, cmd);
+ ckfree(cmd);
+ return code;
+}
+
+static void
+IntProc()
+{
+ Tcl_AsyncMark(intHandler);
+}
+
+static int
+IntHandlerProc(clientData, interp, code)
+ ClientData clientData; /* Interpreter in which to invoke command. */
+ Tcl_Interp *interp; /* Interpreter in which command was
+ * executed, or NULL. */
+ int code; /* Current return code from command. */
+{
+ char *listArgv[4];
+ char string[20], *cmd;
+
+ interp = (Tcl_Interp *) clientData;
+ listArgv[0] = Tcl_GetVar(interp, "sigIntCmd", TCL_GLOBAL_ONLY);
+ if (listArgv[0] == NULL) {
+ return code;
+ }
+ listArgv[1] = interp->result;
+ sprintf(string, "%d", code);
+ listArgv[2] = string;
+ listArgv[3] = NULL;
+ cmd = Tcl_Merge(3, listArgv);
+ code = Tcl_Eval(interp, cmd);
+ ckfree(cmd);
+ return code;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestdcallCmd --
+ *
+ * This procedure implements the "testdcall" command. It is used
+ * to test Tcl_CallWhenDeleted.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Creates and deletes interpreters.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestdcallCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i, id;
+
+ delInterp = Tcl_CreateInterp();
+ Tcl_DStringInit(&delString);
+ for (i = 1; i < argc; i++) {
+ if (Tcl_GetInt(interp, argv[i], &id) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (id < 0) {
+ Tcl_DontCallWhenDeleted(delInterp, DelCallbackProc,
+ (ClientData) (-id));
+ } else {
+ Tcl_CallWhenDeleted(delInterp, DelCallbackProc,
+ (ClientData) id);
+ }
+ }
+ Tcl_DeleteInterp(delInterp);
+ Tcl_DStringResult(interp, &delString);
+ return TCL_OK;
+}
+
+/*
+ * The deletion callback used by TestdcallCmd:
+ */
+
+static void
+DelCallbackProc(clientData, interp)
+ ClientData clientData; /* Numerical value to append to
+ * delString. */
+ Tcl_Interp *interp; /* Interpreter being deleted. */
+{
+ int id = (int) clientData;
+ char buffer[10];
+
+ sprintf(buffer, "%d", id);
+ Tcl_DStringAppendElement(&delString, buffer);
+ if (interp != delInterp) {
+ Tcl_DStringAppendElement(&delString, "bogus interpreter argument!");
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestcmdinfoCmd --
+ *
+ * This procedure implements the "testcmdinfo" command. It is used
+ * to test Tcl_GetCmdInfo, Tcl_SetCmdInfo, and command creation
+ * and deletion.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Creates and deletes various commands and modifies their data.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestcmdinfoCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tcl_CmdInfo info;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option cmdName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (strcmp(argv[1], "create") == 0) {
+ Tcl_CreateCommand(interp, argv[2], CmdProc1, (ClientData) "original",
+ CmdDelProc1);
+ } else if (strcmp(argv[1], "delete") == 0) {
+ Tcl_DStringInit(&delString);
+ Tcl_DeleteCommand(interp, argv[2]);
+ Tcl_DStringResult(interp, &delString);
+ } else if (strcmp(argv[1], "get") == 0) {
+ if (Tcl_GetCommandInfo(interp, argv[2], &info) ==0) {
+ interp->result = "??";
+ return TCL_OK;
+ }
+ if (info.proc == CmdProc1) {
+ Tcl_AppendResult(interp, "CmdProc1", " ",
+ (char *) info.clientData, (char *) NULL);
+ } else if (info.proc == CmdProc2) {
+ Tcl_AppendResult(interp, "CmdProc2", " ",
+ (char *) info.clientData, (char *) NULL);
+ } else {
+ Tcl_AppendResult(interp, "unknown", (char *) NULL);
+ }
+ if (info.deleteProc == CmdDelProc1) {
+ Tcl_AppendResult(interp, " CmdDelProc1", " ",
+ (char *) info.deleteData, (char *) NULL);
+ } else if (info.deleteProc == CmdDelProc2) {
+ Tcl_AppendResult(interp, " CmdDelProc2", " ",
+ (char *) info.deleteData, (char *) NULL);
+ } else {
+ Tcl_AppendResult(interp, " unknown", (char *) NULL);
+ }
+ } else if (strcmp(argv[1], "modify") == 0) {
+ info.proc = CmdProc2;
+ info.clientData = (ClientData) "new_command_data";
+ info.deleteProc = CmdDelProc2;
+ info.deleteData = (ClientData) "new_delete_data";
+ if (Tcl_SetCommandInfo(interp, argv[2], &info) == 0) {
+ interp->result = "0";
+ } else {
+ interp->result = "1";
+ }
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be create, delete, get, or modify",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+ /*ARGSUSED*/
+static int
+CmdProc1(clientData, interp, argc, argv)
+ ClientData clientData; /* String to return. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tcl_AppendResult(interp, "CmdProc1 ", (char *) clientData,
+ (char *) NULL);
+ return TCL_OK;
+}
+
+ /*ARGSUSED*/
+static int
+CmdProc2(clientData, interp, argc, argv)
+ ClientData clientData; /* String to return. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tcl_AppendResult(interp, "CmdProc2 ", (char *) clientData,
+ (char *) NULL);
+ return TCL_OK;
+}
+
+static void
+CmdDelProc1(clientData)
+ ClientData clientData; /* String to save. */
+{
+ Tcl_DStringInit(&delString);
+ Tcl_DStringAppend(&delString, "CmdDelProc1 ", -1);
+ Tcl_DStringAppend(&delString, (char *) clientData, -1);
+}
+
+static void
+CmdDelProc2(clientData)
+ ClientData clientData; /* String to save. */
+{
+ Tcl_DStringInit(&delString);
+ Tcl_DStringAppend(&delString, "CmdDelProc2 ", -1);
+ Tcl_DStringAppend(&delString, (char *) clientData, -1);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestdstringCmd --
+ *
+ * This procedure implements the "testdstring" command. It is used
+ * to test the dynamic string facilities of Tcl.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Creates, deletes, and invokes handlers.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestdstringCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int count;
+
+ if (argc < 2) {
+ wrongNumArgs:
+ interp->result = "wrong # args";
+ return TCL_ERROR;
+ }
+ if (strcmp(argv[1], "append") == 0) {
+ if (argc != 4) {
+ goto wrongNumArgs;
+ }
+ if (Tcl_GetInt(interp, argv[3], &count) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ Tcl_DStringAppend(&dstring, argv[2], count);
+ } else if (strcmp(argv[1], "element") == 0) {
+ if (argc != 3) {
+ goto wrongNumArgs;
+ }
+ Tcl_DStringAppendElement(&dstring, argv[2]);
+ } else if (strcmp(argv[1], "end") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ Tcl_DStringEndSublist(&dstring);
+ } else if (strcmp(argv[1], "free") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ Tcl_DStringFree(&dstring);
+ } else if (strcmp(argv[1], "get") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ interp->result = Tcl_DStringValue(&dstring);
+ } else if (strcmp(argv[1], "length") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ sprintf(interp->result, "%d", Tcl_DStringLength(&dstring));
+ } else if (strcmp(argv[1], "result") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ Tcl_DStringResult(interp, &dstring);
+ } else if (strcmp(argv[1], "trunc") == 0) {
+ if (argc != 3) {
+ goto wrongNumArgs;
+ }
+ if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ Tcl_DStringTrunc(&dstring, count);
+ } else if (strcmp(argv[1], "start") == 0) {
+ if (argc != 2) {
+ goto wrongNumArgs;
+ }
+ Tcl_DStringStartSublist(&dstring);
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be append, element, end, free, get, length, ",
+ "result, trunc, or start", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestlinkCmd --
+ *
+ * This procedure implements the "testlink" command. It is used
+ * to test Tcl_LinkVar and related library procedures.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Creates and deletes various variable links, plus returns
+ * values of the linked variables.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestlinkCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ static int intVar = 43;
+ static int boolVar = 4;
+ static double realVar = 1.23;
+ static char *stringVar = NULL;
+ char buffer[TCL_DOUBLE_SPACE];
+ int writable, flag;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option ?arg arg arg?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (strcmp(argv[1], "create") == 0) {
+ if (Tcl_GetBoolean(interp, argv[2], &writable) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
+ if (Tcl_LinkVar(interp, "int", (char *) &intVar,
+ TCL_LINK_INT | flag) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetBoolean(interp, argv[3], &writable) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
+ if (Tcl_LinkVar(interp, "real", (char *) &realVar,
+ TCL_LINK_DOUBLE | flag) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetBoolean(interp, argv[4], &writable) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
+ if (Tcl_LinkVar(interp, "bool", (char *) &boolVar,
+ TCL_LINK_BOOLEAN | flag) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetBoolean(interp, argv[5], &writable) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY;
+ if (Tcl_LinkVar(interp, "string", (char *) &stringVar,
+ TCL_LINK_STRING | flag) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ } else if (strcmp(argv[1], "delete") == 0) {
+ Tcl_UnlinkVar(interp, "int");
+ Tcl_UnlinkVar(interp, "real");
+ Tcl_UnlinkVar(interp, "bool");
+ Tcl_UnlinkVar(interp, "string");
+ } else if (strcmp(argv[1], "get") == 0) {
+ sprintf(buffer, "%d", intVar);
+ Tcl_AppendElement(interp, buffer);
+ Tcl_PrintDouble(interp, realVar, buffer);
+ Tcl_AppendElement(interp, buffer);
+ sprintf(buffer, "%d", boolVar);
+ Tcl_AppendElement(interp, buffer);
+ Tcl_AppendElement(interp, (stringVar == NULL) ? "-" : stringVar);
+ } else if (strcmp(argv[1], "set") == 0) {
+ if (argc != 6) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " ", argv[1],
+ "intValue realValue boolValue stringValue\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argv[2][0] != 0) {
+ if (Tcl_GetInt(interp, argv[2], &intVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ if (argv[3][0] != 0) {
+ if (Tcl_GetDouble(interp, argv[3], &realVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ if (argv[4][0] != 0) {
+ if (Tcl_GetInt(interp, argv[4], &boolVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ if (argv[5][0] != 0) {
+ if (stringVar != NULL) {
+ ckfree(stringVar);
+ }
+ if (strcmp(argv[5], "-") == 0) {
+ stringVar = NULL;
+ } else {
+ stringVar = ckalloc((unsigned) (strlen(argv[5]) + 1));
+ strcpy(stringVar, argv[5]);
+ }
+ }
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be create, delete, get, or set",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TestMathFunc --
+ *
+ * This is a user-defined math procedure to test out math procedures
+ * with no arguments.
+ *
+ * Results:
+ * A normal Tcl completion code.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static int
+TestMathFunc(clientData, interp, args, resultPtr)
+ ClientData clientData; /* Integer value to return. */
+ Tcl_Interp *interp; /* Not used. */
+ Tcl_Value *args; /* Not used. */
+ Tcl_Value *resultPtr; /* Where to store result. */
+{
+ resultPtr->type = TCL_INT;
+ resultPtr->intValue = (int) clientData;
+ return TCL_OK;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclUnix.h b/vendor/x11iraf/obm/Tcl/tclUnix.h
new file mode 100644
index 00000000..343b0253
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUnix.h
@@ -0,0 +1,285 @@
+/*
+ * tclUnix.h --
+ *
+ * This file reads in UNIX-related header files and sets up
+ * UNIX-related macros for Tcl's UNIX core. It should be the
+ * only file that contains #ifdefs to handle different flavors
+ * of UNIX. This file sets up the union of all UNIX-related
+ * things needed by any of the Tcl core files. This file
+ * depends on configuration #defines in tclConfig.h
+ *
+ * Much of the material in this file was originally contributed
+ * by Karl Lehenbauer, Mark Diekhans and Peter da Silva.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * $Header: /user6/ouster/tcl/RCS/tclUnix.h,v 1.46 93/10/28 16:32:28 ouster Exp $ SPRITE (Berkeley)
+ */
+
+#ifndef _TCLUNIX
+#define _TCLUNIX
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#ifdef USE_DIRENT2_H
+# include "compat/dirent2.h"
+#else
+# ifdef NO_DIRENT_H
+# include "compat/dirent.h"
+# else
+# include <dirent.h>
+# endif
+#endif
+#include <sys/file.h>
+#include <sys/stat.h>
+#ifndef NO_SYS_TIME_H
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+#ifndef NO_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#else
+# include "compat/unistd.h"
+#endif
+
+/*
+ * Not all systems declare the errno variable in errno.h. so this
+ * file does it explicitly. The list of system error messages also
+ * isn't generally declared in a header file anywhere.
+ */
+
+extern int errno;
+
+/*
+ * The type of the status returned by wait varies from UNIX system
+ * to UNIX system. The macro below defines it:
+ */
+
+#ifdef AIX
+# define WAIT_STATUS_TYPE pid_t
+#else
+#ifndef NO_UNION_WAIT
+# define WAIT_STATUS_TYPE union wait
+#else
+# define WAIT_STATUS_TYPE int
+#endif
+#endif
+
+/*
+ * Supply definitions for macros to query wait status, if not already
+ * defined in header files above.
+ */
+
+#ifndef WIFEXITED
+# define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0)
+#endif
+
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
+#endif
+
+#ifndef WIFSIGNALED
+# define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff)))
+#endif
+
+#ifndef WTERMSIG
+# define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f)
+#endif
+
+#ifndef WIFSTOPPED
+# define WIFSTOPPED(stat) (((*((int *) &(stat))) & 0xff) == 0177)
+#endif
+
+#ifndef WSTOPSIG
+# define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff)
+#endif
+
+/*
+ * Supply macros for seek offsets, if they're not already provided by
+ * an include file.
+ */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+/*
+ * The stuff below is needed by the "time" command. If this
+ * system has no gettimeofday call, then must use times and the
+ * CLK_TCK #define (from sys/param.h) to compute elapsed time.
+ * Unfortunately, some systems only have HZ and no CLK_TCK, and
+ * some might not even have HZ.
+ */
+
+#ifdef NO_GETTOD
+# include <sys/times.h>
+# include <sys/param.h>
+# ifndef CLK_TCK
+# ifdef HZ
+# define CLK_TCK HZ
+# else
+# define CLK_TCK 60
+# endif
+# endif
+#endif
+
+/*
+ * Define access mode constants if they aren't already defined.
+ */
+
+#ifndef F_OK
+# define F_OK 00
+#endif
+#ifndef X_OK
+# define X_OK 01
+#endif
+#ifndef W_OK
+# define W_OK 02
+#endif
+#ifndef R_OK
+# define R_OK 04
+#endif
+
+/*
+ * On systems without symbolic links (i.e. S_IFLNK isn't defined)
+ * define "lstat" to use "stat" instead.
+ */
+
+#ifndef S_IFLNK
+# define lstat stat
+#endif
+
+/*
+ * Define macros to query file type bits, if they're not already
+ * defined.
+ */
+
+#ifndef S_ISREG
+# ifdef S_IFREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+# define S_ISREG(m) 0
+# endif
+# endif
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) 0
+# endif
+# endif
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) 0
+# endif
+# endif
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) 0
+# endif
+# endif
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+# endif
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) 0
+# endif
+# endif
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) 0
+# endif
+# endif
+
+/*
+ * Make sure that MAXPATHLEN is defined.
+ */
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN 2048
+# endif
+#endif
+
+/*
+ * Make sure that L_tmpnam is defined.
+ */
+
+#ifndef L_tmpnam
+# define L_tmpnam 100
+#endif
+
+/*
+ * Substitute Tcl's own versions for several system calls. The
+ * Tcl versions retry automatically if interrupted by signals.
+ * (see tclUnixUtil.c).
+ */
+
+#define open(a,b,c) TclOpen(a,b,c)
+#define read(a,b,c) TclRead(a,b,c)
+#define waitpid(a,b,c) TclWaitpid(a,b,c)
+#define write(a,b,c) TclWrite(a,b,c)
+EXTERN int TclOpen _ANSI_ARGS_((char *path, int oflag, int mode));
+EXTERN int TclRead _ANSI_ARGS_((int fd, VOID *buf, size_t numBytes));
+EXTERN int TclWaitpid _ANSI_ARGS_((pid_t pid, int *statPtr, int options));
+EXTERN int TclWrite _ANSI_ARGS_((int fd, VOID *buf, size_t numBytes));
+
+/*
+ * Variables provided by the C library:
+ */
+
+#if defined(_sgi) || defined(__sgi)
+#define environ _environ
+#endif
+extern char **environ;
+
+#endif /* _TCLUNIX */
diff --git a/vendor/x11iraf/obm/Tcl/tclUnixAZ.c b/vendor/x11iraf/obm/Tcl/tclUnixAZ.c
new file mode 100644
index 00000000..765b7f03
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUnixAZ.c
@@ -0,0 +1,1998 @@
+/*
+ * tclUnixAZ.c --
+ *
+ * This file contains the top-level command procedures for
+ * commands in the Tcl core that require UNIX facilities
+ * such as files and process execution. Much of the code
+ * in this file is based on earlier versions contributed
+ * by Karl Lehenbauer, Mark Diekhans and Peter da Silva.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUnixAZ.c,v 1.70 93/09/24 16:47:39 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ * The variable below caches the name of the current working directory
+ * in order to avoid repeated calls to getcwd. The string is malloc-ed.
+ * NULL means the cache needs to be refreshed.
+ */
+
+static char *currentDir = NULL;
+
+/*
+ * If the system doesn't define the EWOULDBLOCK errno, just #define it
+ * to a bogus value that will never occur.
+ */
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK -1901
+#endif
+
+/*
+ * Prototypes for local procedures defined in this file:
+ */
+
+static int CleanupChildren _ANSI_ARGS_((Tcl_Interp *interp,
+ int numPids, int *pidPtr, int errorId,
+ int keepNewline));
+static char * GetFileType _ANSI_ARGS_((int mode));
+static char * GetOpenMode _ANSI_ARGS_((Tcl_Interp *interp,
+ char *string, int *modePtr));
+static int StoreStatData _ANSI_ARGS_((Tcl_Interp *interp,
+ char *varName, struct stat *statPtr));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CdCmd --
+ *
+ * This procedure is invoked to process the "cd" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_CdCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *dirName;
+ Tcl_DString buffer;
+ int result;
+
+ if (argc > 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " dirName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (argc == 2) {
+ dirName = argv[1];
+ } else {
+ dirName = "~";
+ }
+ dirName = Tcl_TildeSubst(interp, dirName, &buffer);
+ if (dirName == NULL) {
+ return TCL_ERROR;
+ }
+ if (currentDir != NULL) {
+ ckfree(currentDir);
+ currentDir = NULL;
+ }
+ result = TCL_OK;
+ if (chdir(dirName) != 0) {
+ Tcl_AppendResult(interp, "couldn't change working directory to \"",
+ dirName, "\": ", Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ }
+ Tcl_DStringFree(&buffer);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CloseCmd --
+ *
+ * This procedure is invoked to process the "close" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_CloseCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ OpenFile *oFilePtr;
+ int result = TCL_OK;
+ FILE *f;
+
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ oFilePtr = tclOpenFiles[fileno(f)];
+ tclOpenFiles[fileno(f)] = NULL;
+
+ /*
+ * First close the file (in the case of a process pipeline, there may
+ * be two files, one for the pipe at each end of the pipeline).
+ */
+
+ if (oFilePtr->f2 != NULL) {
+ clearerr(oFilePtr->f2);
+ if (fclose(oFilePtr->f2) == EOF) {
+ Tcl_AppendResult(interp, "error closing \"", argv[1],
+ "\": ", Tcl_PosixError(interp), "\n", (char *) NULL);
+ result = TCL_ERROR;
+ }
+ }
+ clearerr(oFilePtr->f);
+ if (fclose(oFilePtr->f) == EOF) {
+ Tcl_AppendResult(interp, "error closing \"", argv[1],
+ "\": ", Tcl_PosixError(interp), "\n", (char *) NULL);
+ result = TCL_ERROR;
+ }
+
+ /*
+ * If the file was a connection to a pipeline, clean up everything
+ * associated with the child processes.
+ */
+
+ if (oFilePtr->numPids > 0) {
+ if (CleanupChildren(interp, oFilePtr->numPids, oFilePtr->pidPtr,
+ oFilePtr->errorId, 0) != TCL_OK) {
+ result = TCL_ERROR;
+ }
+ }
+
+ ckfree((char *) oFilePtr);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_EofCmd --
+ *
+ * This procedure is invoked to process the "eof" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_EofCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (feof(f)) {
+ interp->result = "1";
+ } else {
+ interp->result = "0";
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ExecCmd --
+ *
+ * This procedure is invoked to process the "exec" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ExecCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int outputId; /* File id for output pipe. -1
+ * means command overrode. */
+ int errorId; /* File id for temporary file
+ * containing error output. */
+ int *pidPtr;
+ int numPids, result, keepNewline;
+ int firstWord;
+
+ /*
+ * Check for a leading "-keepnewline" argument.
+ */
+
+ keepNewline = 0;
+ for (firstWord = 1; (firstWord < argc) && (argv[firstWord][0] == '-');
+ firstWord++) {
+ if (strcmp(argv[firstWord], "-keepnewline") == 0) {
+ keepNewline = 1;
+ } else if (strcmp(argv[firstWord], "--") == 0) {
+ firstWord++;
+ break;
+ } else {
+ Tcl_AppendResult(interp, "bad switch \"", argv[firstWord],
+ "\": must be -keepnewline or --", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+
+ if (argc <= firstWord) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?switches? arg ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * See if the command is to be run in background; if so, create
+ * the command, detach it, and return a list of pids.
+ */
+
+ if ((argv[argc-1][0] == '&') && (argv[argc-1][1] == 0)) {
+ int i;
+ char id[50];
+
+ argc--;
+ argv[argc] = NULL;
+ numPids = Tcl_CreatePipeline(interp, argc-firstWord, argv+firstWord,
+ &pidPtr, (int *) NULL, (int *) NULL, (int *) NULL);
+ if (numPids < 0) {
+ return TCL_ERROR;
+ }
+ Tcl_DetachPids(numPids, pidPtr);
+ for (i = 0; i < numPids; i++) {
+ sprintf(id, "%d", pidPtr[i]);
+ Tcl_AppendElement(interp, id);
+ }
+ ckfree((char *) pidPtr);
+ return TCL_OK;
+ }
+
+ /*
+ * Create the command's pipeline.
+ */
+
+ numPids = Tcl_CreatePipeline(interp, argc-firstWord, argv+firstWord,
+ &pidPtr, (int *) NULL, &outputId, &errorId);
+ if (numPids < 0) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Read the child's output (if any) and put it into the result.
+ */
+
+ result = TCL_OK;
+ if (outputId != -1) {
+ while (1) {
+# define BUFFER_SIZE 1000
+ char buffer[BUFFER_SIZE+1];
+ int count;
+
+ count = read(outputId, buffer, (size_t) BUFFER_SIZE);
+
+ if (count == 0) {
+ break;
+ }
+ if (count < 0) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp,
+ "error reading from output pipe: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ buffer[count] = 0;
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ }
+ close(outputId);
+ }
+
+ if (CleanupChildren(interp, numPids, pidPtr, errorId, keepNewline)
+ != TCL_OK) {
+ result = TCL_ERROR;
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ExitCmd --
+ *
+ * This procedure is invoked to process the "exit" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ExitCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int value;
+
+ if ((argc != 1) && (argc != 2)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?returnCode?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 1) {
+ exit(0);
+ }
+ if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ exit(value);
+ /*NOTREACHED*/
+ return TCL_OK; /* Better not ever reach this! */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FileCmd --
+ *
+ * This procedure is invoked to process the "file" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_FileCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char *p;
+ int length, statOp, result;
+ int mode = 0; /* Initialized only to prevent
+ * compiler warning message. */
+ struct stat statBuf;
+ char *fileName, c;
+ Tcl_DString buffer;
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option name ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ result = TCL_OK;
+
+ /*
+ * First handle operations on the file name.
+ */
+
+ fileName = Tcl_TildeSubst(interp, argv[2], &buffer);
+ if (fileName == NULL) {
+ result = TCL_ERROR;
+ goto done;
+ }
+ if ((c == 'd') && (strncmp(argv[1], "dirname", length) == 0)) {
+ if (argc != 3) {
+ argv[1] = "dirname";
+ not3Args:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ", argv[1], " name\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ p = strrchr(fileName, '/');
+ if (p == NULL) {
+ interp->result = ".";
+ } else if (p == fileName) {
+ interp->result = "/";
+ } else {
+ *p = 0;
+ Tcl_SetResult(interp, fileName, TCL_VOLATILE);
+ *p = '/';
+ }
+ goto done;
+ } else if ((c == 'r') && (strncmp(argv[1], "rootname", length) == 0)
+ && (length >= 2)) {
+ char *lastSlash;
+
+ if (argc != 3) {
+ argv[1] = "rootname";
+ goto not3Args;
+ }
+ p = strrchr(fileName, '.');
+ lastSlash = strrchr(fileName, '/');
+ if ((p == NULL) || ((lastSlash != NULL) && (lastSlash > p))) {
+ Tcl_SetResult(interp, fileName, TCL_VOLATILE);
+ } else {
+ *p = 0;
+ Tcl_SetResult(interp, fileName, TCL_VOLATILE);
+ *p = '.';
+ }
+ goto done;
+ } else if ((c == 'e') && (strncmp(argv[1], "extension", length) == 0)
+ && (length >= 3)) {
+ char *lastSlash;
+
+ if (argc != 3) {
+ argv[1] = "extension";
+ goto not3Args;
+ }
+ p = strrchr(fileName, '.');
+ lastSlash = strrchr(fileName, '/');
+ if ((p != NULL) && ((lastSlash == NULL) || (lastSlash < p))) {
+ Tcl_SetResult(interp, p, TCL_VOLATILE);
+ }
+ goto done;
+ } else if ((c == 't') && (strncmp(argv[1], "tail", length) == 0)
+ && (length >= 2)) {
+ if (argc != 3) {
+ argv[1] = "tail";
+ goto not3Args;
+ }
+ p = strrchr(fileName, '/');
+ if (p != NULL) {
+ Tcl_SetResult(interp, p+1, TCL_VOLATILE);
+ } else {
+ Tcl_SetResult(interp, fileName, TCL_VOLATILE);
+ }
+ goto done;
+ }
+
+ /*
+ * Next, handle operations that can be satisfied with the "access"
+ * kernel call.
+ */
+
+ if (fileName == NULL) {
+ result = TCL_ERROR;
+ goto done;
+ }
+ if ((c == 'r') && (strncmp(argv[1], "readable", length) == 0)
+ && (length >= 5)) {
+ if (argc != 3) {
+ argv[1] = "readable";
+ goto not3Args;
+ }
+ mode = R_OK;
+ checkAccess:
+ if (access(fileName, mode) == -1) {
+ interp->result = "0";
+ } else {
+ interp->result = "1";
+ }
+ goto done;
+ } else if ((c == 'w') && (strncmp(argv[1], "writable", length) == 0)) {
+ if (argc != 3) {
+ argv[1] = "writable";
+ goto not3Args;
+ }
+ mode = W_OK;
+ goto checkAccess;
+ } else if ((c == 'e') && (strncmp(argv[1], "executable", length) == 0)
+ && (length >= 3)) {
+ if (argc != 3) {
+ argv[1] = "executable";
+ goto not3Args;
+ }
+ mode = X_OK;
+ goto checkAccess;
+ } else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0)
+ && (length >= 3)) {
+ if (argc != 3) {
+ argv[1] = "exists";
+ goto not3Args;
+ }
+ mode = F_OK;
+ goto checkAccess;
+ }
+
+ /*
+ * Lastly, check stuff that requires the file to be stat-ed.
+ */
+
+ if ((c == 'a') && (strncmp(argv[1], "atime", length) == 0)) {
+ if (argc != 3) {
+ argv[1] = "atime";
+ goto not3Args;
+ }
+ if (stat(fileName, &statBuf) == -1) {
+ goto badStat;
+ }
+ sprintf(interp->result, "%ld", statBuf.st_atime);
+ goto done;
+ } else if ((c == 'i') && (strncmp(argv[1], "isdirectory", length) == 0)
+ && (length >= 3)) {
+ if (argc != 3) {
+ argv[1] = "isdirectory";
+ goto not3Args;
+ }
+ statOp = 2;
+ } else if ((c == 'i') && (strncmp(argv[1], "isfile", length) == 0)
+ && (length >= 3)) {
+ if (argc != 3) {
+ argv[1] = "isfile";
+ goto not3Args;
+ }
+ statOp = 1;
+ } else if ((c == 'l') && (strncmp(argv[1], "lstat", length) == 0)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " lstat name varName\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ if (lstat(fileName, &statBuf) == -1) {
+ Tcl_AppendResult(interp, "couldn't lstat \"", argv[2],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ result = StoreStatData(interp, argv[3], &statBuf);
+ goto done;
+ } else if ((c == 'm') && (strncmp(argv[1], "mtime", length) == 0)) {
+ if (argc != 3) {
+ argv[1] = "mtime";
+ goto not3Args;
+ }
+ if (stat(fileName, &statBuf) == -1) {
+ goto badStat;
+ }
+ sprintf(interp->result, "%ld", statBuf.st_mtime);
+ goto done;
+ } else if ((c == 'o') && (strncmp(argv[1], "owned", length) == 0)) {
+ if (argc != 3) {
+ argv[1] = "owned";
+ goto not3Args;
+ }
+ statOp = 0;
+ } else if ((c == 'r') && (strncmp(argv[1], "readlink", length) == 0)
+ && (length >= 5)) {
+ char linkValue[MAXPATHLEN+1];
+ int linkLength;
+
+ if (argc != 3) {
+ argv[1] = "readlink";
+ goto not3Args;
+ }
+
+ /*
+ * If S_IFLNK isn't defined it means that the machine doesn't
+ * support symbolic links, so the file can't possibly be a
+ * symbolic link. Generate an EINVAL error, which is what
+ * happens on machines that do support symbolic links when
+ * you invoke readlink on a file that isn't a symbolic link.
+ */
+
+#ifndef S_IFLNK
+ linkLength = -1;
+ errno = EINVAL;
+#else
+ linkLength = readlink(fileName, linkValue, sizeof(linkValue) - 1);
+#endif /* S_IFLNK */
+ if (linkLength == -1) {
+ Tcl_AppendResult(interp, "couldn't readlink \"", argv[2],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ linkValue[linkLength] = 0;
+ Tcl_SetResult(interp, linkValue, TCL_VOLATILE);
+ goto done;
+ } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)
+ && (length >= 2)) {
+ if (argc != 3) {
+ argv[1] = "size";
+ goto not3Args;
+ }
+ if (stat(fileName, &statBuf) == -1) {
+ goto badStat;
+ }
+ sprintf(interp->result, "%ld", statBuf.st_size);
+ goto done;
+ } else if ((c == 's') && (strncmp(argv[1], "stat", length) == 0)
+ && (length >= 2)) {
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " stat name varName\"", (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ if (stat(fileName, &statBuf) == -1) {
+ badStat:
+ Tcl_AppendResult(interp, "couldn't stat \"", argv[2],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ result = StoreStatData(interp, argv[3], &statBuf);
+ goto done;
+ } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)
+ && (length >= 2)) {
+ if (argc != 3) {
+ argv[1] = "type";
+ goto not3Args;
+ }
+ if (lstat(fileName, &statBuf) == -1) {
+ goto badStat;
+ }
+ interp->result = GetFileType((int) statBuf.st_mode);
+ goto done;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be atime, dirname, executable, exists, ",
+ "extension, isdirectory, isfile, lstat, mtime, owned, ",
+ "readable, readlink, ",
+ "root, size, stat, tail, type, ",
+ "or writable",
+ (char *) NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ if (stat(fileName, &statBuf) == -1) {
+ interp->result = "0";
+ goto done;
+ }
+ switch (statOp) {
+ case 0:
+ mode = (geteuid() == statBuf.st_uid);
+ break;
+ case 1:
+ mode = S_ISREG(statBuf.st_mode);
+ break;
+ case 2:
+ mode = S_ISDIR(statBuf.st_mode);
+ break;
+ }
+ if (mode) {
+ interp->result = "1";
+ } else {
+ interp->result = "0";
+ }
+
+ done:
+ Tcl_DStringFree(&buffer);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StoreStatData --
+ *
+ * This is a utility procedure that breaks out the fields of a
+ * "stat" structure and stores them in textual form into the
+ * elements of an associative array.
+ *
+ * Results:
+ * Returns a standard Tcl return value. If an error occurs then
+ * a message is left in interp->result.
+ *
+ * Side effects:
+ * Elements of the associative array given by "varName" are modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+StoreStatData(interp, varName, statPtr)
+ Tcl_Interp *interp; /* Interpreter for error reports. */
+ char *varName; /* Name of associative array variable
+ * in which to store stat results. */
+ struct stat *statPtr; /* Pointer to buffer containing
+ * stat data to store in varName. */
+{
+ char string[30];
+
+ sprintf(string, "%d", statPtr->st_dev);
+ if (Tcl_SetVar2(interp, varName, "dev", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%d", statPtr->st_ino);
+ if (Tcl_SetVar2(interp, varName, "ino", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%d", statPtr->st_mode);
+ if (Tcl_SetVar2(interp, varName, "mode", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%d", statPtr->st_nlink);
+ if (Tcl_SetVar2(interp, varName, "nlink", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%d", statPtr->st_uid);
+ if (Tcl_SetVar2(interp, varName, "uid", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%d", statPtr->st_gid);
+ if (Tcl_SetVar2(interp, varName, "gid", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%ld", statPtr->st_size);
+ if (Tcl_SetVar2(interp, varName, "size", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%ld", statPtr->st_atime);
+ if (Tcl_SetVar2(interp, varName, "atime", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%ld", statPtr->st_mtime);
+ if (Tcl_SetVar2(interp, varName, "mtime", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ sprintf(string, "%ld", statPtr->st_ctime);
+ if (Tcl_SetVar2(interp, varName, "ctime", string, TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_SetVar2(interp, varName, "type",
+ GetFileType((int) statPtr->st_mode), TCL_LEAVE_ERR_MSG) == NULL) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetFileType --
+ *
+ * Given a mode word, returns a string identifying the type of a
+ * file.
+ *
+ * Results:
+ * A static text string giving the file type from mode.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+GetFileType(mode)
+ int mode;
+{
+ if (S_ISREG(mode)) {
+ return "file";
+ } else if (S_ISDIR(mode)) {
+ return "directory";
+ } else if (S_ISCHR(mode)) {
+ return "characterSpecial";
+ } else if (S_ISBLK(mode)) {
+ return "blockSpecial";
+ } else if (S_ISFIFO(mode)) {
+ return "fifo";
+ } else if (S_ISLNK(mode)) {
+ return "link";
+ } else if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+ return "unknown";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FlushCmd --
+ *
+ * This procedure is invoked to process the "flush" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_FlushCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 1, 1, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ clearerr(f);
+ if (fflush(f) == EOF) {
+ Tcl_AppendResult(interp, "error flushing \"", argv[1],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetsCmd --
+ *
+ * This procedure is invoked to process the "gets" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_GetsCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+# define BUF_SIZE 200
+ char buffer[BUF_SIZE+1];
+ int totalCount, done, flags;
+ FILE *f;
+
+ if ((argc != 2) && (argc != 3)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId ?varName?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 1, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * We can't predict how large a line will be, so read it in
+ * pieces, appending to the current result or to a variable.
+ */
+
+ totalCount = 0;
+ done = 0;
+ flags = 0;
+ clearerr(f);
+ while (!done) {
+ register int c, count;
+ register char *p;
+
+ for (p = buffer, count = 0; count < BUF_SIZE-1; count++, p++) {
+ c = getc(f);
+ if (c == EOF) {
+ if (ferror(f)) {
+ /*
+ * If the file is in non-blocking mode, return any
+ * bytes that were read before a block would occur.
+ */
+
+ if ((errno == EWOULDBLOCK)
+ && ((count > 0 || totalCount > 0))) {
+ done = 1;
+ break;
+ }
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "error reading \"", argv[1],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ } else if (feof(f)) {
+ if ((totalCount == 0) && (count == 0)) {
+ totalCount = -1;
+ }
+ done = 1;
+ break;
+ }
+ }
+ if (c == '\n') {
+ done = 1;
+ break;
+ }
+ *p = c;
+ }
+ *p = 0;
+ if (argc == 2) {
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ } else {
+ if (Tcl_SetVar(interp, argv[2], buffer, flags|TCL_LEAVE_ERR_MSG)
+ == NULL) {
+ return TCL_ERROR;
+ }
+ flags = TCL_APPEND_VALUE;
+ }
+ totalCount += count;
+ }
+
+ if (argc == 3) {
+ sprintf(interp->result, "%d", totalCount);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_OpenCmd --
+ *
+ * This procedure is invoked to process the "open" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_OpenCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int pipeline, fd, mode, prot, readWrite, permissions;
+ char *access;
+ FILE *f, *f2;
+
+ if ((argc < 2) || (argc > 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " filename ?access? ?permissions?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ prot = 0666;
+ if (argc == 2) {
+ mode = O_RDONLY;
+ access = "r";
+ } else {
+ access = GetOpenMode(interp, argv[2], &mode);
+ if (access == NULL) {
+ return TCL_ERROR;
+ }
+ if (argc == 4) {
+ if (Tcl_GetInt(interp, argv[3], &prot) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ }
+
+ f = f2 = NULL;
+ readWrite = mode & (O_RDWR|O_RDONLY|O_WRONLY);
+ if (readWrite == O_RDONLY) {
+ permissions = TCL_FILE_READABLE;
+ } else if (readWrite == O_WRONLY) {
+ permissions = TCL_FILE_WRITABLE;
+ } else {
+ permissions = TCL_FILE_READABLE|TCL_FILE_WRITABLE;
+ }
+
+ pipeline = 0;
+ if (argv[1][0] == '|') {
+ pipeline = 1;
+ }
+
+ /*
+ * Open the file or create a process pipeline.
+ */
+
+ if (!pipeline) {
+ char *fileName;
+ Tcl_DString buffer;
+
+ fileName = Tcl_TildeSubst(interp, argv[1], &buffer);
+ if (fileName == NULL) {
+ return TCL_ERROR;
+ }
+ fd = open(fileName, mode, prot);
+ Tcl_DStringFree(&buffer);
+ if (fd < 0) {
+ Tcl_AppendResult(interp, "couldn't open \"", argv[1],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ }
+ f = fdopen(fd, access);
+ if (f == NULL) {
+ close(fd);
+ return TCL_ERROR;
+ }
+ Tcl_EnterFile(interp, f, permissions);
+ } else {
+ int *inPipePtr, *outPipePtr;
+ int cmdArgc, inPipe, outPipe, numPids, *pidPtr, errorId;
+ char **cmdArgv;
+ OpenFile *oFilePtr;
+
+ if (Tcl_SplitList(interp, argv[1]+1, &cmdArgc, &cmdArgv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ inPipePtr = (permissions & TCL_FILE_WRITABLE) ? &inPipe : NULL;
+ outPipePtr = (permissions & TCL_FILE_READABLE) ? &outPipe : NULL;
+ inPipe = outPipe = errorId = -1;
+ numPids = Tcl_CreatePipeline(interp, cmdArgc, cmdArgv,
+ &pidPtr, inPipePtr, outPipePtr, &errorId);
+ ckfree((char *) cmdArgv);
+ if (numPids < 0) {
+ pipelineError:
+ if (f != NULL) {
+ fclose(f);
+ }
+ if (f2 != NULL) {
+ fclose(f2);
+ }
+ if (numPids > 0) {
+ Tcl_DetachPids(numPids, pidPtr);
+ ckfree((char *) pidPtr);
+ }
+ if (errorId != -1) {
+ close(errorId);
+ }
+ return TCL_ERROR;
+ }
+ if (permissions & TCL_FILE_READABLE) {
+ if (outPipe == -1) {
+ if (inPipe != -1) {
+ close(inPipe);
+ }
+ Tcl_AppendResult(interp, "can't read output from command:",
+ " standard output was redirected", (char *) NULL);
+ goto pipelineError;
+ }
+ f = fdopen(outPipe, "r");
+ }
+ if (permissions & TCL_FILE_WRITABLE) {
+ if (inPipe == -1) {
+ Tcl_AppendResult(interp, "can't write input to command:",
+ " standard input was redirected", (char *) NULL);
+ goto pipelineError;
+ }
+ if (f != NULL) {
+ f2 = fdopen(inPipe, "w");
+ } else {
+ f = fdopen(inPipe, "w");
+ }
+ }
+ Tcl_EnterFile(interp, f, permissions);
+ oFilePtr = tclOpenFiles[fileno(f)];
+ oFilePtr->f2 = f2;
+ oFilePtr->numPids = numPids;
+ oFilePtr->pidPtr = pidPtr;
+ oFilePtr->errorId = errorId;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetOpenMode --
+ *
+ * description.
+ *
+ * Results:
+ * Normally, sets *modePtr to an access mode for passing to "open",
+ * and returns a string that can be used as the access mode in a
+ * subsequent call to "fdopen". If an error occurs, then returns
+ * NULL and sets interp->result to an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ * Special note:
+ * This code is based on a prototype implementation contributed
+ * by Mark Diekhans.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+GetOpenMode(interp, string, modePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error
+ * reporting. */
+ char *string; /* Mode string, e.g. "r+" or
+ * "RDONLY CREAT". */
+ int *modePtr; /* Where to store mode corresponding
+ * to string. */
+{
+ int mode, modeArgc, c, i, gotRW;
+ char **modeArgv, *flag;
+#define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR)
+
+ /*
+ * Check for the simpler fopen-like access modes (e.g. "r"). They
+ * are distinguished from the POSIX access modes by the presence
+ * of a lower-case first letter.
+ */
+
+ mode = 0;
+ if (islower(UCHAR(string[0]))) {
+ switch (string[0]) {
+ case 'r':
+ mode = O_RDONLY;
+ break;
+ case 'w':
+ mode = O_WRONLY|O_CREAT|O_TRUNC;
+ break;
+ case 'a':
+ mode = O_WRONLY|O_CREAT|O_APPEND;
+ break;
+ default:
+ error:
+ Tcl_AppendResult(interp,
+ "illegal access mode \"", string, "\"", (char *) NULL);
+ return NULL;
+ }
+ if (string[1] == '+') {
+ mode &= ~(O_RDONLY|O_WRONLY);
+ mode |= O_RDWR;
+ if (string[2] != 0) {
+ goto error;
+ }
+ } else if (string[1] != 0) {
+ goto error;
+ }
+ *modePtr = mode;
+ return string;
+ }
+
+ /*
+ * The access modes are specified using a list of POSIX modes
+ * such as O_CREAT.
+ */
+
+ if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) {
+ Tcl_AddErrorInfo(interp, "\n while processing open access modes \"");
+ Tcl_AddErrorInfo(interp, string);
+ Tcl_AddErrorInfo(interp, "\"");
+ return NULL;
+ }
+ gotRW = 0;
+ for (i = 0; i < modeArgc; i++) {
+ flag = modeArgv[i];
+ c = flag[0];
+ if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) {
+ mode = (mode & ~RW_MODES) | O_RDONLY;
+ gotRW = 1;
+ } else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) {
+ mode = (mode & ~RW_MODES) | O_WRONLY;
+ gotRW = 1;
+ } else if ((c == 'R') && (strcmp(flag, "RDWR") == 0)) {
+ mode = (mode & ~RW_MODES) | O_RDWR;
+ gotRW = 1;
+ } else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) {
+ mode |= O_APPEND;
+ } else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) {
+ mode |= O_CREAT;
+ } else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) {
+ mode |= O_EXCL;
+ } else if ((c == 'N') && (strcmp(flag, "NOCTTY") == 0)) {
+#ifdef O_NOCTTY
+ mode |= O_NOCTTY;
+#else
+ Tcl_AppendResult(interp, "access mode \"", flag,
+ "\" not supported by this system", (char *) NULL);
+ ckfree((char *) modeArgv);
+ return NULL;
+#endif
+ } else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) {
+#ifdef O_NONBLOCK
+ mode |= O_NONBLOCK;
+#else
+ mode |= O_NDELAY;
+#endif
+ } else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) {
+ mode |= O_TRUNC;
+ } else {
+ Tcl_AppendResult(interp, "invalid access mode \"", flag,
+ "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT",
+ " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL);
+ ckfree((char *) modeArgv);
+ return NULL;
+ }
+ }
+ ckfree((char *) modeArgv);
+ if (!gotRW) {
+ Tcl_AppendResult(interp, "access mode must include either",
+ " RDONLY, WRONLY, or RDWR", (char *) NULL);
+ return NULL;
+ }
+ *modePtr = mode;
+
+ /*
+ * The calculation of fdopen access mode below isn't really correct,
+ * but it doesn't have to be. All it has to do is to disinguish
+ * read and write permissions, plus indicate append mode.
+ */
+
+ i = mode & RW_MODES;
+ if (i == O_RDONLY) {
+ return "r";
+ }
+ if (mode & O_APPEND) {
+ if (i == O_WRONLY) {
+ return "a";
+ } else {
+ return "a+";
+ }
+ }
+ if (i == O_WRONLY) {
+ return "w";
+ }
+ return "r+";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PidCmd --
+ *
+ * This procedure is invoked to process the "pid" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_PidCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+ OpenFile *oFilePtr;
+ int i;
+ char string[50];
+
+ if (argc > 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " ?fileId?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (argc == 1) {
+ sprintf(interp->result, "%d", getpid());
+ } else {
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ oFilePtr = tclOpenFiles[fileno(f)];
+ for (i = 0; i < oFilePtr->numPids; i++) {
+ sprintf(string, "%d", oFilePtr->pidPtr[i]);
+ Tcl_AppendElement(interp, string);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PutsCmd --
+ *
+ * This procedure is invoked to process the "puts" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_PutsCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+ int i, newline;
+ char *fileId;
+
+ i = 1;
+ newline = 1;
+ if ((argc >= 2) && (strcmp(argv[1], "-nonewline") == 0)) {
+ newline = 0;
+ i++;
+ }
+ if ((i < (argc-3)) || (i >= argc)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ "\" ?-nonewline? ?fileId? string", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * The code below provides backwards compatibility with an old
+ * form of the command that is no longer recommended or documented.
+ */
+
+ if (i == (argc-3)) {
+ if (strncmp(argv[i+2], "nonewline", strlen(argv[i+2])) != 0) {
+ Tcl_AppendResult(interp, "bad argument \"", argv[i+2],
+ "\": should be \"nonewline\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ newline = 0;
+ }
+ if (i == (argc-1)) {
+ fileId = "stdout";
+ } else {
+ fileId = argv[i];
+ i++;
+ }
+
+ if (Tcl_GetOpenFile(interp, fileId, 1, 1, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ clearerr(f);
+ fputs(argv[i], f);
+ if (newline) {
+ fputc('\n', f);
+ }
+ if (ferror(f)) {
+ Tcl_AppendResult(interp, "error writing \"", fileId,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PwdCmd --
+ *
+ * This procedure is invoked to process the "pwd" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_PwdCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ char buffer[MAXPATHLEN+1];
+
+ if (argc != 1) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (currentDir == NULL) {
+ if (getcwd(buffer, MAXPATHLEN+1) == NULL) {
+ if (errno == ERANGE) {
+ interp->result = "working directory name is too long";
+ } else {
+ Tcl_AppendResult(interp,
+ "error getting working directory name: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
+ currentDir = (char *) ckalloc((unsigned) (strlen(buffer) + 1));
+ strcpy(currentDir, buffer);
+ }
+ interp->result = currentDir;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ReadCmd --
+ *
+ * This procedure is invoked to process the "read" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ReadCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int bytesLeft, bytesRead, count;
+#define READ_BUF_SIZE 4096
+ char buffer[READ_BUF_SIZE+1];
+ int newline, i;
+ FILE *f;
+
+ if ((argc != 2) && (argc != 3)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId ?numBytes?\" or \"", argv[0],
+ " ?-nonewline? fileId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ i = 1;
+ newline = 1;
+ if ((argc == 3) && (strcmp(argv[1], "-nonewline") == 0)) {
+ newline = 0;
+ i++;
+ }
+ if (Tcl_GetOpenFile(interp, argv[i], 0, 1, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Compute how many bytes to read, and see whether the final
+ * newline should be dropped.
+ */
+
+ if ((argc >= (i + 2)) && isdigit(UCHAR(argv[i+1][0]))) {
+ if (Tcl_GetInt(interp, argv[i+1], &bytesLeft) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ } else {
+ bytesLeft = 1<<30;
+
+ /*
+ * The code below provides backward compatibility for an
+ * archaic earlier version of this command.
+ */
+
+ if (argc >= (i + 2)) {
+ if (strncmp(argv[i+1], "nonewline", strlen(argv[i+1])) == 0) {
+ newline = 0;
+ } else {
+ Tcl_AppendResult(interp, "bad argument \"", argv[i+1],
+ "\": should be \"nonewline\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ }
+
+ /*
+ * Read the file in one or more chunks.
+ */
+
+ bytesRead = 0;
+ clearerr(f);
+ while (bytesLeft > 0) {
+ count = READ_BUF_SIZE;
+ if (bytesLeft < READ_BUF_SIZE) {
+ count = bytesLeft;
+ }
+ count = fread(buffer, 1, count, f);
+ if (ferror(f)) {
+ /*
+ * If the file is in non-blocking mode, break out of the
+ * loop and return any bytes that were read.
+ */
+
+ if ((errno == EWOULDBLOCK) && ((count > 0) || (bytesRead > 0))) {
+ clearerr(f);
+ bytesLeft = count;
+ } else {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "error reading \"", argv[i],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (count == 0) {
+ break;
+ }
+ buffer[count] = 0;
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ bytesLeft -= count;
+ bytesRead += count;
+ }
+ if ((newline == 0) && (bytesRead > 0)
+ && (interp->result[bytesRead-1] == '\n')) {
+ interp->result[bytesRead-1] = 0;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SeekCmd --
+ *
+ * This procedure is invoked to process the "seek" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_SeekCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+ int offset, mode;
+
+ if ((argc != 3) && (argc != 4)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId offset ?origin?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[2], &offset) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ mode = SEEK_SET;
+ if (argc == 4) {
+ int length;
+ char c;
+
+ length = strlen(argv[3]);
+ c = argv[3][0];
+ if ((c == 's') && (strncmp(argv[3], "start", length) == 0)) {
+ mode = SEEK_SET;
+ } else if ((c == 'c') && (strncmp(argv[3], "current", length) == 0)) {
+ mode = SEEK_CUR;
+ } else if ((c == 'e') && (strncmp(argv[3], "end", length) == 0)) {
+ mode = SEEK_END;
+ } else {
+ Tcl_AppendResult(interp, "bad origin \"", argv[3],
+ "\": should be start, current, or end", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ clearerr(f);
+ if (fseek(f, (long) offset, mode) == -1) {
+ Tcl_AppendResult(interp, "error during seek: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SourceCmd --
+ *
+ * This procedure is invoked to process the "source" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_SourceCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return Tcl_EvalFile(interp, argv[1]);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TellCmd --
+ *
+ * This procedure is invoked to process the "tell" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_TellCmd(notUsed, interp, argc, argv)
+ ClientData notUsed; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ FILE *f;
+
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " fileId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ sprintf(interp->result, "%d", ftell(f));
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TimeCmd --
+ *
+ * This procedure is invoked to process the "time" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_TimeCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int count, i, result;
+ double timePer;
+#if NO_GETTOD
+ struct tms dummy2;
+ long start, stop;
+#else
+ struct timeval start, stop;
+ struct timezone tz;
+ int micros;
+#endif
+
+ if (argc == 2) {
+ count = 1;
+ } else if (argc == 3) {
+ if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ } else {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " command ?count?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+#if NO_GETTOD
+ start = times(&dummy2);
+#else
+ gettimeofday(&start, &tz);
+#endif
+ for (i = count ; i > 0; i--) {
+ result = Tcl_Eval(interp, argv[1]);
+ if (result != TCL_OK) {
+ if (result == TCL_ERROR) {
+ char msg[60];
+ sprintf(msg, "\n (\"time\" body line %d)",
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ return result;
+ }
+ }
+#if NO_GETTOD
+ stop = times(&dummy2);
+ timePer = (((double) (stop - start))*1000000.0)/CLK_TCK;
+#else
+ gettimeofday(&stop, &tz);
+ micros = (stop.tv_sec - start.tv_sec)*1000000
+ + (stop.tv_usec - start.tv_usec);
+ timePer = micros;
+#endif
+ Tcl_ResetResult(interp);
+ sprintf(interp->result, "%.0f microseconds per iteration", timePer/count);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CleanupChildren --
+ *
+ * This is a utility procedure used to wait for child processes
+ * to exit, record information about abnormal exits, and then
+ * collect any stderr output generated by them.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If anything at
+ * weird happened with the child processes, TCL_ERROR is returned
+ * and a message is left in interp->result.
+ *
+ * Side effects:
+ * If the last character of interp->result is a newline, then it
+ * is removed unless keepNewline is non-zero. File errorId gets
+ * closed, and pidPtr is freed back to the storage allocator.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+CleanupChildren(interp, numPids, pidPtr, errorId, keepNewline)
+ Tcl_Interp *interp; /* Used for error messages. */
+ int numPids; /* Number of entries in pidPtr array. */
+ int *pidPtr; /* Array of process ids of children. */
+ int errorId; /* File descriptor index for file containing
+ * stderr output from pipeline. -1 means
+ * there isn't any stderr output. */
+ int keepNewline; /* Non-zero means don't discard trailing
+ * newline. */
+{
+ int result = TCL_OK;
+ int i, pid, length, abnormalExit;
+ WAIT_STATUS_TYPE waitStatus;
+
+ abnormalExit = 0;
+ for (i = 0; i < numPids; i++) {
+ pid = waitpid(pidPtr[i], (int *) &waitStatus, 0);
+ if (pid == -1) {
+ Tcl_AppendResult(interp, "error waiting for process to exit: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ continue;
+ }
+
+ /*
+ * Create error messages for unusual process exits. An
+ * extra newline gets appended to each error message, but
+ * it gets removed below (in the same fashion that an
+ * extra newline in the command's output is removed).
+ */
+
+ if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) {
+ char msg1[20], msg2[20];
+
+ result = TCL_ERROR;
+ sprintf(msg1, "%d", pid);
+ if (WIFEXITED(waitStatus)) {
+ sprintf(msg2, "%d", WEXITSTATUS(waitStatus));
+ Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2,
+ (char *) NULL);
+ abnormalExit = 1;
+ } else if (WIFSIGNALED(waitStatus)) {
+ char *p;
+
+ p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus)));
+ Tcl_SetErrorCode(interp, "CHILDKILLED", msg1,
+ Tcl_SignalId((int) (WTERMSIG(waitStatus))), p,
+ (char *) NULL);
+ Tcl_AppendResult(interp, "child killed: ", p, "\n",
+ (char *) NULL);
+ } else if (WIFSTOPPED(waitStatus)) {
+ char *p;
+
+ p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus)));
+ Tcl_SetErrorCode(interp, "CHILDSUSP", msg1,
+ Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, (char *) NULL);
+ Tcl_AppendResult(interp, "child suspended: ", p, "\n",
+ (char *) NULL);
+ } else {
+ Tcl_AppendResult(interp,
+ "child wait status didn't make sense\n",
+ (char *) NULL);
+ }
+ }
+ }
+ ckfree((char *) pidPtr);
+
+ /*
+ * Read the standard error file. If there's anything there,
+ * then return an error and add the file's contents to the result
+ * string.
+ */
+
+ if (errorId >= 0) {
+ while (1) {
+# define BUFFER_SIZE 1000
+ char buffer[BUFFER_SIZE+1];
+ int count;
+
+ count = read(errorId, buffer, (size_t) BUFFER_SIZE);
+
+ if (count == 0) {
+ break;
+ }
+ result = TCL_ERROR;
+ if (count < 0) {
+ Tcl_AppendResult(interp,
+ "error reading stderr output file: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ break;
+ }
+ buffer[count] = 0;
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ }
+ close(errorId);
+ }
+
+ /*
+ * If a child exited abnormally but didn't output any error information
+ * at all, generate an error message here.
+ */
+
+ if (abnormalExit && (*interp->result == 0)) {
+ Tcl_AppendResult(interp, "child process exited abnormally",
+ (char *) NULL);
+ }
+
+ /*
+ * If the last character of interp->result is a newline, then remove
+ * the newline character (the newline would just confuse things).
+ * Special hack: must replace the old terminating null character
+ * as a signal to Tcl_AppendResult et al. that we've mucked with
+ * the string.
+ */
+
+ length = strlen(interp->result);
+ if (!keepNewline && (length > 0) && (interp->result[length-1] == '\n')) {
+ interp->result[length-1] = '\0';
+ interp->result[length] = 'x';
+ }
+
+ return result;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclUnixStr.c b/vendor/x11iraf/obm/Tcl/tclUnixStr.c
new file mode 100644
index 00000000..0ac38b19
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUnixStr.c
@@ -0,0 +1,737 @@
+/*
+ * tclUnixStr.c --
+ *
+ * This file contains procedures that generate strings
+ * corresponding to various UNIX-related codes, such
+ * as errno and signals.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUnixStr.c,v 1.17 93/09/09 14:47:55 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ErrnoId --
+ *
+ * Return a textual identifier for the current errno value.
+ *
+ * Results:
+ * This procedure returns a machine-readable textual identifier
+ * that corresponds to the current errno value (e.g. "EPERM").
+ * The identifier is the same as the #define name in errno.h.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_ErrnoId()
+{
+ switch (errno) {
+#ifdef E2BIG
+ case E2BIG: return "E2BIG";
+#endif
+#ifdef EACCES
+ case EACCES: return "EACCES";
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return "EADDRINUSE";
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
+#endif
+#ifdef EADV
+ case EADV: return "EADV";
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return "EAFNOSUPPORT";
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return "EAGAIN";
+#endif
+#ifdef EALIGN
+ case EALIGN: return "EALIGN";
+#endif
+#ifdef EALREADY
+ case EALREADY: return "EALREADY";
+#endif
+#ifdef EBADE
+ case EBADE: return "EBADE";
+#endif
+#ifdef EBADF
+ case EBADF: return "EBADF";
+#endif
+#ifdef EBADFD
+ case EBADFD: return "EBADFD";
+#endif
+#ifdef EBADMSG
+ case EBADMSG: return "EBADMSG";
+#endif
+#ifdef EBADR
+ case EBADR: return "EBADR";
+#endif
+#ifdef EBADRPC
+ case EBADRPC: return "EBADRPC";
+#endif
+#ifdef EBADRQC
+ case EBADRQC: return "EBADRQC";
+#endif
+#ifdef EBADSLT
+ case EBADSLT: return "EBADSLT";
+#endif
+#ifdef EBFONT
+ case EBFONT: return "EBFONT";
+#endif
+#ifdef EBUSY
+ case EBUSY: return "EBUSY";
+#endif
+#ifdef ECHILD
+ case ECHILD: return "ECHILD";
+#endif
+#ifdef ECHRNG
+ case ECHRNG: return "ECHRNG";
+#endif
+#ifdef ECOMM
+ case ECOMM: return "ECOMM";
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return "ECONNABORTED";
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return "ECONNREFUSED";
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return "ECONNRESET";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+ case EDEADLK: return "EDEADLK";
+#endif
+#ifdef EDEADLOCK
+#if (EDEADLOCK != EDEADLK) && (!(!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)))
+ case EDEADLOCK: return "EDEADLOCK";
+#endif
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return "EDESTADDRREQ";
+#endif
+#ifdef EDIRTY
+ case EDIRTY: return "EDIRTY";
+#endif
+#ifdef EDOM
+ case EDOM: return "EDOM";
+#endif
+#ifdef EDOTDOT
+ case EDOTDOT: return "EDOTDOT";
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return "EDQUOT";
+#endif
+#ifdef EDUPPKG
+ case EDUPPKG: return "EDUPPKG";
+#endif
+#ifdef EEXIST
+ case EEXIST: return "EEXIST";
+#endif
+#ifdef EFAULT
+ case EFAULT: return "EFAULT";
+#endif
+#ifdef EFBIG
+ case EFBIG: return "EFBIG";
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return "EHOSTDOWN";
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return "EHOSTUNREACH";
+#endif
+#ifdef EIDRM
+ case EIDRM: return "EIDRM";
+#endif
+#ifdef EINIT
+ case EINIT: return "EINIT";
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return "EINPROGRESS";
+#endif
+#ifdef EINTR
+ case EINTR: return "EINTR";
+#endif
+#ifdef EINVAL
+ case EINVAL: return "EINVAL";
+#endif
+#ifdef EIO
+ case EIO: return "EIO";
+#endif
+#ifdef EISCONN
+ case EISCONN: return "EISCONN";
+#endif
+#ifdef EISDIR
+ case EISDIR: return "EISDIR";
+#endif
+#ifdef EISNAME
+ case EISNAM: return "EISNAM";
+#endif
+#ifdef ELBIN
+ case ELBIN: return "ELBIN";
+#endif
+#ifdef EL2HLT
+ case EL2HLT: return "EL2HLT";
+#endif
+#ifdef EL2NSYNC
+ case EL2NSYNC: return "EL2NSYNC";
+#endif
+#ifdef EL3HLT
+ case EL3HLT: return "EL3HLT";
+#endif
+#ifdef EL3RST
+ case EL3RST: return "EL3RST";
+#endif
+#ifdef ELIBACC
+ case ELIBACC: return "ELIBACC";
+#endif
+#ifdef ELIBBAD
+ case ELIBBAD: return "ELIBBAD";
+#endif
+#ifdef ELIBEXEC
+ case ELIBEXEC: return "ELIBEXEC";
+#endif
+#ifdef ELIBMAX
+ case ELIBMAX: return "ELIBMAX";
+#endif
+#ifdef ELIBSCN
+ case ELIBSCN: return "ELIBSCN";
+#endif
+#ifdef ELNRNG
+ case ELNRNG: return "ELNRNG";
+#endif
+#ifdef ELOOP
+ case ELOOP: return "ELOOP";
+#endif
+#ifdef EMFILE
+ case EMFILE: return "EMFILE";
+#endif
+#ifdef EMLINK
+ case EMLINK: return "EMLINK";
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return "EMSGSIZE";
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP: return "EMULTIHOP";
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return "ENAMETOOLONG";
+#endif
+#ifdef ENAVAIL
+ case ENAVAIL: return "ENAVAIL";
+#endif
+#ifdef ENET
+ case ENET: return "ENET";
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return "ENETDOWN";
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return "ENETRESET";
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return "ENETUNREACH";
+#endif
+#ifdef ENFILE
+ case ENFILE: return "ENFILE";
+#endif
+#ifdef ENOANO
+ case ENOANO: return "ENOANO";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+ case ENOBUFS: return "ENOBUFS";
+#endif
+#ifdef ENOCSI
+ case ENOCSI: return "ENOCSI";
+#endif
+#ifdef ENODATA
+ case ENODATA: return "ENODATA";
+#endif
+#ifdef ENODEV
+ case ENODEV: return "ENODEV";
+#endif
+#ifdef ENOENT
+ case ENOENT: return "ENOENT";
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return "ENOEXEC";
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return "ENOLCK";
+#endif
+#ifdef ENOLINK
+ case ENOLINK: return "ENOLINK";
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return "ENOMEM";
+#endif
+#ifdef ENOMSG
+ case ENOMSG: return "ENOMSG";
+#endif
+#ifdef ENONET
+ case ENONET: return "ENONET";
+#endif
+#ifdef ENOPKG
+ case ENOPKG: return "ENOPKG";
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return "ENOPROTOOPT";
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return "ENOSPC";
+#endif
+#ifdef ENOSR
+ case ENOSR: return "ENOSR";
+#endif
+#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR))
+ case ENOSTR: return "ENOSTR";
+#endif
+#ifdef ENOSYM
+ case ENOSYM: return "ENOSYM";
+#endif
+#ifdef ENOSYS
+ case ENOSYS: return "ENOSYS";
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: return "ENOTBLK";
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return "ENOTCONN";
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return "ENOTDIR";
+#endif
+#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST))
+ case ENOTEMPTY: return "ENOTEMPTY";
+#endif
+#ifdef ENOTNAM
+ case ENOTNAM: return "ENOTNAM";
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return "ENOTSOCK";
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return "ENOTTY";
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return "ENOTUNIQ";
+#endif
+#ifdef ENXIO
+ case ENXIO: return "ENXIO";
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP: return "EOPNOTSUPP";
+#endif
+#ifdef EPERM
+ case EPERM: return "EPERM";
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: return "EPFNOSUPPORT";
+#endif
+#ifdef EPIPE
+ case EPIPE: return "EPIPE";
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: return "EPROCLIM";
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL: return "EPROCUNAVAIL";
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH: return "EPROGMISMATCH";
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL: return "EPROGUNAVAIL";
+#endif
+#ifdef EPROTO
+ case EPROTO: return "EPROTO";
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return "EPROTOTYPE";
+#endif
+#ifdef ERANGE
+ case ERANGE: return "ERANGE";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+ case EREFUSED: return "EREFUSED";
+#endif
+#ifdef EREMCHG
+ case EREMCHG: return "EREMCHG";
+#endif
+#ifdef EREMDEV
+ case EREMDEV: return "EREMDEV";
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return "EREMOTE";
+#endif
+#ifdef EREMOTEIO
+ case EREMOTEIO: return "EREMOTEIO";
+#endif
+#ifdef EREMOTERELEASE
+ case EREMOTERELEASE: return "EREMOTERELEASE";
+#endif
+#ifdef EROFS
+ case EROFS: return "EROFS";
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH: return "ERPCMISMATCH";
+#endif
+#ifdef ERREMOTE
+ case ERREMOTE: return "ERREMOTE";
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return "ESHUTDOWN";
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return "ESPIPE";
+#endif
+#ifdef ESRCH
+ case ESRCH: return "ESRCH";
+#endif
+#ifdef ESRMNT
+ case ESRMNT: return "ESRMNT";
+#endif
+#ifdef ESTALE
+ case ESTALE: return "ESTALE";
+#endif
+#ifdef ESUCCESS
+ case ESUCCESS: return "ESUCCESS";
+#endif
+#ifdef ETIME
+ case ETIME: return "ETIME";
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return "ETIMEDOUT";
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return "ETOOMANYREFS";
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return "ETXTBSY";
+#endif
+#ifdef EUCLEAN
+ case EUCLEAN: return "EUCLEAN";
+#endif
+#ifdef EUNATCH
+ case EUNATCH: return "EUNATCH";
+#endif
+#ifdef EUSERS
+ case EUSERS: return "EUSERS";
+#endif
+#ifdef EVERSION
+ case EVERSION: return "EVERSION";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK: return "EWOULDBLOCK";
+#endif
+#ifdef EXDEV
+ case EXDEV: return "EXDEV";
+#endif
+#ifdef EXFULL
+ case EXFULL: return "EXFULL";
+#endif
+ }
+ return "unknown error";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ * Return a textual identifier for a signal number.
+ *
+ * Results:
+ * This procedure returns a machine-readable textual identifier
+ * that corresponds to sig. The identifier is the same as the
+ * #define name in signal.h.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SignalId(sig)
+ int sig; /* Number of signal. */
+{
+ switch (sig) {
+#ifdef SIGABRT
+ case SIGABRT: return "SIGABRT";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "SIGALRM";
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "SIGBUS";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "SIGCHLD";
+#endif
+#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD))
+ case SIGCLD: return "SIGCLD";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "SIGCONT";
+#endif
+#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU))
+ case SIGEMT: return "SIGEMT";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "SIGFPE";
+#endif
+#ifdef SIGHUP
+ case SIGHUP: return "SIGHUP";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "SIGILL";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "SIGINT";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "SIGIO";
+#endif
+#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT))
+ case SIGIOT: return "SIGIOT";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "SIGKILL";
+#endif
+#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG))
+ case SIGLOST: return "SIGLOST";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "SIGPIPE";
+#endif
+#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
+ case SIGPOLL: return "SIGPOLL";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "SIGPROF";
+#endif
+#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ))
+ case SIGPWR: return "SIGPWR";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "SIGQUIT";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "SIGSEGV";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "SIGSTOP";
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "SIGSYS";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "SIGTERM";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "SIGTRAP";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "SIGTTOU";
+#endif
+#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO))
+ case SIGURG: return "SIGURG";
+#endif
+#if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO))
+ case SIGUSR1: return "SIGUSR1";
+#endif
+#if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG))
+ case SIGUSR2: return "SIGUSR2";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "SIGVTALRM";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "SIGWINCH";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "SIGXFSZ";
+#endif
+ }
+ return "unknown signal";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalMsg --
+ *
+ * Return a human-readable message describing a signal.
+ *
+ * Results:
+ * This procedure returns a string describing sig that should
+ * make sense to a human. It may not be easy for a machine
+ * to parse.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SignalMsg(sig)
+ int sig; /* Number of signal. */
+{
+ switch (sig) {
+#ifdef SIGABRT
+ case SIGABRT: return "SIGABRT";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "alarm clock";
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "bus error";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "child status changed";
+#endif
+#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD))
+ case SIGCLD: return "child status changed";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "continue after stop";
+#endif
+#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU))
+ case SIGEMT: return "EMT instruction";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "floating-point exception";
+#endif
+#ifdef SIGHUP
+ case SIGHUP: return "hangup";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "illegal instruction";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "interrupt";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "input/output possible on file";
+#endif
+#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT))
+ case SIGIOT: return "IOT instruction";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "kill signal";
+#endif
+#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG))
+ case SIGLOST: return "resource lost";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "write on pipe with no readers";
+#endif
+#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
+ case SIGPOLL: return "input/output possible on file";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "profiling alarm";
+#endif
+#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ))
+ case SIGPWR: return "power-fail restart";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "quit signal";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "segmentation violation";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "stop";
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "bad argument to system call";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "software termination signal";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "trace trap";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "stop signal from tty";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "background tty read";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "background tty write";
+#endif
+#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO))
+ case SIGURG: return "urgent I/O condition";
+#endif
+#if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO))
+ case SIGUSR1: return "user-defined signal 1";
+#endif
+#if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG))
+ case SIGUSR2: return "user-defined signal 2";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "virtual time alarm";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "window changed";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "exceeded CPU time limit";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "exceeded file size limit";
+#endif
+ }
+ return "unknown signal";
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclUnixStr.c.OLD b/vendor/x11iraf/obm/Tcl/tclUnixStr.c.OLD
new file mode 100644
index 00000000..454f30a7
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUnixStr.c.OLD
@@ -0,0 +1,735 @@
+/*
+ * tclUnixStr.c --
+ *
+ * This file contains procedures that generate strings
+ * corresponding to various UNIX-related codes, such
+ * as errno and signals.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUnixStr.c,v 1.17 93/09/09 14:47:55 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ErrnoId --
+ *
+ * Return a textual identifier for the current errno value.
+ *
+ * Results:
+ * This procedure returns a machine-readable textual identifier
+ * that corresponds to the current errno value (e.g. "EPERM").
+ * The identifier is the same as the #define name in errno.h.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_ErrnoId()
+{
+ switch (errno) {
+#ifdef E2BIG
+ case E2BIG: return "E2BIG";
+#endif
+#ifdef EACCES
+ case EACCES: return "EACCES";
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return "EADDRINUSE";
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
+#endif
+#ifdef EADV
+ case EADV: return "EADV";
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return "EAFNOSUPPORT";
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return "EAGAIN";
+#endif
+#ifdef EALIGN
+ case EALIGN: return "EALIGN";
+#endif
+#ifdef EALREADY
+ case EALREADY: return "EALREADY";
+#endif
+#ifdef EBADE
+ case EBADE: return "EBADE";
+#endif
+#ifdef EBADF
+ case EBADF: return "EBADF";
+#endif
+#ifdef EBADFD
+ case EBADFD: return "EBADFD";
+#endif
+#ifdef EBADMSG
+ case EBADMSG: return "EBADMSG";
+#endif
+#ifdef EBADR
+ case EBADR: return "EBADR";
+#endif
+#ifdef EBADRPC
+ case EBADRPC: return "EBADRPC";
+#endif
+#ifdef EBADRQC
+ case EBADRQC: return "EBADRQC";
+#endif
+#ifdef EBADSLT
+ case EBADSLT: return "EBADSLT";
+#endif
+#ifdef EBFONT
+ case EBFONT: return "EBFONT";
+#endif
+#ifdef EBUSY
+ case EBUSY: return "EBUSY";
+#endif
+#ifdef ECHILD
+ case ECHILD: return "ECHILD";
+#endif
+#ifdef ECHRNG
+ case ECHRNG: return "ECHRNG";
+#endif
+#ifdef ECOMM
+ case ECOMM: return "ECOMM";
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return "ECONNABORTED";
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return "ECONNREFUSED";
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return "ECONNRESET";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+ case EDEADLK: return "EDEADLK";
+#endif
+#ifdef EDEADLOCK
+ case EDEADLOCK: return "EDEADLOCK";
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return "EDESTADDRREQ";
+#endif
+#ifdef EDIRTY
+ case EDIRTY: return "EDIRTY";
+#endif
+#ifdef EDOM
+ case EDOM: return "EDOM";
+#endif
+#ifdef EDOTDOT
+ case EDOTDOT: return "EDOTDOT";
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return "EDQUOT";
+#endif
+#ifdef EDUPPKG
+ case EDUPPKG: return "EDUPPKG";
+#endif
+#ifdef EEXIST
+ case EEXIST: return "EEXIST";
+#endif
+#ifdef EFAULT
+ case EFAULT: return "EFAULT";
+#endif
+#ifdef EFBIG
+ case EFBIG: return "EFBIG";
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return "EHOSTDOWN";
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return "EHOSTUNREACH";
+#endif
+#ifdef EIDRM
+ case EIDRM: return "EIDRM";
+#endif
+#ifdef EINIT
+ case EINIT: return "EINIT";
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return "EINPROGRESS";
+#endif
+#ifdef EINTR
+ case EINTR: return "EINTR";
+#endif
+#ifdef EINVAL
+ case EINVAL: return "EINVAL";
+#endif
+#ifdef EIO
+ case EIO: return "EIO";
+#endif
+#ifdef EISCONN
+ case EISCONN: return "EISCONN";
+#endif
+#ifdef EISDIR
+ case EISDIR: return "EISDIR";
+#endif
+#ifdef EISNAME
+ case EISNAM: return "EISNAM";
+#endif
+#ifdef ELBIN
+ case ELBIN: return "ELBIN";
+#endif
+#ifdef EL2HLT
+ case EL2HLT: return "EL2HLT";
+#endif
+#ifdef EL2NSYNC
+ case EL2NSYNC: return "EL2NSYNC";
+#endif
+#ifdef EL3HLT
+ case EL3HLT: return "EL3HLT";
+#endif
+#ifdef EL3RST
+ case EL3RST: return "EL3RST";
+#endif
+#ifdef ELIBACC
+ case ELIBACC: return "ELIBACC";
+#endif
+#ifdef ELIBBAD
+ case ELIBBAD: return "ELIBBAD";
+#endif
+#ifdef ELIBEXEC
+ case ELIBEXEC: return "ELIBEXEC";
+#endif
+#ifdef ELIBMAX
+ case ELIBMAX: return "ELIBMAX";
+#endif
+#ifdef ELIBSCN
+ case ELIBSCN: return "ELIBSCN";
+#endif
+#ifdef ELNRNG
+ case ELNRNG: return "ELNRNG";
+#endif
+#ifdef ELOOP
+ case ELOOP: return "ELOOP";
+#endif
+#ifdef EMFILE
+ case EMFILE: return "EMFILE";
+#endif
+#ifdef EMLINK
+ case EMLINK: return "EMLINK";
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return "EMSGSIZE";
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP: return "EMULTIHOP";
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return "ENAMETOOLONG";
+#endif
+#ifdef ENAVAIL
+ case ENAVAIL: return "ENAVAIL";
+#endif
+#ifdef ENET
+ case ENET: return "ENET";
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return "ENETDOWN";
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return "ENETRESET";
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return "ENETUNREACH";
+#endif
+#ifdef ENFILE
+ case ENFILE: return "ENFILE";
+#endif
+#ifdef ENOANO
+ case ENOANO: return "ENOANO";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+ case ENOBUFS: return "ENOBUFS";
+#endif
+#ifdef ENOCSI
+ case ENOCSI: return "ENOCSI";
+#endif
+#ifdef ENODATA
+ case ENODATA: return "ENODATA";
+#endif
+#ifdef ENODEV
+ case ENODEV: return "ENODEV";
+#endif
+#ifdef ENOENT
+ case ENOENT: return "ENOENT";
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return "ENOEXEC";
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return "ENOLCK";
+#endif
+#ifdef ENOLINK
+ case ENOLINK: return "ENOLINK";
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return "ENOMEM";
+#endif
+#ifdef ENOMSG
+ case ENOMSG: return "ENOMSG";
+#endif
+#ifdef ENONET
+ case ENONET: return "ENONET";
+#endif
+#ifdef ENOPKG
+ case ENOPKG: return "ENOPKG";
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return "ENOPROTOOPT";
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return "ENOSPC";
+#endif
+#ifdef ENOSR
+ case ENOSR: return "ENOSR";
+#endif
+#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR))
+ case ENOSTR: return "ENOSTR";
+#endif
+#ifdef ENOSYM
+ case ENOSYM: return "ENOSYM";
+#endif
+#ifdef ENOSYS
+ case ENOSYS: return "ENOSYS";
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: return "ENOTBLK";
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return "ENOTCONN";
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return "ENOTDIR";
+#endif
+#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST))
+ case ENOTEMPTY: return "ENOTEMPTY";
+#endif
+#ifdef ENOTNAM
+ case ENOTNAM: return "ENOTNAM";
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return "ENOTSOCK";
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return "ENOTTY";
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return "ENOTUNIQ";
+#endif
+#ifdef ENXIO
+ case ENXIO: return "ENXIO";
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP: return "EOPNOTSUPP";
+#endif
+#ifdef EPERM
+ case EPERM: return "EPERM";
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: return "EPFNOSUPPORT";
+#endif
+#ifdef EPIPE
+ case EPIPE: return "EPIPE";
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: return "EPROCLIM";
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL: return "EPROCUNAVAIL";
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH: return "EPROGMISMATCH";
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL: return "EPROGUNAVAIL";
+#endif
+#ifdef EPROTO
+ case EPROTO: return "EPROTO";
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return "EPROTOTYPE";
+#endif
+#ifdef ERANGE
+ case ERANGE: return "ERANGE";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+ case EREFUSED: return "EREFUSED";
+#endif
+#ifdef EREMCHG
+ case EREMCHG: return "EREMCHG";
+#endif
+#ifdef EREMDEV
+ case EREMDEV: return "EREMDEV";
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return "EREMOTE";
+#endif
+#ifdef EREMOTEIO
+ case EREMOTEIO: return "EREMOTEIO";
+#endif
+#ifdef EREMOTERELEASE
+ case EREMOTERELEASE: return "EREMOTERELEASE";
+#endif
+#ifdef EROFS
+ case EROFS: return "EROFS";
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH: return "ERPCMISMATCH";
+#endif
+#ifdef ERREMOTE
+ case ERREMOTE: return "ERREMOTE";
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return "ESHUTDOWN";
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return "ESPIPE";
+#endif
+#ifdef ESRCH
+ case ESRCH: return "ESRCH";
+#endif
+#ifdef ESRMNT
+ case ESRMNT: return "ESRMNT";
+#endif
+#ifdef ESTALE
+ case ESTALE: return "ESTALE";
+#endif
+#ifdef ESUCCESS
+ case ESUCCESS: return "ESUCCESS";
+#endif
+#ifdef ETIME
+ case ETIME: return "ETIME";
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return "ETIMEDOUT";
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return "ETOOMANYREFS";
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return "ETXTBSY";
+#endif
+#ifdef EUCLEAN
+ case EUCLEAN: return "EUCLEAN";
+#endif
+#ifdef EUNATCH
+ case EUNATCH: return "EUNATCH";
+#endif
+#ifdef EUSERS
+ case EUSERS: return "EUSERS";
+#endif
+#ifdef EVERSION
+ case EVERSION: return "EVERSION";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK: return "EWOULDBLOCK";
+#endif
+#ifdef EXDEV
+ case EXDEV: return "EXDEV";
+#endif
+#ifdef EXFULL
+ case EXFULL: return "EXFULL";
+#endif
+ }
+ return "unknown error";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalId --
+ *
+ * Return a textual identifier for a signal number.
+ *
+ * Results:
+ * This procedure returns a machine-readable textual identifier
+ * that corresponds to sig. The identifier is the same as the
+ * #define name in signal.h.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SignalId(sig)
+ int sig; /* Number of signal. */
+{
+ switch (sig) {
+#ifdef SIGABRT
+ case SIGABRT: return "SIGABRT";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "SIGALRM";
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "SIGBUS";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "SIGCHLD";
+#endif
+#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD))
+ case SIGCLD: return "SIGCLD";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "SIGCONT";
+#endif
+#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU))
+ case SIGEMT: return "SIGEMT";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "SIGFPE";
+#endif
+#ifdef SIGHUP
+ case SIGHUP: return "SIGHUP";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "SIGILL";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "SIGINT";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "SIGIO";
+#endif
+#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT))
+ case SIGIOT: return "SIGIOT";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "SIGKILL";
+#endif
+#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG))
+ case SIGLOST: return "SIGLOST";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "SIGPIPE";
+#endif
+#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
+ case SIGPOLL: return "SIGPOLL";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "SIGPROF";
+#endif
+#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ))
+ case SIGPWR: return "SIGPWR";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "SIGQUIT";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "SIGSEGV";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "SIGSTOP";
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "SIGSYS";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "SIGTERM";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "SIGTRAP";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "SIGTTOU";
+#endif
+#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO))
+ case SIGURG: return "SIGURG";
+#endif
+#if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO))
+ case SIGUSR1: return "SIGUSR1";
+#endif
+#if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG))
+ case SIGUSR2: return "SIGUSR2";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "SIGVTALRM";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "SIGWINCH";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "SIGXFSZ";
+#endif
+ }
+ return "unknown signal";
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SignalMsg --
+ *
+ * Return a human-readable message describing a signal.
+ *
+ * Results:
+ * This procedure returns a string describing sig that should
+ * make sense to a human. It may not be easy for a machine
+ * to parse.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SignalMsg(sig)
+ int sig; /* Number of signal. */
+{
+ switch (sig) {
+#ifdef SIGABRT
+ case SIGABRT: return "SIGABRT";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "alarm clock";
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "bus error";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "child status changed";
+#endif
+#if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD))
+ case SIGCLD: return "child status changed";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "continue after stop";
+#endif
+#if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU))
+ case SIGEMT: return "EMT instruction";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "floating-point exception";
+#endif
+#ifdef SIGHUP
+ case SIGHUP: return "hangup";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "illegal instruction";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "interrupt";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "input/output possible on file";
+#endif
+#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT))
+ case SIGIOT: return "IOT instruction";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "kill signal";
+#endif
+#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG))
+ case SIGLOST: return "resource lost";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "write on pipe with no readers";
+#endif
+#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
+ case SIGPOLL: return "input/output possible on file";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "profiling alarm";
+#endif
+#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ))
+ case SIGPWR: return "power-fail restart";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "quit signal";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "segmentation violation";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "stop";
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "bad argument to system call";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "software termination signal";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "trace trap";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "stop signal from tty";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "background tty read";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "background tty write";
+#endif
+#if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO))
+ case SIGURG: return "urgent I/O condition";
+#endif
+#if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO))
+ case SIGUSR1: return "user-defined signal 1";
+#endif
+#if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG))
+ case SIGUSR2: return "user-defined signal 2";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "virtual time alarm";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "window changed";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "exceeded CPU time limit";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "exceeded file size limit";
+#endif
+ }
+ return "unknown signal";
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclUnixUtil.c b/vendor/x11iraf/obm/Tcl/tclUnixUtil.c
new file mode 100644
index 00000000..9f85dc86
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUnixUtil.c
@@ -0,0 +1,1393 @@
+/*
+ * tclUnixUtil.c --
+ *
+ * This file contains a collection of utility procedures that
+ * are present in the Tcl's UNIX core but not in the generic
+ * core. For example, they do file manipulation and process
+ * manipulation.
+ *
+ * Parts of this file are based on code contributed by Karl
+ * Lehenbauer, Mark Diekhans and Peter da Silva.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUnixUtil.c,v 1.45 93/10/23 14:52:10 ouster Exp $ SPRITE (Berkeley)";
+#endif /* not lint */
+
+#include "tclInt.h"
+#include "tclUnix.h"
+
+/*
+ * A linked list of the following structures is used to keep track
+ * of child processes that have been detached but haven't exited
+ * yet, so we can make sure that they're properly "reaped" (officially
+ * waited for) and don't lie around as zombies cluttering the
+ * system.
+ */
+
+typedef struct Detached {
+ int pid; /* Id of process that's been detached
+ * but isn't known to have exited. */
+ struct Detached *nextPtr; /* Next in list of all detached
+ * processes. */
+} Detached;
+
+static Detached *detList = NULL; /* List of all detached proceses. */
+
+/*
+ * The following variables are used to keep track of all the open files
+ * in the process. These files can be shared across interpreters, so the
+ * information can't be put in the Interp structure.
+ */
+
+int tclNumFiles = 0; /* Number of entries in tclOpenFiles below.
+ * 0 means array hasn't been created yet. */
+OpenFile **tclOpenFiles; /* Pointer to malloc-ed array of pointers
+ * to information about open files. Entry
+ * N corresponds to the file with fileno N.
+ * If an entry is NULL then the corresponding
+ * file isn't open. If tclOpenFiles is NULL
+ * it means no files have been used, so even
+ * stdin/stdout/stderr entries haven't been
+ * setup yet. */
+
+/*
+ * Declarations for local procedures defined in this file:
+ */
+
+static int FileForRedirect _ANSI_ARGS_((Tcl_Interp *interp,
+ char *spec, int atOk, char *arg, int flags,
+ char *nextArg, int *skipPtr, int *closePtr));
+static void MakeFileTable _ANSI_ARGS_((Interp *iPtr, int index));
+static void RestoreSignals _ANSI_ARGS_((void));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_EvalFile --
+ *
+ * Read in a file and process the entire file as one gigantic
+ * Tcl command.
+ *
+ * Results:
+ * A standard Tcl result, which is either the result of executing
+ * the file or an error indicating why the file couldn't be read.
+ *
+ * Side effects:
+ * Depends on the commands in the file.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_EvalFile(interp, fileName)
+ Tcl_Interp *interp; /* Interpreter in which to process file. */
+ char *fileName; /* Name of file to process. Tilde-substitution
+ * will be performed on this name. */
+{
+ int fileId, result;
+ struct stat statBuf;
+ char *cmdBuffer, *oldScriptFile;
+ Interp *iPtr = (Interp *) interp;
+ Tcl_DString buffer;
+
+ oldScriptFile = iPtr->scriptFile;
+ iPtr->scriptFile = fileName;
+ fileName = Tcl_TildeSubst(interp, fileName, &buffer);
+ if (fileName == NULL) {
+ goto error;
+ }
+ fileId = open(fileName, O_RDONLY, 0);
+ if (fileId < 0) {
+ Tcl_AppendResult(interp, "couldn't read file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ if (fstat(fileId, &statBuf) == -1) {
+ Tcl_AppendResult(interp, "couldn't stat file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ close(fileId);
+ goto error;
+ }
+ cmdBuffer = (char *) ckalloc((unsigned) statBuf.st_size+1);
+ if (read(fileId, cmdBuffer, (size_t) statBuf.st_size) != statBuf.st_size) {
+ Tcl_AppendResult(interp, "error in reading file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ close(fileId);
+ ckfree(cmdBuffer);
+ goto error;
+ }
+ if (close(fileId) != 0) {
+ Tcl_AppendResult(interp, "error closing file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ ckfree(cmdBuffer);
+ goto error;
+ }
+ cmdBuffer[statBuf.st_size] = 0;
+ result = Tcl_Eval(interp, cmdBuffer);
+ if (result == TCL_RETURN) {
+ result = TCL_OK;
+ }
+ if (result == TCL_ERROR) {
+ char msg[200];
+
+ /*
+ * Record information telling where the error occurred.
+ */
+
+ sprintf(msg, "\n (file \"%.150s\" line %d)", fileName,
+ interp->errorLine);
+ Tcl_AddErrorInfo(interp, msg);
+ }
+ ckfree(cmdBuffer);
+ iPtr->scriptFile = oldScriptFile;
+ Tcl_DStringFree(&buffer);
+ return result;
+
+ error:
+ iPtr->scriptFile = oldScriptFile;
+ Tcl_DStringFree(&buffer);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DetachPids --
+ *
+ * This procedure is called to indicate that one or more child
+ * processes have been placed in background and will never be
+ * waited for; they should eventually be reaped by
+ * Tcl_ReapDetachedProcs.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DetachPids(numPids, pidPtr)
+ int numPids; /* Number of pids to detach: gives size
+ * of array pointed to by pidPtr. */
+ int *pidPtr; /* Array of pids to detach. */
+{
+ register Detached *detPtr;
+ int i;
+
+ for (i = 0; i < numPids; i++) {
+ detPtr = (Detached *) ckalloc(sizeof(Detached));
+ detPtr->pid = pidPtr[i];
+ detPtr->nextPtr = detList;
+ detList = detPtr;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ReapDetachedProcs --
+ *
+ * This procedure checks to see if any detached processes have
+ * exited and, if so, it "reaps" them by officially waiting on
+ * them. It should be called "occasionally" to make sure that
+ * all detached processes are eventually reaped.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Processes are waited on, so that they can be reaped by the
+ * system.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_ReapDetachedProcs()
+{
+ register Detached *detPtr;
+ Detached *nextPtr, *prevPtr;
+ int status, result;
+
+ for (detPtr = detList, prevPtr = NULL; detPtr != NULL; ) {
+ result = waitpid(detPtr->pid, &status, WNOHANG);
+ if ((result == 0) || ((result == -1) && (errno != ECHILD))) {
+ prevPtr = detPtr;
+ detPtr = detPtr->nextPtr;
+ continue;
+ }
+ nextPtr = detPtr->nextPtr;
+ if (prevPtr == NULL) {
+ detList = detPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = detPtr->nextPtr;
+ }
+ ckfree((char *) detPtr);
+ detPtr = nextPtr;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreatePipeline --
+ *
+ * Given an argc/argv array, instantiate a pipeline of processes
+ * as described by the argv.
+ *
+ * Results:
+ * The return value is a count of the number of new processes
+ * created, or -1 if an error occurred while creating the pipeline.
+ * *pidArrayPtr is filled in with the address of a dynamically
+ * allocated array giving the ids of all of the processes. It
+ * is up to the caller to free this array when it isn't needed
+ * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in
+ * with the file id for the input pipe for the pipeline (if any):
+ * the caller must eventually close this file. If outPipePtr
+ * isn't NULL, then *outPipePtr is filled in with the file id
+ * for the output pipe from the pipeline: the caller must close
+ * this file. If errFilePtr isn't NULL, then *errFilePtr is filled
+ * with a file id that may be used to read error output after the
+ * pipeline completes.
+ *
+ * Side effects:
+ * Processes and pipes are created.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_CreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr,
+ outPipePtr, errFilePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ int argc; /* Number of entries in argv. */
+ char **argv; /* Array of strings describing commands in
+ * pipeline plus I/O redirection with <,
+ * <<, >, etc. Argv[argc] must be NULL. */
+ int **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with
+ * address of array of pids for processes
+ * in pipeline (first pid is first process
+ * in pipeline). */
+ int *inPipePtr; /* If non-NULL, input to the pipeline comes
+ * from a pipe (unless overridden by
+ * redirection in the command). The file
+ * id with which to write to this pipe is
+ * stored at *inPipePtr. -1 means command
+ * specified its own input source. */
+ int *outPipePtr; /* If non-NULL, output to the pipeline goes
+ * to a pipe, unless overriden by redirection
+ * in the command. The file id with which to
+ * read frome this pipe is stored at
+ * *outPipePtr. -1 means command specified
+ * its own output sink. */
+ int *errFilePtr; /* If non-NULL, all stderr output from the
+ * pipeline will go to a temporary file
+ * created here, and a descriptor to read
+ * the file will be left at *errFilePtr.
+ * The file will be removed already, so
+ * closing this descriptor will be the end
+ * of the file. If this is NULL, then
+ * all stderr output goes to our stderr.
+ * If the pipeline specifies redirection
+ * then the fill will still be created
+ * but it will never get any data. */
+{
+ int *pidPtr = NULL; /* Points to malloc-ed array holding all
+ * the pids of child processes. */
+ int numPids = 0; /* Actual number of processes that exist
+ * at *pidPtr right now. */
+ int cmdCount; /* Count of number of distinct commands
+ * found in argc/argv. */
+ char *input = NULL; /* If non-null, then this points to a
+ * string containing input data (specified
+ * via <<) to be piped to the first process
+ * in the pipeline. */
+ int inputId = -1; /* If >= 0, gives file id to use as input for
+ * first process in pipeline (specified via
+ * < or <@). */
+ int closeInput = 0; /* If non-zero, then must close inputId
+ * when cleaning up (zero means the file needs
+ * to stay open for some other reason). */
+ int outputId = -1; /* Writable file id for output from last
+ * command in pipeline (could be file or pipe).
+ * -1 means use stdout. */
+ int closeOutput = 0; /* Non-zero means must close outputId when
+ * cleaning up (similar to closeInput). */
+ int errorId = -1; /* Writable file id for error output from
+ * all commands in pipeline. -1 means use
+ * stderr. */
+ int closeError = 0; /* Non-zero means must close errorId when
+ * cleaning up. */
+ int pipeIds[2]; /* File ids for pipe that's being created. */
+ int firstArg, lastArg; /* Indexes of first and last arguments in
+ * current command. */
+ int skip; /* Number of arguments to skip (because they
+ * specify redirection). */
+ int maxFd; /* Highest known file descriptor (used to
+ * close off extraneous file descriptors in
+ * child process). */
+ int lastBar;
+ char *execName;
+ int i, j, pid;
+ char *p;
+ Tcl_DString buffer;
+
+ if (inPipePtr != NULL) {
+ *inPipePtr = -1;
+ }
+ if (outPipePtr != NULL) {
+ *outPipePtr = -1;
+ }
+ if (errFilePtr != NULL) {
+ *errFilePtr = -1;
+ }
+ pipeIds[0] = pipeIds[1] = -1;
+
+ /*
+ * First, scan through all the arguments to figure out the structure
+ * of the pipeline. Process all of the input and output redirection
+ * arguments and remove them from the argument list in the pipeline.
+ * Count the number of distinct processes (it's the number of "|"
+ * arguments plus one) but don't remove the "|" arguments.
+ */
+
+ cmdCount = 1;
+ lastBar = -1;
+ for (i = 0; i < argc; i++) {
+ if ((argv[i][0] == '|') && (((argv[i][1] == 0))
+ || ((argv[i][1] == '&') && (argv[i][2] == 0)))) {
+ if ((i == (lastBar+1)) || (i == (argc-1))) {
+ interp->result = "illegal use of | or |& in command";
+ return -1;
+ }
+ lastBar = i;
+ cmdCount++;
+ continue;
+ } else if (argv[i][0] == '<') {
+ if ((inputId >= 0) && closeInput) {
+ close(inputId);
+ }
+ inputId = -1;
+ skip = 1;
+ if (argv[i][1] == '<') {
+ input = argv[i]+2;
+ if (*input == 0) {
+ input = argv[i+1];
+ if (input == 0) {
+ Tcl_AppendResult(interp, "can't specify \"", argv[i],
+ "\" as last word in command", (char *) NULL);
+ goto error;
+ }
+ skip = 2;
+ }
+ } else {
+ input = 0;
+ inputId = FileForRedirect(interp, argv[i]+1, 1, argv[i],
+ O_RDONLY, argv[i+1], &skip, &closeInput);
+ if (inputId < 0) {
+ goto error;
+ }
+ }
+ } else if (argv[i][0] == '>') {
+ int append, useForStdErr, useForStdOut, mustClose, fd, atOk, flags;
+
+ skip = atOk = 1;
+ append = useForStdErr = 0;
+ useForStdOut = 1;
+ if (argv[i][1] == '>') {
+ p = argv[i] + 2;
+ append = 1;
+ atOk = 0;
+ flags = O_WRONLY|O_CREAT;
+ } else {
+ p = argv[i] + 1;
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ }
+ if (*p == '&') {
+ useForStdErr = 1;
+ p++;
+ }
+ fd = FileForRedirect(interp, p, atOk, argv[i], flags, argv[i+1],
+ &skip, &mustClose);
+ if (fd < 0) {
+ goto error;
+ }
+ if (append) {
+ lseek(fd, 0L, 2);
+ }
+
+ /*
+ * Got the file descriptor. Now use it for standard output,
+ * standard error, or both, depending on the redirection.
+ */
+
+ if (useForStdOut) {
+ if ((outputId > 0) && closeOutput) {
+ close(outputId);
+ }
+ outputId = fd;
+ closeOutput = mustClose;
+ }
+ if (useForStdErr) {
+ if ((errorId > 0) && closeError) {
+ close(errorId);
+ }
+ errorId = fd;
+ closeError = (useForStdOut) ? 0 : mustClose;
+ }
+ } else if ((argv[i][0] == '2') && (argv[i][1] == '>')) {
+ int append, atOk, flags;
+
+ if ((errorId > 0) && closeError) {
+ close(errorId);
+ }
+ skip = 1;
+ p = argv[i] + 2;
+ if (*p == '>') {
+ p++;
+ append = 1;
+ atOk = 0;
+ flags = O_WRONLY|O_CREAT;
+ } else {
+ append = 0;
+ atOk = 1;
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ }
+ errorId = FileForRedirect(interp, p, atOk, argv[i], flags,
+ argv[i+1], &skip, &closeError);
+ if (errorId < 0) {
+ goto error;
+ }
+ if (append) {
+ lseek(errorId, 0L, 2);
+ }
+ } else {
+ continue;
+ }
+ for (j = i+skip; j < argc; j++) {
+ argv[j-skip] = argv[j];
+ }
+ argc -= skip;
+ i -= 1; /* Process next arg from same position. */
+ }
+ if (argc == 0) {
+ interp->result = "didn't specify command to execute";
+ return -1;
+ }
+
+ if (inputId < 0) {
+ if (input != NULL) {
+ char inName[L_tmpnam];
+ int length;
+
+ /*
+ * The input for the first process is immediate data coming from
+ * Tcl. Create a temporary file for it and put the data into the
+ * file.
+ */
+
+#ifdef linux
+ mkstemp(inName);
+#else
+ tmpnam(inName);
+#endif
+ inputId = open(inName, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ closeInput = 1;
+ if (inputId < 0) {
+ Tcl_AppendResult(interp,
+ "couldn't create input file for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ length = strlen(input);
+ if (write(inputId, input, (size_t) length) != length) {
+ Tcl_AppendResult(interp,
+ "couldn't write file input for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ if ((lseek(inputId, 0L, 0) == -1) || (unlink(inName) == -1)) {
+ Tcl_AppendResult(interp,
+ "couldn't reset or remove input file for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ } else if (inPipePtr != NULL) {
+ /*
+ * The input for the first process in the pipeline is to
+ * come from a pipe that can be written from this end.
+ */
+
+ if (pipe(pipeIds) != 0) {
+ Tcl_AppendResult(interp,
+ "couldn't create input pipe for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ inputId = pipeIds[0];
+ closeInput = 1;
+ *inPipePtr = pipeIds[1];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+ }
+
+ /*
+ * Set up a pipe to receive output from the pipeline, if no other
+ * output sink has been specified.
+ */
+
+ if ((outputId < 0) && (outPipePtr != NULL)) {
+ if (pipe(pipeIds) != 0) {
+ Tcl_AppendResult(interp,
+ "couldn't create output pipe: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ outputId = pipeIds[1];
+ closeOutput = 1;
+ *outPipePtr = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ /*
+ * Set up the standard error output sink for the pipeline, if
+ * requested. Use a temporary file which is opened, then deleted.
+ * Could potentially just use pipe, but if it filled up it could
+ * cause the pipeline to deadlock: we'd be waiting for processes
+ * to complete before reading stderr, and processes couldn't complete
+ * because stderr was backed up.
+ */
+
+ if (errFilePtr != NULL) {
+ char errName[L_tmpnam];
+
+#ifdef linux
+ mkstemp(errName);
+#else
+ tmpnam(errName);
+#endif
+ *errFilePtr = open(errName, O_RDONLY|O_CREAT|O_TRUNC, 0600);
+ if (*errFilePtr < 0) {
+ errFileError:
+ Tcl_AppendResult(interp,
+ "couldn't create error file for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ if (errorId < 0) {
+ errorId = open(errName, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ if (errorId < 0) {
+ goto errFileError;
+ }
+ closeError = 1;
+ }
+ if (unlink(errName) == -1) {
+ Tcl_AppendResult(interp,
+ "couldn't remove error file for command: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ }
+
+ /*
+ * Find the largest file descriptor used so far, so that we can
+ * clean up all the extraneous file descriptors in the child
+ * processes we create.
+ */
+
+ maxFd = inputId;
+ if (outputId > maxFd) {
+ maxFd = outputId;
+ }
+ if (errorId > maxFd) {
+ maxFd = errorId;
+ }
+ if ((inPipePtr != NULL) && (*inPipePtr > maxFd)) {
+ maxFd = *inPipePtr;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr > maxFd)) {
+ maxFd = *outPipePtr;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr > maxFd)) {
+ maxFd = *errFilePtr;
+ }
+
+ /*
+ * Scan through the argc array, forking off a process for each
+ * group of arguments between "|" arguments.
+ */
+
+ pidPtr = (int *) ckalloc((unsigned) (cmdCount * sizeof(int)));
+ for (i = 0; i < numPids; i++) {
+ pidPtr[i] = -1;
+ }
+ Tcl_ReapDetachedProcs();
+ for (firstArg = 0; firstArg < argc; numPids++, firstArg = lastArg+1) {
+ int joinThisError;
+ int curOutputId;
+
+ joinThisError = 0;
+ for (lastArg = firstArg; lastArg < argc; lastArg++) {
+ if (argv[lastArg][0] == '|') {
+ if (argv[lastArg][1] == 0) {
+ break;
+ }
+ if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == 0)) {
+ joinThisError = 1;
+ break;
+ }
+ }
+ }
+ argv[lastArg] = NULL;
+ if (lastArg == argc) {
+ curOutputId = outputId;
+ } else {
+ if (pipe(pipeIds) != 0) {
+ Tcl_AppendResult(interp, "couldn't create pipe: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ curOutputId = pipeIds[1];
+ if (pipeIds[0] > maxFd) {
+ maxFd = pipeIds[0];
+ }
+ if (pipeIds[1] > maxFd) {
+ maxFd = pipeIds[1];
+ }
+ }
+ execName = Tcl_TildeSubst(interp, argv[firstArg], &buffer);
+ pid = fork();
+ if (pid == 0) {
+ char errSpace[200];
+
+ if (((inputId != -1) && (dup2(inputId, 0) == -1))
+ || ((curOutputId != -1) && (dup2(curOutputId, 1) == -1))
+ || (joinThisError && (dup2(1, 2) == -1))
+ || (!joinThisError && (errorId != -1)
+ && (dup2(errorId, 2) == -1))) {
+ char *err;
+ err = "forked process couldn't set up input/output\n";
+ write(errorId < 0 ? 2 : errorId, err, (size_t) strlen(err));
+ _exit(1);
+ }
+ for (i = 3; i <= maxFd; i++) {
+ close(i);
+ }
+ RestoreSignals();
+ execvp(execName, &argv[firstArg]);
+ sprintf(errSpace, "couldn't find \"%.150s\" to execute\n",
+ argv[firstArg]);
+ write(2, errSpace, (size_t) strlen(errSpace));
+ _exit(1);
+ }
+ Tcl_DStringFree(&buffer);
+ if (pid == -1) {
+ Tcl_AppendResult(interp, "couldn't fork child process: ",
+ Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ pidPtr[numPids] = pid;
+
+ /*
+ * Close off our copies of file descriptors that were set up for
+ * this child, then set up the input for the next child.
+ */
+
+ if ((inputId != -1) && closeInput) {
+ close(inputId);
+ }
+ if ((curOutputId != -1) && (curOutputId != outputId)) {
+ close(curOutputId);
+ }
+ inputId = pipeIds[0];
+ closeInput = 1;
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+ *pidArrayPtr = pidPtr;
+
+ /*
+ * All done. Cleanup open files lying around and then return.
+ */
+
+cleanup:
+ if ((inputId != -1) && closeInput) {
+ close(inputId);
+ }
+ if ((outputId != -1) && closeOutput) {
+ close(outputId);
+ }
+ if ((errorId != -1) && closeError) {
+ close(errorId);
+ }
+ return numPids;
+
+ /*
+ * An error occurred. There could have been extra files open, such
+ * as pipes between children. Clean them all up. Detach any child
+ * processes that have been created.
+ */
+
+ error:
+ if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
+ close(*inPipePtr);
+ *inPipePtr = -1;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
+ close(*outPipePtr);
+ *outPipePtr = -1;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
+ close(*errFilePtr);
+ *errFilePtr = -1;
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (pipeIds[1] != -1) {
+ close(pipeIds[1]);
+ }
+ if (pidPtr != NULL) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != -1) {
+ Tcl_DetachPids(1, &pidPtr[i]);
+ }
+ }
+ ckfree((char *) pidPtr);
+ }
+ numPids = -1;
+ goto cleanup;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FileForRedirect --
+ *
+ * This procedure does much of the work of parsing redirection
+ * operators. It handles "@" if specified and allowed, and a file
+ * name, and opens the file if necessary.
+ *
+ * Results:
+ * The return value is the descriptor number for the file. If an
+ * error occurs then -1 is returned and an error message is left
+ * in interp->result. Several arguments are side-effected; see
+ * the argument list below for details.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+FileForRedirect(interp, spec, atOk, arg, flags, nextArg, skipPtr, closePtr)
+ Tcl_Interp *interp; /* Intepreter to use for error
+ * reporting. */
+ register char *spec; /* Points to character just after
+ * redirection character. */
+ int atOk; /* Non-zero means '@' notation is
+ * OK, zero means it isn't. */
+ char *arg; /* Pointer to entire argument
+ * containing spec: used for error
+ * reporting. */
+ int flags; /* Flags to use for opening file. */
+ char *nextArg; /* Next argument in argc/argv
+ * array, if needed for file name.
+ * May be NULL. */
+ int *skipPtr; /* This value is incremented if
+ * nextArg is used for redirection
+ * spec. */
+ int *closePtr; /* This value is set to 1 if the file
+ * that's returned must be closed, 0
+ * if it was specified with "@" so
+ * it must be left open. */
+{
+ int writing = (flags & O_WRONLY);
+ FILE *f;
+ int fd;
+
+ if (atOk && (*spec == '@')) {
+ spec++;
+ if (*spec == 0) {
+ spec = nextArg;
+ if (spec == NULL) {
+ goto badLastArg;
+ }
+ *skipPtr += 1;
+ }
+ if (Tcl_GetOpenFile(interp, spec, writing, 1, &f) != TCL_OK) {
+ return -1;
+ }
+ *closePtr = 0;
+ fd = fileno(f);
+ } else {
+ if (*spec == 0) {
+ spec = nextArg;
+ if (spec == NULL) {
+ goto badLastArg;
+ }
+ *skipPtr += 1;
+ }
+ fd = open(spec, flags, 0666);
+ if (fd < 0) {
+ Tcl_AppendResult(interp, "couldn't ",
+ (writing) ? "write" : "read", " file \"", spec, "\": ",
+ Tcl_PosixError(interp), (char *) NULL);
+ return -1;
+ }
+ *closePtr = 1;
+ }
+ return fd;
+
+ badLastArg:
+ Tcl_AppendResult(interp, "can't specify \"", arg,
+ "\" as last word in command", (char *) NULL);
+ return -1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * RestoreSignals --
+ *
+ * This procedure is invoked in a forked child process just before
+ * exec-ing a new program to restore all signals to their default
+ * settings.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Signal settings get changed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+RestoreSignals()
+{
+#ifdef SIGABRT
+ signal(SIGABRT, SIG_DFL);
+#endif
+#ifdef SIGALRM
+ signal(SIGALRM, SIG_DFL);
+#endif
+#ifdef SIGFPE
+ signal(SIGFPE, SIG_DFL);
+#endif
+#ifdef SIGHUP
+ signal(SIGHUP, SIG_DFL);
+#endif
+#ifdef SIGILL
+ signal(SIGILL, SIG_DFL);
+#endif
+#ifdef SIGINT
+ signal(SIGINT, SIG_DFL);
+#endif
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+#ifdef SIGQUIT
+ signal(SIGQUIT, SIG_DFL);
+#endif
+#ifdef SIGSEGV
+ signal(SIGSEGV, SIG_DFL);
+#endif
+#ifdef SIGTERM
+ signal(SIGTERM, SIG_DFL);
+#endif
+#ifdef SIGUSR1
+ signal(SIGUSR1, SIG_DFL);
+#endif
+#ifdef SIGUSR2
+ signal(SIGUSR2, SIG_DFL);
+#endif
+#ifdef SIGCHLD
+ signal(SIGCHLD, SIG_DFL);
+#endif
+#ifdef SIGCONT
+ signal(SIGCONT, SIG_DFL);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_DFL);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_DFL);
+#endif
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_DFL);
+#endif
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PosixError --
+ *
+ * This procedure is typically called after UNIX kernel calls
+ * return errors. It stores machine-readable information about
+ * the error in $errorCode returns an information string for
+ * the caller's use.
+ *
+ * Results:
+ * The return value is a human-readable string describing the
+ * error, as returned by strerror.
+ *
+ * Side effects:
+ * The global variable $errorCode is reset.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_PosixError(interp)
+ Tcl_Interp *interp; /* Interpreter whose $errorCode variable
+ * is to be changed. */
+{
+ char *id, *msg;
+
+ id = Tcl_ErrnoId();
+ msg = strerror(errno);
+ Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL);
+ return msg;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MakeFileTable --
+ *
+ * Create or enlarge the file table for the interpreter, so that
+ * there is room for a given index.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The file table for iPtr will be created if it doesn't exist
+ * (and entries will be added for stdin, stdout, and stderr).
+ * If it already exists, then it will be grown if necessary.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+static void
+MakeFileTable(iPtr, index)
+ Interp *iPtr; /* Interpreter whose table of files is
+ * to be manipulated. */
+ int index; /* Make sure table is large enough to
+ * hold at least this index. */
+{
+ /*
+ * If the table doesn't even exist, then create it and initialize
+ * entries for standard files.
+ */
+
+ if (tclNumFiles == 0) {
+ OpenFile *oFilePtr;
+ int i;
+
+ if (index < 2) {
+ tclNumFiles = 3;
+ } else {
+ tclNumFiles = index+1;
+ }
+ tclOpenFiles = (OpenFile **) ckalloc((unsigned)
+ ((tclNumFiles)*sizeof(OpenFile *)));
+ for (i = tclNumFiles-1; i >= 0; i--) {
+ tclOpenFiles[i] = NULL;
+ }
+
+ oFilePtr = (OpenFile *) ckalloc(sizeof(OpenFile));
+ oFilePtr->f = stdin;
+ oFilePtr->f2 = NULL;
+ oFilePtr->permissions = TCL_FILE_READABLE;
+ oFilePtr->numPids = 0;
+ oFilePtr->pidPtr = NULL;
+ oFilePtr->errorId = -1;
+ tclOpenFiles[0] = oFilePtr;
+
+ oFilePtr = (OpenFile *) ckalloc(sizeof(OpenFile));
+ oFilePtr->f = stdout;
+ oFilePtr->f2 = NULL;
+ oFilePtr->permissions = TCL_FILE_WRITABLE;
+ oFilePtr->numPids = 0;
+ oFilePtr->pidPtr = NULL;
+ oFilePtr->errorId = -1;
+ tclOpenFiles[1] = oFilePtr;
+
+ oFilePtr = (OpenFile *) ckalloc(sizeof(OpenFile));
+ oFilePtr->f = stderr;
+ oFilePtr->f2 = NULL;
+ oFilePtr->permissions = TCL_FILE_WRITABLE;
+ oFilePtr->numPids = 0;
+ oFilePtr->pidPtr = NULL;
+ oFilePtr->errorId = -1;
+ tclOpenFiles[2] = oFilePtr;
+ } else if (index >= tclNumFiles) {
+ int newSize;
+ OpenFile **newPtrArray;
+ int i;
+
+ newSize = index+1;
+ newPtrArray = (OpenFile **) ckalloc((unsigned)
+ ((newSize)*sizeof(OpenFile *)));
+ memcpy((VOID *) newPtrArray, (VOID *) tclOpenFiles,
+ tclNumFiles*sizeof(OpenFile *));
+ for (i = tclNumFiles; i < newSize; i++) {
+ newPtrArray[i] = NULL;
+ }
+ ckfree((char *) tclOpenFiles);
+ tclNumFiles = newSize;
+ tclOpenFiles = newPtrArray;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_EnterFile --
+ *
+ * This procedure is used to enter an already-open file into the
+ * file table for an interpreter so that the file can be read
+ * and written with Tcl commands.
+ *
+ * Results:
+ * There is no return value, but interp->result is set to
+ * hold Tcl's id for the open file, such as "file4".
+ *
+ * Side effects:
+ * "File" is added to the files accessible from interp.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_EnterFile(interp, file, permissions)
+ Tcl_Interp *interp; /* Interpreter in which to make file
+ * available. */
+ FILE *file; /* File to make available in interp. */
+ int permissions; /* Ops that may be done on file: OR-ed
+ * combinination of TCL_FILE_READABLE and
+ * TCL_FILE_WRITABLE. */
+{
+ Interp *iPtr = (Interp *) interp;
+ int fd;
+ register OpenFile *oFilePtr;
+
+ fd = fileno(file);
+ if (fd >= tclNumFiles) {
+ MakeFileTable(iPtr, fd);
+ }
+ oFilePtr = tclOpenFiles[fd];
+
+ /*
+ * It's possible that there already appears to be a file open in
+ * the slot. This could happen, for example, if the application
+ * closes a file behind our back so that we don't have a chance
+ * to clean up. This is probably a bad idea, but if it happens
+ * just discard the information in the old record (hopefully the
+ * application is smart enough to have really cleaned everything
+ * up right).
+ */
+
+ if (oFilePtr == NULL) {
+ oFilePtr = (OpenFile *) ckalloc(sizeof(OpenFile));
+ tclOpenFiles[fd] = oFilePtr;
+ }
+ oFilePtr->f = file;
+ oFilePtr->f2 = NULL;
+ oFilePtr->permissions = permissions;
+ oFilePtr->numPids = 0;
+ oFilePtr->pidPtr = NULL;
+ oFilePtr->errorId = -1;
+ if (fd <= 2) {
+ if (fd == 0) {
+ interp->result = "stdin";
+ } else if (fd == 1) {
+ interp->result = "stdout";
+ } else {
+ interp->result = "stderr";
+ }
+ } else {
+ sprintf(interp->result, "file%d", fd);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetOpenFile --
+ *
+ * Given a string identifier for an open file, find the corresponding
+ * open file structure, if there is one.
+ *
+ * Results:
+ * A standard Tcl return value. If the open file is successfully
+ * located and meets any usage check requested by checkUsage, TCL_OK
+ * is returned and *filePtr is modified to hold a pointer to its
+ * FILE structure. If an error occurs then TCL_ERROR is returned
+ * and interp->result contains an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetOpenFile(interp, string, forWriting, checkUsage, filePtr)
+ Tcl_Interp *interp; /* Interpreter in which to find file. */
+ char *string; /* String that identifies file. */
+ int forWriting; /* 1 means the file is going to be used
+ * for writing, 0 means for reading. */
+ int checkUsage; /* 1 means verify that the file was opened
+ * in a mode that allows the access specified
+ * by "forWriting". */
+ FILE **filePtr; /* Store pointer to FILE structure here. */
+{
+ OpenFile *oFilePtr;
+ int fd = 0; /* Initial value needed only to stop compiler
+ * warnings. */
+ Interp *iPtr = (Interp *) interp;
+
+ if ((string[0] == 'f') && (string[1] == 'i') && (string[2] == 'l')
+ & (string[3] == 'e')) {
+ char *end;
+
+ fd = strtoul(string+4, &end, 10);
+ if ((end == string+4) || (*end != 0)) {
+ goto badId;
+ }
+ } else if ((string[0] == 's') && (string[1] == 't')
+ && (string[2] == 'd')) {
+ if (strcmp(string+3, "in") == 0) {
+ fd = 0;
+ } else if (strcmp(string+3, "out") == 0) {
+ fd = 1;
+ } else if (strcmp(string+3, "err") == 0) {
+ fd = 2;
+ } else {
+ goto badId;
+ }
+ } else {
+ badId:
+ Tcl_AppendResult(interp, "bad file identifier \"", string,
+ "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (fd >= tclNumFiles) {
+ if ((tclNumFiles == 0) && (fd <= 2)) {
+ MakeFileTable(iPtr, fd);
+ } else {
+ notOpen:
+ Tcl_AppendResult(interp, "file \"", string, "\" isn't open",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ oFilePtr = tclOpenFiles[fd];
+ if (oFilePtr == NULL) {
+ goto notOpen;
+ }
+ if (forWriting) {
+ if (checkUsage && !(oFilePtr->permissions & TCL_FILE_WRITABLE)) {
+ Tcl_AppendResult(interp, "\"", string,
+ "\" wasn't opened for writing", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (oFilePtr->f2 != NULL) {
+ *filePtr = oFilePtr->f2;
+ } else {
+ *filePtr = oFilePtr->f;
+ }
+ } else {
+ if (checkUsage && !(oFilePtr->permissions & TCL_FILE_READABLE)) {
+ Tcl_AppendResult(interp, "\"", string,
+ "\" wasn't opened for reading", (char *) NULL);
+ return TCL_ERROR;
+ }
+ *filePtr = oFilePtr->f;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FilePermissions --
+ *
+ * Given a FILE * pointer, return the read/write permissions
+ * associated with the open file.
+ *
+ * Results:
+ * If file is currently open, the return value is an OR-ed
+ * combination of TCL_FILE_READABLE and TCL_FILE_WRITABLE,
+ * which indicates the operations permitted on the open file.
+ * If the file isn't open then the return value is -1.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_FilePermissions(file)
+ FILE *file; /* File for which permissions are wanted. */
+{
+ register OpenFile *oFilePtr;
+ int i, fd;
+
+ /*
+ * First try the entry in tclOpenFiles given by the file descriptor
+ * for the file. If that doesn't match then search all the entries
+ * in tclOpenFiles.
+ */
+
+ if (file != NULL) {
+ fd = fileno(file);
+ if (fd < tclNumFiles) {
+ oFilePtr = tclOpenFiles[fd];
+ if ((oFilePtr != NULL) && (oFilePtr->f == file)) {
+ return oFilePtr->permissions;
+ }
+ }
+ }
+ for (i = 0; i < tclNumFiles; i++) {
+ oFilePtr = tclOpenFiles[i];
+ if (oFilePtr == NULL) {
+ continue;
+ }
+ if ((oFilePtr->f == file) || (oFilePtr->f2 == file)) {
+ return oFilePtr->permissions;
+ }
+ }
+ return -1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclOpen, etc. --
+ *
+ * Below are a bunch of procedures that are used by Tcl instead
+ * of system calls. Each of the procedures executes the
+ * corresponding system call and retries automatically
+ * if the system call was interrupted by a signal.
+ *
+ * Results:
+ * Whatever the system call would normally return.
+ *
+ * Side effects:
+ * Whatever the system call would normally do.
+ *
+ * NOTE:
+ * This should be the last page of this file, since it undefines
+ * the macros that redirect read etc. to the procedures below.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#undef open
+int
+TclOpen(path, oflag, mode)
+ char *path;
+ int oflag;
+ int mode;
+{
+ int result;
+ while (1) {
+ result = open(path, oflag, mode);
+ if ((result != -1) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+#undef read
+int
+TclRead(fd, buf, numBytes)
+ int fd;
+ VOID *buf;
+ size_t numBytes;
+{
+ int result;
+ while (1) {
+ result = read(fd, buf, (size_t) numBytes);
+ if ((result != -1) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+#undef waitpid
+extern pid_t waitpid _ANSI_ARGS_((pid_t pid, int *stat_loc, int options));
+
+/*
+ * Note: the #ifdef below is needed to avoid compiler errors on systems
+ * that have ANSI compilers and also define pid_t to be short. The
+ * problem is a complex one having to do with argument type promotion.
+ */
+
+#ifdef _USING_PROTOTYPES_
+int
+TclWaitpid _ANSI_ARGS_((pid_t pid, int *statPtr, int options))
+#else
+int
+TclWaitpid(pid, statPtr, options)
+ pid_t pid;
+ int *statPtr;
+ int options;
+#endif /* _USING_PROTOTYPES_ */
+{
+ int result;
+ while (1) {
+ result = waitpid(pid, statPtr, options);
+ if ((result != -1) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+#undef write
+int
+TclWrite(fd, buf, numBytes)
+ int fd;
+ VOID *buf;
+ size_t numBytes;
+{
+ int result;
+ while (1) {
+ result = write(fd, buf, (size_t) numBytes);
+ if ((result != -1) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclUtil.c b/vendor/x11iraf/obm/Tcl/tclUtil.c
new file mode 100644
index 00000000..5c3905a9
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclUtil.c
@@ -0,0 +1,1998 @@
+/*
+ * tclUtil.c --
+ *
+ * This file contains utility procedures that are used by many Tcl
+ * commands.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUtil.c,v 1.84 93/10/11 09:18:49 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+/*
+ * The following values are used in the flags returned by Tcl_ScanElement
+ * and used by Tcl_ConvertElement. The value TCL_DONT_USE_BRACES is also
+ * defined in tcl.h; make sure its value doesn't overlap with any of the
+ * values below.
+ *
+ * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in
+ * braces (e.g. it contains unmatched braces,
+ * or ends in a backslash character, or user
+ * just doesn't want braces); handle all
+ * special characters by adding backslashes.
+ * USE_BRACES - 1 means the string contains a special
+ * character that can be handled simply by
+ * enclosing the entire argument in braces.
+ * BRACES_UNMATCHED - 1 means that braces aren't properly matched
+ * in the argument.
+ */
+
+#define USE_BRACES 2
+#define BRACES_UNMATCHED 4
+
+/*
+ * The variable below is set to NULL before invoking regexp functions
+ * and checked after those functions. If an error occurred then TclRegError
+ * will set the variable to point to a (static) error message. This
+ * mechanism unfortunately does not support multi-threading, but then
+ * neither does the rest of the regexp facilities.
+ */
+
+char *tclRegexpError = NULL;
+
+/*
+ * Function prototypes for local procedures in this file:
+ */
+
+static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
+ int newSpace));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclFindElement --
+ *
+ * Given a pointer into a Tcl list, locate the first (or next)
+ * element in the list.
+ *
+ * Results:
+ * The return value is normally TCL_OK, which means that the
+ * element was successfully located. If TCL_ERROR is returned
+ * it means that list didn't have proper list structure;
+ * interp->result contains a more detailed error message.
+ *
+ * If TCL_OK is returned, then *elementPtr will be set to point
+ * to the first element of list, and *nextPtr will be set to point
+ * to the character just after any white space following the last
+ * character that's part of the element. If this is the last argument
+ * in the list, then *nextPtr will point to the NULL character at the
+ * end of list. If sizePtr is non-NULL, *sizePtr is filled in with
+ * the number of characters in the element. If the element is in
+ * braces, then *elementPtr will point to the character after the
+ * opening brace and *sizePtr will not include either of the braces.
+ * If there isn't an element in the list, *sizePtr will be zero, and
+ * both *elementPtr and *termPtr will refer to the null character at
+ * the end of list. Note: this procedure does NOT collapse backslash
+ * sequences.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ register char *list; /* String containing Tcl list with zero
+ * or more elements (possibly in braces). */
+ char **elementPtr; /* Fill in with location of first significant
+ * character in first element of list. */
+ char **nextPtr; /* Fill in with location of character just
+ * after all white space following end of
+ * argument (i.e. next argument or end of
+ * list). */
+ int *sizePtr; /* If non-zero, fill in with size of
+ * element. */
+ int *bracePtr; /* If non-zero fill in with non-zero/zero
+ * to indicate that arg was/wasn't
+ * in braces. */
+{
+ register char *p;
+ int openBraces = 0;
+ int inQuotes = 0;
+ int size;
+
+ /*
+ * Skim off leading white space and check for an opening brace or
+ * quote. Note: use of "isascii" below and elsewhere in this
+ * procedure is a temporary hack (7/27/90) because Mx uses characters
+ * with the high-order bit set for some things. This should probably
+ * be changed back eventually, or all of Tcl should call isascii.
+ */
+
+ while (isspace(UCHAR(*list))) {
+ list++;
+ }
+ if (*list == '{') {
+ openBraces = 1;
+ list++;
+ } else if (*list == '"') {
+ inQuotes = 1;
+ list++;
+ }
+ if (bracePtr != 0) {
+ *bracePtr = openBraces;
+ }
+ p = list;
+
+ /*
+ * Find the end of the element (either a space or a close brace or
+ * the end of the string).
+ */
+
+ while (1) {
+ switch (*p) {
+
+ /*
+ * Open brace: don't treat specially unless the element is
+ * in braces. In this case, keep a nesting count.
+ */
+
+ case '{':
+ if (openBraces != 0) {
+ openBraces++;
+ }
+ break;
+
+ /*
+ * Close brace: if element is in braces, keep nesting
+ * count and quit when the last close brace is seen.
+ */
+
+ case '}':
+ if (openBraces == 1) {
+ char *p2;
+
+ size = p - list;
+ p++;
+ if (isspace(UCHAR(*p)) || (*p == 0)) {
+ goto done;
+ }
+ for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
+ && (p2 < p+20); p2++) {
+ /* null body */
+ }
+ Tcl_ResetResult(interp);
+ sprintf(interp->result,
+ "list element in braces followed by \"%.*s\" instead of space",
+ p2-p, p);
+ return TCL_ERROR;
+ } else if (openBraces != 0) {
+ openBraces--;
+ }
+ break;
+
+ /*
+ * Backslash: skip over everything up to the end of the
+ * backslash sequence.
+ */
+
+ case '\\': {
+ int size;
+
+ (void) Tcl_Backslash(p, &size);
+ p += size - 1;
+ break;
+ }
+
+ /*
+ * Space: ignore if element is in braces or quotes; otherwise
+ * terminate element.
+ */
+
+ case ' ':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ if ((openBraces == 0) && !inQuotes) {
+ size = p - list;
+ goto done;
+ }
+ break;
+
+ /*
+ * Double-quote: if element is in quotes then terminate it.
+ */
+
+ case '"':
+ if (inQuotes) {
+ char *p2;
+
+ size = p-list;
+ p++;
+ if (isspace(UCHAR(*p)) || (*p == 0)) {
+ goto done;
+ }
+ for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
+ && (p2 < p+20); p2++) {
+ /* null body */
+ }
+ Tcl_ResetResult(interp);
+ sprintf(interp->result,
+ "list element in quotes followed by \"%.*s\" %s",
+ p2-p, p, "instead of space");
+ return TCL_ERROR;
+ }
+ break;
+
+ /*
+ * End of list: terminate element.
+ */
+
+ case 0:
+ if (openBraces != 0) {
+ Tcl_SetResult(interp, "unmatched open brace in list",
+ TCL_STATIC);
+ return TCL_ERROR;
+ } else if (inQuotes) {
+ Tcl_SetResult(interp, "unmatched open quote in list",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ size = p - list;
+ goto done;
+
+ }
+ p++;
+ }
+
+ done:
+ while (isspace(UCHAR(*p))) {
+ p++;
+ }
+ *elementPtr = list;
+ *nextPtr = p;
+ if (sizePtr != 0) {
+ *sizePtr = size;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclCopyAndCollapse --
+ *
+ * Copy a string and eliminate any backslashes that aren't in braces.
+ *
+ * Results:
+ * There is no return value. Count chars. get copied from src
+ * to dst. Along the way, if backslash sequences are found outside
+ * braces, the backslashes are eliminated in the copy.
+ * After scanning count chars. from source, a null character is
+ * placed at the end of dst.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclCopyAndCollapse(count, src, dst)
+ int count; /* Total number of characters to copy
+ * from src. */
+ register char *src; /* Copy from here... */
+ register char *dst; /* ... to here. */
+{
+ register char c;
+ int numRead;
+
+ for (c = *src; count > 0; src++, c = *src, count--) {
+ if (c == '\\') {
+ *dst = Tcl_Backslash(src, &numRead);
+ dst++;
+ src += numRead-1;
+ count -= numRead-1;
+ } else {
+ *dst = c;
+ dst++;
+ }
+ }
+ *dst = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SplitList --
+ *
+ * Splits a list up into its constituent fields.
+ *
+ * Results
+ * The return value is normally TCL_OK, which means that
+ * the list was successfully split up. If TCL_ERROR is
+ * returned, it means that "list" didn't have proper list
+ * structure; interp->result will contain a more detailed
+ * error message.
+ *
+ * *argvPtr will be filled in with the address of an array
+ * whose elements point to the elements of list, in order.
+ * *argcPtr will get filled in with the number of valid elements
+ * in the array. A single block of memory is dynamically allocated
+ * to hold both the argv array and a copy of the list (with
+ * backslashes and braces removed in the standard way).
+ * The caller must eventually free this memory by calling free()
+ * on *argvPtr. Note: *argvPtr and *argcPtr are only modified
+ * if the procedure returns normally.
+ *
+ * Side effects:
+ * Memory is allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_SplitList(interp, list, argcPtr, argvPtr)
+ Tcl_Interp *interp; /* Interpreter to use for error reporting. */
+ char *list; /* Pointer to string with list structure. */
+ int *argcPtr; /* Pointer to location to fill in with
+ * the number of elements in the list. */
+ char ***argvPtr; /* Pointer to place to store pointer to array
+ * of pointers to list elements. */
+{
+ char **argv;
+ register char *p;
+ int size, i, result, elSize, brace;
+ char *element;
+
+ /*
+ * Figure out how much space to allocate. There must be enough
+ * space for both the array of pointers and also for a copy of
+ * the list. To estimate the number of pointers needed, count
+ * the number of space characters in the list.
+ */
+
+ for (size = 1, p = list; *p != 0; p++) {
+ if (isspace(UCHAR(*p))) {
+ size++;
+ }
+ }
+ size++; /* Leave space for final NULL pointer. */
+ argv = (char **) ckalloc((unsigned)
+ ((size * sizeof(char *)) + (p - list) + 1));
+ for (i = 0, p = ((char *) argv) + size*sizeof(char *);
+ *list != 0; i++) {
+ result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
+ if (result != TCL_OK) {
+ ckfree((char *) argv);
+ return result;
+ }
+ if (*element == 0) {
+ break;
+ }
+ if (i >= size) {
+ ckfree((char *) argv);
+ Tcl_SetResult(interp, "internal error in Tcl_SplitList",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ argv[i] = p;
+ if (brace) {
+ strncpy(p, element, elSize);
+ p += elSize;
+ *p = 0;
+ p++;
+ } else {
+ TclCopyAndCollapse(elSize, element, p);
+ p += elSize+1;
+ }
+ }
+
+ argv[i] = NULL;
+ *argvPtr = argv;
+ *argcPtr = i;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ScanElement --
+ *
+ * This procedure is a companion procedure to Tcl_ConvertElement.
+ * It scans a string to see what needs to be done to it (e.g.
+ * add backslashes or enclosing braces) to make the string into
+ * a valid Tcl list element.
+ *
+ * Results:
+ * The return value is an overestimate of the number of characters
+ * that will be needed by Tcl_ConvertElement to produce a valid
+ * list element from string. The word at *flagPtr is filled in
+ * with a value needed by Tcl_ConvertElement when doing the actual
+ * conversion.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_ScanElement(string, flagPtr)
+ char *string; /* String to convert to Tcl list element. */
+ int *flagPtr; /* Where to store information to guide
+ * Tcl_ConvertElement. */
+{
+ int flags, nestingLevel;
+ register char *p;
+
+ /*
+ * This procedure and Tcl_ConvertElement together do two things:
+ *
+ * 1. They produce a proper list, one that will yield back the
+ * argument strings when evaluated or when disassembled with
+ * Tcl_SplitList. This is the most important thing.
+ *
+ * 2. They try to produce legible output, which means minimizing the
+ * use of backslashes (using braces instead). However, there are
+ * some situations where backslashes must be used (e.g. an element
+ * like "{abc": the leading brace will have to be backslashed. For
+ * each element, one of three things must be done:
+ *
+ * (a) Use the element as-is (it doesn't contain anything special
+ * characters). This is the most desirable option.
+ *
+ * (b) Enclose the element in braces, but leave the contents alone.
+ * This happens if the element contains embedded space, or if it
+ * contains characters with special interpretation ($, [, ;, or \),
+ * or if it starts with a brace or double-quote, or if there are
+ * no characters in the element.
+ *
+ * (c) Don't enclose the element in braces, but add backslashes to
+ * prevent special interpretation of special characters. This is a
+ * last resort used when the argument would normally fall under case
+ * (b) but contains unmatched braces. It also occurs if the last
+ * character of the argument is a backslash or if the element contains
+ * a backslash followed by newline.
+ *
+ * The procedure figures out how many bytes will be needed to store
+ * the result (actually, it overestimates). It also collects information
+ * about the element in the form of a flags word.
+ */
+
+ nestingLevel = 0;
+ flags = 0;
+ if (string == NULL) {
+ string = "";
+ }
+ p = string;
+ if ((*p == '{') || (*p == '"') || (*p == 0)) {
+ flags |= USE_BRACES;
+ }
+ for ( ; *p != 0; p++) {
+ switch (*p) {
+ case '{':
+ nestingLevel++;
+ break;
+ case '}':
+ nestingLevel--;
+ if (nestingLevel < 0) {
+ flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
+ }
+ break;
+ case '[':
+ case '$':
+ case ';':
+ case ' ':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ flags |= USE_BRACES;
+ break;
+ case '\\':
+ if ((p[1] == 0) || (p[1] == '\n')) {
+ flags = TCL_DONT_USE_BRACES;
+ } else {
+ int size;
+
+ (void) Tcl_Backslash(p, &size);
+ p += size-1;
+ flags |= USE_BRACES;
+ }
+ break;
+ }
+ }
+ if (nestingLevel != 0) {
+ flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
+ }
+ *flagPtr = flags;
+
+ /*
+ * Allow enough space to backslash every character plus leave
+ * two spaces for braces.
+ */
+
+ return 2*(p-string) + 2;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ConvertElement --
+ *
+ * This is a companion procedure to Tcl_ScanElement. Given the
+ * information produced by Tcl_ScanElement, this procedure converts
+ * a string to a list element equal to that string.
+ *
+ * Results:
+ * Information is copied to *dst in the form of a list element
+ * identical to src (i.e. if Tcl_SplitList is applied to dst it
+ * will produce a string identical to src). The return value is
+ * a count of the number of characters copied (not including the
+ * terminating NULL character).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_ConvertElement(src, dst, flags)
+ register char *src; /* Source information for list element. */
+ char *dst; /* Place to put list-ified element. */
+ int flags; /* Flags produced by Tcl_ScanElement. */
+{
+ register char *p = dst;
+
+ /*
+ * See the comment block at the beginning of the Tcl_ScanElement
+ * code for details of how this works.
+ */
+
+ if (src == NULL) {
+ src = "";
+ }
+ if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
+ *p = '{';
+ p++;
+ for ( ; *src != 0; src++, p++) {
+ *p = *src;
+ }
+ *p = '}';
+ p++;
+ } else if (*src == 0) {
+ /*
+ * If string is empty but can't use braces, then use special
+ * backslash sequence that maps to empty string.
+ */
+
+ p[0] = '\\';
+ p[1] = '0';
+ p += 2;
+ } else {
+ if (*src == '{') {
+ /*
+ * Can't have a leading brace unless the whole element is
+ * enclosed in braces. Add a backslash before the brace.
+ * Furthermore, this may destroy the balance between open
+ * and close braces, so set BRACES_UNMATCHED.
+ */
+
+ p[0] = '\\';
+ p[1] = '{';
+ p += 2;
+ src++;
+ flags |= BRACES_UNMATCHED;
+ }
+ for (; *src != 0 ; src++) {
+ switch (*src) {
+ case ']':
+ case '[':
+ case '$':
+ case ';':
+ case ' ':
+ case '\\':
+ case '"':
+ *p = '\\';
+ p++;
+ break;
+ case '{':
+ case '}':
+ /*
+ * It may not seem necessary to backslash braces, but
+ * it is. The reason for this is that the resulting
+ * list element may actually be an element of a sub-list
+ * enclosed in braces (e.g. if Tcl_DStringStartSublist
+ * has been invoked), so there may be a brace mismatch
+ * if the braces aren't backslashed.
+ */
+
+ if (flags & BRACES_UNMATCHED) {
+ *p = '\\';
+ p++;
+ }
+ break;
+ case '\f':
+ *p = '\\';
+ p++;
+ *p = 'f';
+ p++;
+ continue;
+ case '\n':
+ *p = '\\';
+ p++;
+ *p = 'n';
+ p++;
+ continue;
+ case '\r':
+ *p = '\\';
+ p++;
+ *p = 'r';
+ p++;
+ continue;
+ case '\t':
+ *p = '\\';
+ p++;
+ *p = 't';
+ p++;
+ continue;
+ case '\v':
+ *p = '\\';
+ p++;
+ *p = 'v';
+ p++;
+ continue;
+ }
+ *p = *src;
+ p++;
+ }
+ }
+ *p = '\0';
+ return p-dst;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_Merge --
+ *
+ * Given a collection of strings, merge them together into a
+ * single string that has proper Tcl list structured (i.e.
+ * Tcl_SplitList may be used to retrieve strings equal to the
+ * original elements, and Tcl_Eval will parse the string back
+ * into its original elements).
+ *
+ * Results:
+ * The return value is the address of a dynamically-allocated
+ * string containing the merged list.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_Merge(argc, argv)
+ int argc; /* How many strings to merge. */
+ char **argv; /* Array of string values. */
+{
+# define LOCAL_SIZE 20
+ int localFlags[LOCAL_SIZE], *flagPtr;
+ int numChars;
+ char *result;
+ register char *dst;
+ int i;
+
+ /*
+ * Pass 1: estimate space, gather flags.
+ */
+
+ if (argc <= LOCAL_SIZE) {
+ flagPtr = localFlags;
+ } else {
+ flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
+ }
+ numChars = 1;
+ for (i = 0; i < argc; i++) {
+ numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
+ }
+
+ /*
+ * Pass two: copy into the result area.
+ */
+
+ result = (char *) ckalloc((unsigned) numChars);
+ dst = result;
+ for (i = 0; i < argc; i++) {
+ numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
+ dst += numChars;
+ *dst = ' ';
+ dst++;
+ }
+ if (dst == result) {
+ *dst = 0;
+ } else {
+ dst[-1] = 0;
+ }
+
+ if (flagPtr != localFlags) {
+ ckfree((char *) flagPtr);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_Concat --
+ *
+ * Concatenate a set of strings into a single large string.
+ *
+ * Results:
+ * The return value is dynamically-allocated string containing
+ * a concatenation of all the strings in argv, with spaces between
+ * the original argv elements.
+ *
+ * Side effects:
+ * Memory is allocated for the result; the caller is responsible
+ * for freeing the memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_Concat(argc, argv)
+ int argc; /* Number of strings to concatenate. */
+ char **argv; /* Array of strings to concatenate. */
+{
+ int totalSize, i;
+ register char *p;
+ char *result;
+
+ for (totalSize = 1, i = 0; i < argc; i++) {
+ totalSize += strlen(argv[i]) + 1;
+ }
+ result = (char *) ckalloc((unsigned) totalSize);
+ if (argc == 0) {
+ *result = '\0';
+ return result;
+ }
+ for (p = result, i = 0; i < argc; i++) {
+ char *element;
+ int length;
+
+ /*
+ * Clip white space off the front and back of the string
+ * to generate a neater result, and ignore any empty
+ * elements.
+ */
+
+ element = argv[i];
+ while (isspace(UCHAR(*element))) {
+ element++;
+ }
+ for (length = strlen(element);
+ (length > 0) && (isspace(UCHAR(element[length-1])));
+ length--) {
+ /* Null loop body. */
+ }
+ if (length == 0) {
+ continue;
+ }
+ (void) strncpy(p, element, length);
+ p += length;
+ *p = ' ';
+ p++;
+ }
+ if (p != result) {
+ p[-1] = 0;
+ } else {
+ *p = 0;
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_StringMatch --
+ *
+ * See if a particular string matches a particular pattern.
+ *
+ * Results:
+ * The return value is 1 if string matches pattern, and
+ * 0 otherwise. The matching operation permits the following
+ * special characters in the pattern: *?\[] (see the manual
+ * entry for details on what these mean).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_StringMatch(string, pattern)
+ register char *string; /* String. */
+ register char *pattern; /* Pattern, which may contain
+ * special characters. */
+{
+ char c2;
+
+ while (1) {
+ /* See if we're at the end of both the pattern and the string.
+ * If so, we succeeded. If we're at the end of the pattern
+ * but not at the end of the string, we failed.
+ */
+
+ if (*pattern == 0) {
+ if (*string == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ if ((*string == 0) && (*pattern != '*')) {
+ return 0;
+ }
+
+ /* Check for a "*" as the next pattern character. It matches
+ * any substring. We handle this by calling ourselves
+ * recursively for each postfix of string, until either we
+ * match or we reach the end of the string.
+ */
+
+ if (*pattern == '*') {
+ pattern += 1;
+ if (*pattern == 0) {
+ return 1;
+ }
+ while (1) {
+ if (Tcl_StringMatch(string, pattern)) {
+ return 1;
+ }
+ if (*string == 0) {
+ return 0;
+ }
+ string += 1;
+ }
+ }
+
+ /* Check for a "?" as the next pattern character. It matches
+ * any single character.
+ */
+
+ if (*pattern == '?') {
+ goto thisCharOK;
+ }
+
+ /* Check for a "[" as the next pattern character. It is followed
+ * by a list of characters that are acceptable, or by a range
+ * (two characters separated by "-").
+ */
+
+ if (*pattern == '[') {
+ pattern += 1;
+ while (1) {
+ if ((*pattern == ']') || (*pattern == 0)) {
+ return 0;
+ }
+ if (*pattern == *string) {
+ break;
+ }
+ if (pattern[1] == '-') {
+ c2 = pattern[2];
+ if (c2 == 0) {
+ return 0;
+ }
+ if ((*pattern <= *string) && (c2 >= *string)) {
+ break;
+ }
+ if ((*pattern >= *string) && (c2 <= *string)) {
+ break;
+ }
+ pattern += 2;
+ }
+ pattern += 1;
+ }
+ while ((*pattern != ']') && (*pattern != 0)) {
+ pattern += 1;
+ }
+ goto thisCharOK;
+ }
+
+ /* If the next pattern character is '/', just strip off the '/'
+ * so we do exact matching on the character that follows.
+ */
+
+ if (*pattern == '\\') {
+ pattern += 1;
+ if (*pattern == 0) {
+ return 0;
+ }
+ }
+
+ /* There's no special character. Just make sure that the next
+ * characters of each string match.
+ */
+
+ if (*pattern != *string) {
+ return 0;
+ }
+
+ thisCharOK: pattern += 1;
+ string += 1;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetResult --
+ *
+ * Arrange for "string" to be the Tcl return value.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * interp->result is left pointing either to "string" (if "copy" is 0)
+ * or to a copy of string.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_SetResult(interp, string, freeProc)
+ Tcl_Interp *interp; /* Interpreter with which to associate the
+ * return value. */
+ char *string; /* Value to be returned. If NULL,
+ * the result is set to an empty string. */
+ Tcl_FreeProc *freeProc; /* Gives information about the string:
+ * TCL_STATIC, TCL_VOLATILE, or the address
+ * of a Tcl_FreeProc such as free. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int length;
+ Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
+ char *oldResult = iPtr->result;
+
+ iPtr->freeProc = freeProc;
+ if (string == NULL) {
+ iPtr->resultSpace[0] = 0;
+ iPtr->result = iPtr->resultSpace;
+ iPtr->freeProc = 0;
+ } else if (freeProc == TCL_VOLATILE) {
+ length = strlen(string);
+ if (length > TCL_RESULT_SIZE) {
+ iPtr->result = (char *) ckalloc((unsigned) length+1);
+ iPtr->freeProc = (Tcl_FreeProc *) free;
+ } else {
+ iPtr->result = iPtr->resultSpace;
+ iPtr->freeProc = 0;
+ }
+ strcpy(iPtr->result, string);
+ } else {
+ iPtr->result = string;
+ }
+
+ /*
+ * If the old result was dynamically-allocated, free it up. Do it
+ * here, rather than at the beginning, in case the new result value
+ * was part of the old result value.
+ */
+
+ if (oldFreeProc != 0) {
+ if (oldFreeProc == (Tcl_FreeProc *) free) {
+ ckfree(oldResult);
+ } else {
+ (*oldFreeProc)(oldResult);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppendResult --
+ *
+ * Append a variable number of strings onto the result already
+ * present for an interpreter.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The result in the interpreter given by the first argument
+ * is extended by the strings given by the second and following
+ * arguments (up to a terminating NULL argument).
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* VARARGS2 */
+void
+#ifdef USE_STDARG
+Tcl_AppendResult(Tcl_Interp *interp, ...)
+#else
+#ifndef lint
+Tcl_AppendResult(va_alist)
+#else
+void
+ /* VARARGS2 */ /* ARGSUSED */
+Tcl_AppendResult(interp, p, va_alist)
+ Tcl_Interp *interp; /* Interpreter whose result is to be
+ * extended. */
+ char *p; /* One or more strings to add to the
+ * result, terminated with NULL. */
+#endif
+ va_dcl
+#endif
+{
+ va_list argList;
+ Interp *iPtr = (Interp *) interp;
+ char *string;
+ int newSpace;
+
+ /*
+ * First, scan through all the arguments to see how much space is
+ * needed.
+ */
+
+#ifdef USE_STDARG
+ va_start(argList, interp);
+#else
+ va_start(argList);
+ (void) va_arg(argList, Interp *);
+#endif
+ newSpace = 0;
+ while (1) {
+ string = va_arg(argList, char *);
+ if (string == NULL) {
+ break;
+ }
+ newSpace += strlen(string);
+ }
+ va_end(argList);
+
+ /*
+ * If the append buffer isn't already setup and large enough
+ * to hold the new data, set it up.
+ */
+
+ if ((iPtr->result != iPtr->appendResult)
+ || (iPtr->appendResult[iPtr->appendUsed] != 0)
+ || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
+ SetupAppendBuffer(iPtr, newSpace);
+ }
+
+ /*
+ * Final step: go through all the argument strings again, copying
+ * them into the buffer.
+ */
+
+#ifdef USE_STDARG
+ va_start(argList, interp);
+#else
+ va_start(argList);
+ (void) va_arg(argList, Interp *);
+#endif
+ while (1) {
+ string = va_arg(argList, char *);
+ if (string == NULL) {
+ break;
+ }
+ strcpy(iPtr->appendResult + iPtr->appendUsed, string);
+ iPtr->appendUsed += strlen(string);
+ }
+ va_end(argList);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppendElement --
+ *
+ * Convert a string to a valid Tcl list element and append it
+ * to the current result (which is ostensibly a list).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The result in the interpreter given by the first argument
+ * is extended with a list element converted from string. A
+ * separator space is added before the converted list element
+ * unless the current result is empty, contains the single
+ * character "{", or ends in " {".
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AppendElement(interp, string)
+ Tcl_Interp *interp; /* Interpreter whose result is to be
+ * extended. */
+ char *string; /* String to convert to list element and
+ * add to result. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int size, flags;
+ char *dst;
+
+ /*
+ * See how much space is needed, and grow the append buffer if
+ * needed to accommodate the list element.
+ */
+
+ size = Tcl_ScanElement(string, &flags) + 1;
+ if ((iPtr->result != iPtr->appendResult)
+ || (iPtr->appendResult[iPtr->appendUsed] != 0)
+ || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
+ SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
+ }
+
+ /*
+ * Convert the string into a list element and copy it to the
+ * buffer that's forming.
+ */
+
+ dst = iPtr->appendResult + iPtr->appendUsed;
+ if ((iPtr->appendUsed > 0) && ((dst[-1] != '{')
+ || ((iPtr->appendUsed > 1) && (dst[-2] == '\\')))) {
+ iPtr->appendUsed++;
+ *dst = ' ';
+ dst++;
+ }
+ iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SetupAppendBuffer --
+ *
+ * This procedure makes sure that there is an append buffer
+ * properly initialized for interp, and that it has at least
+ * enough room to accommodate newSpace new bytes of information.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+SetupAppendBuffer(iPtr, newSpace)
+ register Interp *iPtr; /* Interpreter whose result is being set up. */
+ int newSpace; /* Make sure that at least this many bytes
+ * of new information may be added. */
+{
+ int totalSpace;
+
+ /*
+ * Make the append buffer larger, if that's necessary, then
+ * copy the current result into the append buffer and make the
+ * append buffer the official Tcl result.
+ */
+
+ if (iPtr->result != iPtr->appendResult) {
+ /*
+ * If an oversized buffer was used recently, then free it up
+ * so we go back to a smaller buffer. This avoids tying up
+ * memory forever after a large operation.
+ */
+
+ if (iPtr->appendAvl > 500) {
+ ckfree(iPtr->appendResult);
+ iPtr->appendResult = NULL;
+ iPtr->appendAvl = 0;
+ }
+ iPtr->appendUsed = strlen(iPtr->result);
+ } else if (iPtr->result[iPtr->appendUsed] != 0) {
+ /*
+ * Most likely someone has modified a result created by
+ * Tcl_AppendResult et al. so that it has a different size.
+ * Just recompute the size.
+ */
+
+ iPtr->appendUsed = strlen(iPtr->result);
+ }
+ totalSpace = newSpace + iPtr->appendUsed;
+ if (totalSpace >= iPtr->appendAvl) {
+ char *new;
+
+ if (totalSpace < 100) {
+ totalSpace = 200;
+ } else {
+ totalSpace *= 2;
+ }
+ new = (char *) ckalloc((unsigned) totalSpace);
+ strcpy(new, iPtr->result);
+ if (iPtr->appendResult != NULL) {
+ ckfree(iPtr->appendResult);
+ }
+ iPtr->appendResult = new;
+ iPtr->appendAvl = totalSpace;
+ } else if (iPtr->result != iPtr->appendResult) {
+ strcpy(iPtr->appendResult, iPtr->result);
+ }
+ Tcl_FreeResult(iPtr);
+ iPtr->result = iPtr->appendResult;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ResetResult --
+ *
+ * This procedure restores the result area for an interpreter
+ * to its default initialized state, freeing up any memory that
+ * may have been allocated for the result and clearing any
+ * error information for the interpreter.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_ResetResult(interp)
+ Tcl_Interp *interp; /* Interpreter for which to clear result. */
+{
+ register Interp *iPtr = (Interp *) interp;
+
+ Tcl_FreeResult(iPtr);
+ iPtr->result = iPtr->resultSpace;
+ iPtr->resultSpace[0] = 0;
+ iPtr->flags &=
+ ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetErrorCode --
+ *
+ * This procedure is called to record machine-readable information
+ * about an error that is about to be returned.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The errorCode global variable is modified to hold all of the
+ * arguments to this procedure, in a list form with each argument
+ * becoming one element of the list. A flag is set internally
+ * to remember that errorCode has been set, so the variable doesn't
+ * get set automatically when the error is returned.
+ *
+ *----------------------------------------------------------------------
+ */
+ /* VARARGS2 */
+void
+#ifdef USE_STDARG
+Tcl_SetErrorCode(Tcl_Interp *interp, ...)
+#else
+#ifndef lint
+Tcl_SetErrorCode(va_alist)
+#else
+void
+ /* VARARGS2 */ /* ARGSUSED */
+Tcl_SetErrorCode(interp, p, va_alist)
+ Tcl_Interp *interp; /* Interpreter whose errorCode variable is
+ * to be set. */
+ char *p; /* One or more elements to add to errorCode,
+ * terminated with NULL. */
+#endif
+ va_dcl
+#endif
+{
+ va_list argList;
+ char *string;
+ int flags;
+ Interp *iPtr = (Interp *)interp;
+
+ /*
+ * Scan through the arguments one at a time, appending them to
+ * $errorCode as list elements.
+ */
+
+#ifdef USE_STDARG
+ va_start(argList, interp);
+#else
+ va_start(argList);
+#endif
+ (void) va_arg(argList, Tcl_Interp *);
+ flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
+ while (1) {
+ string = va_arg(argList, char *);
+ if (string == NULL) {
+ break;
+ }
+ (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
+ (char *) NULL, string, flags);
+ flags |= TCL_APPEND_VALUE;
+ }
+ va_end(argList);
+ iPtr->flags |= ERROR_CODE_SET;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGetListIndex --
+ *
+ * Parse a list index, which may be either an integer or the
+ * value "end".
+ *
+ * Results:
+ * The return value is either TCL_OK or TCL_ERROR. If it is
+ * TCL_OK, then the index corresponding to string is left in
+ * *indexPtr. If the return value is TCL_ERROR, then string
+ * was bogus; an error message is returned in interp->result.
+ * If a negative index is specified, it is rounded up to 0.
+ * The index value may be larger than the size of the list
+ * (this happens when "end" is specified).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclGetListIndex(interp, string, indexPtr)
+ Tcl_Interp *interp; /* Interpreter for error reporting. */
+ char *string; /* String containing list index. */
+ int *indexPtr; /* Where to store index. */
+{
+ if (isdigit(UCHAR(*string)) || (*string == '-')) {
+ if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (*indexPtr < 0) {
+ *indexPtr = 0;
+ }
+ } else if (strncmp(string, "end", strlen(string)) == 0) {
+ *indexPtr = 1<<30;
+ } else {
+ Tcl_AppendResult(interp, "bad index \"", string,
+ "\": must be integer or \"end\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclCompileRegexp --
+ *
+ * Compile a regular expression into a form suitable for fast
+ * matching. This procedure retains a small cache of pre-compiled
+ * regular expressions in the interpreter, in order to avoid
+ * compilation costs as much as possible.
+ *
+ * Results:
+ * The return value is a pointer to the compiled form of string,
+ * suitable for passing to TclRegExec. If an error occurred while
+ * compiling the pattern, then NULL is returned and an error
+ * message is left in interp->result.
+ *
+ * Side effects:
+ * The cache of compiled regexp's in interp will be modified to
+ * hold information for string, if such information isn't already
+ * present in the cache.
+ *
+ *----------------------------------------------------------------------
+ */
+
+regexp *
+TclCompileRegexp(interp, string)
+ Tcl_Interp *interp; /* For use in error reporting. */
+ char *string; /* String for which to produce
+ * compiled regular expression. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int i, length;
+ regexp *result;
+
+ length = strlen(string);
+ for (i = 0; i < NUM_REGEXPS; i++) {
+ if ((length == iPtr->patLengths[i])
+ && (strcmp(string, iPtr->patterns[i]) == 0)) {
+ /*
+ * Move the matched pattern to the first slot in the
+ * cache and shift the other patterns down one position.
+ */
+
+ if (i != 0) {
+ int j;
+ char *cachedString;
+
+ cachedString = iPtr->patterns[i];
+ result = iPtr->regexps[i];
+ for (j = i-1; j >= 0; j--) {
+ iPtr->patterns[j+1] = iPtr->patterns[j];
+ iPtr->patLengths[j+1] = iPtr->patLengths[j];
+ iPtr->regexps[j+1] = iPtr->regexps[j];
+ }
+ iPtr->patterns[0] = cachedString;
+ iPtr->patLengths[0] = length;
+ iPtr->regexps[0] = result;
+ }
+ return iPtr->regexps[0];
+ }
+ }
+
+ /*
+ * No match in the cache. Compile the string and add it to the
+ * cache.
+ */
+
+ tclRegexpError = NULL;
+ result = TclRegComp(string);
+ if (tclRegexpError != NULL) {
+ Tcl_AppendResult(interp,
+ "couldn't compile regular expression pattern: ",
+ tclRegexpError, (char *) NULL);
+ return NULL;
+ }
+ if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
+ ckfree(iPtr->patterns[NUM_REGEXPS-1]);
+ ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
+ }
+ for (i = NUM_REGEXPS - 2; i >= 0; i--) {
+ iPtr->patterns[i+1] = iPtr->patterns[i];
+ iPtr->patLengths[i+1] = iPtr->patLengths[i];
+ iPtr->regexps[i+1] = iPtr->regexps[i];
+ }
+ iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
+ strcpy(iPtr->patterns[0], string);
+ iPtr->patLengths[0] = length;
+ iPtr->regexps[0] = result;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclRegError --
+ *
+ * This procedure is invoked by the Henry Spencer's regexp code
+ * when an error occurs. It saves the error message so it can
+ * be seen by the code that called Spencer's code.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The value of "string" is saved in "tclRegexpError".
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclRegError(string)
+ char *string; /* Error message. */
+{
+ tclRegexpError = string;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RegExpMatch --
+ *
+ * See if a string matches a regular expression.
+ *
+ * Results:
+ * If an error occurs during the matching operation then -1
+ * is returned and interp->result contains an error message.
+ * Otherwise the return value is 1 if "string" matches "pattern"
+ * and 0 otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_RegExpMatch(interp, string, pattern)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ char *string; /* String. */
+ char *pattern; /* Regular expression to match against
+ * string. */
+{
+ regexp *regexpPtr;
+ int match;
+
+ regexpPtr = TclCompileRegexp(interp, pattern);
+ if (regexpPtr == NULL) {
+ return -1;
+ }
+ tclRegexpError = NULL;
+ match = TclRegExec(regexpPtr, string, string);
+ if (tclRegexpError != NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "error while matching regular expression: ",
+ tclRegexpError, (char *) NULL);
+ return -1;
+ }
+ return match;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringInit --
+ *
+ * Initializes a dynamic string, discarding any previous contents
+ * of the string (Tcl_DStringFree should have been called already
+ * if the dynamic string was previously in use).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The dynamic string is initialized to be empty.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringInit(dsPtr)
+ register Tcl_DString *dsPtr; /* Pointer to structure for
+ * dynamic string. */
+{
+ dsPtr->string = dsPtr->staticSpace;
+ dsPtr->length = 0;
+ dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
+ dsPtr->staticSpace[0] = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringAppend --
+ *
+ * Append more characters to the current value of a dynamic string.
+ *
+ * Results:
+ * The return value is a pointer to the dynamic string's new value.
+ *
+ * Side effects:
+ * Length bytes from string (or all of string if length is less
+ * than zero) are added to the current value of the string. Memory
+ * gets reallocated if needed to accomodate the string's new size.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_DStringAppend(dsPtr, string, length)
+ register Tcl_DString *dsPtr; /* Structure describing dynamic
+ * string. */
+ char *string; /* String to append. If length is
+ * -1 then this must be
+ * null-terminated. */
+ int length; /* Number of characters from string
+ * to append. If < 0, then append all
+ * of string, up to null at end. */
+{
+ int newSize;
+ char *newString;
+
+ if (length < 0) {
+ length = strlen(string);
+ }
+ newSize = length + dsPtr->length;
+
+ /*
+ * Allocate a larger buffer for the string if the current one isn't
+ * large enough. Allocate extra space in the new buffer so that there
+ * will be room to grow before we have to allocate again.
+ */
+
+ if (newSize >= dsPtr->spaceAvl) {
+ dsPtr->spaceAvl = newSize*2;
+ newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
+ strcpy(newString, dsPtr->string);
+ if (dsPtr->string != dsPtr->staticSpace) {
+ ckfree(dsPtr->string);
+ }
+ dsPtr->string = newString;
+ }
+
+ /*
+ * Copy the new string into the buffer at the end of the old
+ * one.
+ */
+
+ strncpy(dsPtr->string + dsPtr->length, string, length);
+ dsPtr->length += length;
+ dsPtr->string[dsPtr->length] = 0;
+ return dsPtr->string;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringAppendElement --
+ *
+ * Append a list element to the current value of a dynamic string.
+ *
+ * Results:
+ * The return value is a pointer to the dynamic string's new value.
+ *
+ * Side effects:
+ * String is reformatted as a list element and added to the current
+ * value of the string. Memory gets reallocated if needed to
+ * accomodate the string's new size.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_DStringAppendElement(dsPtr, string)
+ register Tcl_DString *dsPtr; /* Structure describing dynamic
+ * string. */
+ char *string; /* String to append. Must be
+ * null-terminated. */
+{
+ int newSize, flags;
+ char *dst, *newString;
+
+ newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
+
+ /*
+ * Allocate a larger buffer for the string if the current one isn't
+ * large enough. Allocate extra space in the new buffer so that there
+ * will be room to grow before we have to allocate again.
+ */
+
+ if (newSize >= dsPtr->spaceAvl) {
+ dsPtr->spaceAvl = newSize*2;
+ newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
+ strcpy(newString, dsPtr->string);
+ if (dsPtr->string != dsPtr->staticSpace) {
+ ckfree(dsPtr->string);
+ }
+ dsPtr->string = newString;
+ }
+
+ /*
+ * Convert the new string to a list element and copy it into the
+ * buffer at the end. Add a space separator unless we're at the
+ * start of the string or just after an unbackslashed "{".
+ */
+
+ dst = dsPtr->string + dsPtr->length;
+ if ((dsPtr->length > 0) && ((dst[-1] != '{')
+ || ((dsPtr->length > 1) && (dst[-2] == '\\')))) {
+ *dst = ' ';
+ dst++;
+ dsPtr->length++;
+ }
+ dsPtr->length += Tcl_ConvertElement(string, dst, flags);
+ return dsPtr->string;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringTrunc --
+ *
+ * Truncate a dynamic string to a given length without freeing
+ * up its storage.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The length of dsPtr is reduced to length unless it was already
+ * shorter than that.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringTrunc(dsPtr, length)
+ register Tcl_DString *dsPtr; /* Structure describing dynamic
+ * string. */
+ int length; /* New length for dynamic string. */
+{
+ if (length < 0) {
+ length = 0;
+ }
+ if (length < dsPtr->length) {
+ dsPtr->length = length;
+ dsPtr->string[length] = 0;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringFree --
+ *
+ * Frees up any memory allocated for the dynamic string and
+ * reinitializes the string to an empty state.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The previous contents of the dynamic string are lost, and
+ * the new value is an empty string.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringFree(dsPtr)
+ register Tcl_DString *dsPtr; /* Structure describing dynamic
+ * string. */
+{
+ if (dsPtr->string != dsPtr->staticSpace) {
+ ckfree(dsPtr->string);
+ }
+ dsPtr->string = dsPtr->staticSpace;
+ dsPtr->length = 0;
+ dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
+ dsPtr->staticSpace[0] = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringResult --
+ *
+ * This procedure moves the value of a dynamic string into an
+ * interpreter as its result. The string itself is reinitialized
+ * to an empty string.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The string is "moved" to interp's result, and any existing
+ * result for interp is freed up. DsPtr is reinitialized to
+ * an empty string.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringResult(interp, dsPtr)
+ Tcl_Interp *interp; /* Interpreter whose result is to be
+ * reset. */
+ Tcl_DString *dsPtr; /* Dynamic string that is to become
+ * the result of interp. */
+{
+ Tcl_FreeResult(interp);
+ if (dsPtr->string != dsPtr->staticSpace) {
+ interp->result = dsPtr->string;
+ interp->freeProc = (Tcl_FreeProc *) free;
+ } else if (dsPtr->length < TCL_RESULT_SIZE) {
+ strcpy(interp->result, dsPtr->string);
+ } else {
+ Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
+ }
+ dsPtr->string = dsPtr->staticSpace;
+ dsPtr->length = 0;
+ dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
+ dsPtr->staticSpace[0] = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringStartSublist --
+ *
+ * This procedure adds the necessary information to a dynamic
+ * string (e.g. " {" to start a sublist. Future element
+ * appends will be in the sublist rather than the main list.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Characters get added to the dynamic string.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringStartSublist(dsPtr)
+ Tcl_DString *dsPtr; /* Dynamic string. */
+{
+ if ((dsPtr->length == 0)
+ || ((dsPtr->length == 1) && (dsPtr->string[0] == '{'))
+ || ((dsPtr->length > 1) && (dsPtr->string[dsPtr->length-1] == '{')
+ && (dsPtr->string[dsPtr->length-2] != '\\'))) {
+ Tcl_DStringAppend(dsPtr, "{", -1);
+ } else {
+ Tcl_DStringAppend(dsPtr, " {", -1);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DStringEndSublist --
+ *
+ * This procedure adds the necessary characters to a dynamic
+ * string to end a sublist (e.g. "}"). Future element appends
+ * will be in the enclosing (sub)list rather than the current
+ * sublist.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DStringEndSublist(dsPtr)
+ Tcl_DString *dsPtr; /* Dynamic string. */
+{
+ Tcl_DStringAppend(dsPtr, "}", -1);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_PrintDouble --
+ *
+ * Given a floating-point value, this procedure converts it to
+ * an ASCII string using.
+ *
+ * Results:
+ * The ASCII equivalent of "value" is written at "dst". It is
+ * written using the current precision, and it is guaranteed to
+ * contain a decimal point or exponent, so that it looks like
+ * a floating-point value and not an integer.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_PrintDouble(interp, value, dst)
+ Tcl_Interp *interp; /* Interpreter whose tcl_precision
+ * variable controls printing. */
+ double value; /* Value to print as string. */
+ char *dst; /* Where to store converted value;
+ * must have at least TCL_DOUBLE_SPACE
+ * characters. */
+{
+ register char *p;
+ sprintf(dst, ((Interp *) interp)->pdFormat, value);
+
+ /*
+ * If the ASCII result looks like an integer, add ".0" so that it
+ * doesn't look like an integer anymore. This prevents floating-point
+ * values from being converted to integers unintentionally.
+ */
+
+ for (p = dst; *p != 0; p++) {
+ if ((*p == '.') || (isalpha(UCHAR(*p)))) {
+ return;
+ }
+ }
+ p[0] = '.';
+ p[1] = '0';
+ p[2] = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclPrecTraceProc --
+ *
+ * This procedure is invoked whenever the variable "tcl_precision"
+ * is written.
+ *
+ * Results:
+ * Returns NULL if all went well, or an error message if the
+ * new value for the variable doesn't make sense.
+ *
+ * Side effects:
+ * If the new value doesn't make sense then this procedure
+ * undoes the effect of the variable modification. Otherwise
+ * it modifies the format string that's used by Tcl_PrintDouble.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+char *
+TclPrecTraceProc(clientData, interp, name1, name2, flags)
+ ClientData clientData; /* Not used. */
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ char *name1; /* Name of variable. */
+ char *name2; /* Second part of variable name. */
+ int flags; /* Information about what happened. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ char *value, *end;
+ int prec;
+
+ /*
+ * If the variable is unset, then recreate the trace and restore
+ * the default value of the format string.
+ */
+
+ if (flags & TCL_TRACE_UNSETS) {
+ if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ Tcl_TraceVar2(interp, name1, name2,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ TclPrecTraceProc, clientData);
+ }
+ strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
+ iPtr->pdPrec = DEFAULT_PD_PREC;
+ return (char *) NULL;
+ }
+
+ value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
+ if (value == NULL) {
+ value = "";
+ }
+ prec = strtoul(value, &end, 10);
+ if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
+ (end == value) || (*end != 0)) {
+ char oldValue[10];
+
+ sprintf(oldValue, "%d", iPtr->pdPrec);
+ Tcl_SetVar2(interp, name1, name2, oldValue, flags & TCL_GLOBAL_ONLY);
+ return "improper value for precision";
+ }
+ sprintf(iPtr->pdFormat, "%%.%dg", prec);
+ iPtr->pdPrec = prec;
+ return (char *) NULL;
+}
diff --git a/vendor/x11iraf/obm/Tcl/tclVar.c b/vendor/x11iraf/obm/Tcl/tclVar.c
new file mode 100644
index 00000000..8981cef7
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tclVar.c
@@ -0,0 +1,2363 @@
+/*
+ * tclVar.c --
+ *
+ * This file contains routines that implement Tcl variables
+ * (both scalars and arrays).
+ *
+ * The implementation of arrays is modelled after an initial
+ * implementation by Mark Diekhans and Karl Lehenbauer.
+ *
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclVar.c,v 1.44 93/08/14 17:21:34 ouster Exp $ SPRITE (Berkeley)";
+#endif
+
+#include "tclInt.h"
+
+/*
+ * The strings below are used to indicate what went wrong when a
+ * variable access is denied.
+ */
+
+static char *noSuchVar = "no such variable";
+static char *isArray = "variable is array";
+static char *needArray = "variable isn't array";
+static char *noSuchElement = "no such element in array";
+static char *danglingUpvar = "upvar refers to element in deleted array";
+
+/*
+ * Creation flag values passed in to LookupVar:
+ *
+ * CRT_PART1 - 1 means create hash table entry for part 1 of
+ * name, if it doesn't already exist. 0 means
+ * return an error if it doesn't exist.
+ * CRT_PART2 - 1 means create hash table entry for part 2 of
+ * name, if it doesn't already exist. 0 means
+ * return an error if it doesn't exist.
+ */
+
+#define CRT_PART1 1
+#define CRT_PART2 2
+
+/*
+ * Forward references to procedures defined later in this file:
+ */
+
+static char * CallTraces _ANSI_ARGS_((Interp *iPtr, Var *arrayPtr,
+ Var *varPtr, char *part1, char *part2,
+ int flags));
+static void CleanupVar _ANSI_ARGS_((Var *varPtr, Var *arrayPtr));
+static void DeleteSearches _ANSI_ARGS_((Var *arrayVarPtr));
+static void DeleteArray _ANSI_ARGS_((Interp *iPtr, char *arrayName,
+ Var *varPtr, int flags));
+static Var * LookupVar _ANSI_ARGS_((Tcl_Interp *interp, char *part1,
+ char *part2, int flags, char *msg, int create,
+ Var **arrayPtrPtr));
+static int MakeUpvar _ANSI_ARGS_((Interp *iPtr,
+ CallFrame *framePtr, char *otherP1,
+ char *otherP2, char *myName));
+static Var * NewVar _ANSI_ARGS_((void));
+static ArraySearch * ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
+ Var *varPtr, char *varName, char *string));
+static void VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp,
+ char *part1, char *part2, char *operation,
+ char *reason));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * LookupVar --
+ *
+ * This procedure is used by virtually all of the variable
+ * code to locate a variable given its name(s).
+ *
+ * Results:
+ * The return value is a pointer to the variable indicated by
+ * part1 and part2, or NULL if the variable couldn't be found.
+ * If the variable is found, *arrayPtrPtr is filled in with
+ * the address of the array that contains the variable (or NULL
+ * if the variable is a scalar). Note: it's possible that the
+ * variable returned may be VAR_UNDEFINED, even if CRT_PART1 and
+ * CRT_PART2 are specified (these only cause the hash table entry
+ * and/or array to be created).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Var *
+LookupVar(interp, part1, part2, flags, msg, create, arrayPtrPtr)
+ Tcl_Interp *interp; /* Interpreter to use for lookup. */
+ char *part1; /* If part2 is NULL, this is name of scalar
+ * variable. Otherwise it is name of array. */
+ char *part2; /* Name of an element within array, or NULL. */
+ int flags; /* Only the TCL_GLOBAL_ONLY and
+ * TCL_LEAVE_ERR_MSG bits matter. */
+ char *msg; /* Verb to use in error messages, e.g.
+ * "read" or "set". Only needed if
+ * TCL_LEAVE_ERR_MSG is set in flags. */
+ int create; /* OR'ed combination of CRT_PART1 and
+ * CRT_PART2. Tells which entries to create
+ * if they don't already exist. */
+ Var **arrayPtrPtr; /* If part2 is non-NULL, *arrayPtrPtr gets
+ * filled in with address of array variable. */
+{
+ Interp *iPtr = (Interp *) interp;
+ Tcl_HashTable *tablePtr;
+ Tcl_HashEntry *hPtr;
+ Var *varPtr;
+ int new;
+
+ /*
+ * Lookup part1.
+ */
+
+ *arrayPtrPtr = NULL;
+ if ((flags & TCL_GLOBAL_ONLY) || (iPtr->varFramePtr == NULL)) {
+ tablePtr = &iPtr->globalTable;
+ } else {
+ tablePtr = &iPtr->varFramePtr->varTable;
+ }
+ if (create & CRT_PART1) {
+ hPtr = Tcl_CreateHashEntry(tablePtr, part1, &new);
+ if (new) {
+ varPtr = NewVar();
+ Tcl_SetHashValue(hPtr, varPtr);
+ varPtr->hPtr = hPtr;
+ }
+ } else {
+ hPtr = Tcl_FindHashEntry(tablePtr, part1);
+ if (hPtr == NULL) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, msg, noSuchVar);
+ }
+ return NULL;
+ }
+ }
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UPVAR) {
+ varPtr = varPtr->value.upvarPtr;
+ }
+
+ if (part2 == NULL) {
+ return varPtr;
+ }
+
+ /*
+ * We're dealing with an array element, so make sure the variable
+ * is an array and lookup the element (create it if desired).
+ */
+
+ if (varPtr->flags & VAR_UNDEFINED) {
+ if (!(create & CRT_PART1)) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, msg, noSuchVar);
+ }
+ return NULL;
+ }
+ varPtr->flags = VAR_ARRAY;
+ varPtr->value.tablePtr = (Tcl_HashTable *)
+ ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
+ } else if (!(varPtr->flags & VAR_ARRAY)) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, msg, needArray);
+ }
+ return NULL;
+ }
+ *arrayPtrPtr = varPtr;
+ if (create & CRT_PART2) {
+ hPtr = Tcl_CreateHashEntry(varPtr->value.tablePtr, part2, &new);
+ if (new) {
+ if (varPtr->searchPtr != NULL) {
+ DeleteSearches(varPtr);
+ }
+ varPtr = NewVar();
+ Tcl_SetHashValue(hPtr, varPtr);
+ varPtr->hPtr = hPtr;
+ }
+ } else {
+ hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, part2);
+ if (hPtr == NULL) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, msg, noSuchElement);
+ }
+ return NULL;
+ }
+ }
+ return (Var *) Tcl_GetHashValue(hPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetVar --
+ *
+ * Return the value of a Tcl variable.
+ *
+ * Results:
+ * The return value points to the current value of varName. If
+ * the variable is not defined or can't be read because of a clash
+ * in array usage then a NULL pointer is returned and an error
+ * message is left in interp->result if the TCL_LEAVE_ERR_MSG
+ * flag is set. Note: the return value is only valid up until
+ * the next call to Tcl_SetVar or Tcl_SetVar2; if you depend on
+ * the value lasting longer than that, then make yourself a private
+ * copy.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_GetVar(interp, varName, flags)
+ Tcl_Interp *interp; /* Command interpreter in which varName is
+ * to be looked up. */
+ char *varName; /* Name of a variable in interp. */
+ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY
+ * or TCL_LEAVE_ERR_MSG bits. */
+{
+ register char *p;
+
+ /*
+ * If varName refers to an array (it ends with a parenthesized
+ * element name), then handle it specially.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ char *result;
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = Tcl_GetVar2(interp, varName, open+1, flags);
+ *open = '(';
+ *p = ')';
+ return result;
+ }
+ }
+
+ scalar:
+ return Tcl_GetVar2(interp, varName, (char *) NULL, flags);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetVar2 --
+ *
+ * Return the value of a Tcl variable, given a two-part name
+ * consisting of array name and element within array.
+ *
+ * Results:
+ * The return value points to the current value of the variable
+ * given by part1 and part2. If the specified variable doesn't
+ * exist, or if there is a clash in array usage, then NULL is
+ * returned and a message will be left in interp->result if the
+ * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is
+ * only valid up until the next call to Tcl_SetVar or Tcl_SetVar2;
+ * if you depend on the value lasting longer than that, then make
+ * yourself a private copy.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_GetVar2(interp, part1, part2, flags)
+ Tcl_Interp *interp; /* Command interpreter in which variable is
+ * to be looked up. */
+ char *part1; /* Name of array (if part2 is NULL) or
+ * name of variable. */
+ char *part2; /* If non-null, gives name of element in
+ * array. */
+ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY
+ * or TCL_LEAVE_ERR_MSG bits. */
+{
+ Var *varPtr, *arrayPtr;
+ Interp *iPtr = (Interp *) interp;
+
+ varPtr = LookupVar(interp, part1, part2, flags, "read", CRT_PART2,
+ &arrayPtr);
+ if (varPtr == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Invoke any traces that have been set for the variable.
+ */
+
+ if ((varPtr->tracePtr != NULL)
+ || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+ char *msg;
+
+ msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
+ (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_READS);
+ if (msg != NULL) {
+ VarErrMsg(interp, part1, part2, "read", msg);
+ goto cleanup;
+ }
+ }
+ if (!(varPtr->flags & (VAR_UNDEFINED|VAR_UPVAR|VAR_ARRAY))) {
+ return varPtr->value.string;
+ }
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ char *msg;
+
+ if ((varPtr->flags & VAR_UNDEFINED) && (arrayPtr != NULL)
+ && !(arrayPtr->flags & VAR_UNDEFINED)) {
+ msg = noSuchElement;
+ } else {
+ msg = noSuchVar;
+ }
+ VarErrMsg(interp, part1, part2, "read", msg);
+ }
+
+ /*
+ * If the variable doesn't exist anymore and no-one's using it,
+ * then free up the relevant structures and hash table entries.
+ */
+
+ cleanup:
+ if (varPtr->flags & VAR_UNDEFINED) {
+ CleanupVar(varPtr, arrayPtr);
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetVar --
+ *
+ * Change the value of a variable.
+ *
+ * Results:
+ * Returns a pointer to the malloc'ed string holding the new
+ * value of the variable. The caller should not modify this
+ * string. If the write operation was disallowed then NULL
+ * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
+ * an explanatory message will be left in interp->result.
+ *
+ * Side effects:
+ * If varName is defined as a local or global variable in interp,
+ * its value is changed to newValue. If varName isn't currently
+ * defined, then a new global variable by that name is created.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SetVar(interp, varName, newValue, flags)
+ Tcl_Interp *interp; /* Command interpreter in which varName is
+ * to be looked up. */
+ char *varName; /* Name of a variable in interp. */
+ char *newValue; /* New value for varName. */
+ int flags; /* Various flags that tell how to set value:
+ * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
+ * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG. */
+{
+ register char *p;
+
+ /*
+ * If varName refers to an array (it ends with a parenthesized
+ * element name), then handle it specially.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ char *result;
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = Tcl_SetVar2(interp, varName, open+1, newValue, flags);
+ *open = '(';
+ *p = ')';
+ return result;
+ }
+ }
+
+ scalar:
+ return Tcl_SetVar2(interp, varName, (char *) NULL, newValue, flags);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetVar2 --
+ *
+ * Given a two-part variable name, which may refer either to a
+ * scalar variable or an element of an array, change the value
+ * of the variable. If the named scalar or array or element
+ * doesn't exist then create one.
+ *
+ * Results:
+ * Returns a pointer to the malloc'ed string holding the new
+ * value of the variable. The caller should not modify this
+ * string. If the write operation was disallowed because an
+ * array was expected but not found (or vice versa), then NULL
+ * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then
+ * an explanatory message will be left in interp->result.
+ *
+ * Side effects:
+ * The value of the given variable is set. If either the array
+ * or the entry didn't exist then a new one is created.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Tcl_SetVar2(interp, part1, part2, newValue, flags)
+ Tcl_Interp *interp; /* Command interpreter in which variable is
+ * to be looked up. */
+ char *part1; /* If part2 is NULL, this is name of scalar
+ * variable. Otherwise it is name of array. */
+ char *part2; /* Name of an element within array, or NULL. */
+ char *newValue; /* New value for variable. */
+ int flags; /* Various flags that tell how to set value:
+ * any of TCL_GLOBAL_ONLY, TCL_APPEND_VALUE,
+ * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG . */
+{
+ register Var *varPtr;
+ register Interp *iPtr = (Interp *) interp;
+ int length, listFlags;
+ Var *arrayPtr;
+ char *result;
+
+ varPtr = LookupVar(interp, part1, part2, flags, "set", CRT_PART1|CRT_PART2,
+ &arrayPtr);
+ if (varPtr == NULL) {
+ return NULL;
+ }
+
+ /*
+ * If the variable's hPtr field is NULL, it means that this is an
+ * upvar to an array element where the array was deleted, leaving
+ * the element dangling at the end of the upvar. Generate an error
+ * (allowing the variable to be reset would screw up our storage
+ * allocation and is meaningless anyway).
+ */
+
+ if (varPtr->hPtr == NULL) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, "set", danglingUpvar);
+ }
+ return NULL;
+ }
+
+ /*
+ * Clear the variable's current value unless this is an
+ * append operation.
+ */
+
+ if (varPtr->flags & VAR_ARRAY) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, "set", isArray);
+ }
+ return NULL;
+ }
+ if (!(flags & TCL_APPEND_VALUE) || (varPtr->flags & VAR_UNDEFINED)) {
+ varPtr->valueLength = 0;
+ }
+
+ /*
+ * Compute how many total bytes will be needed for the variable's
+ * new value (leave space for a separating space between list
+ * elements). Allocate new space for the value if needed.
+ */
+
+ if (flags & TCL_LIST_ELEMENT) {
+ length = Tcl_ScanElement(newValue, &listFlags) + 1;
+ } else {
+ length = strlen(newValue);
+ }
+ length += varPtr->valueLength;
+ if (length >= varPtr->valueSpace) {
+ char *newValue;
+ int newSize;
+
+ newSize = 2*varPtr->valueSpace;
+ if (newSize <= length) {
+ newSize = length + 1;
+ }
+ if (newSize < 24) {
+ /*
+ * Don't waste time with teensy-tiny variables; we'll
+ * just end up expanding them later.
+ */
+
+ newSize = 24;
+ }
+ newValue = ckalloc((unsigned) newSize);
+ if (varPtr->valueSpace > 0) {
+ strcpy(newValue, varPtr->value.string);
+ ckfree(varPtr->value.string);
+ }
+ varPtr->valueSpace = newSize;
+ varPtr->value.string = newValue;
+ }
+
+ /*
+ * Append the new value to the variable, either as a list
+ * element or as a string.
+ */
+
+ if (flags & TCL_LIST_ELEMENT) {
+ char *dst = varPtr->value.string + varPtr->valueLength;
+
+ if ((varPtr->valueLength > 0) && ((dst[-1] != '{')
+ || ((varPtr->valueLength > 1) && (dst[-2] == '\\')))) {
+ *dst = ' ';
+ dst++;
+ varPtr->valueLength++;
+ }
+ varPtr->valueLength += Tcl_ConvertElement(newValue, dst, listFlags);
+ } else {
+ strcpy(varPtr->value.string + varPtr->valueLength, newValue);
+ varPtr->valueLength = length;
+ }
+ varPtr->flags &= ~VAR_UNDEFINED;
+
+ /*
+ * Invoke any write traces for the variable.
+ */
+
+ if ((varPtr->tracePtr != NULL)
+ || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+ char *msg;
+
+ msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
+ (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_WRITES);
+ if (msg != NULL) {
+ VarErrMsg(interp, part1, part2, "set", msg);
+ result = NULL;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * If the variable was changed in some gross way by a trace (e.g.
+ * it was unset and then recreated as an array) then just return
+ * an empty string; otherwise return the variable's current
+ * value.
+ */
+
+ if (!(varPtr->flags & (VAR_UNDEFINED|VAR_UPVAR|VAR_ARRAY))) {
+ return varPtr->value.string;
+ }
+ result = "";
+
+ /*
+ * If the variable doesn't exist anymore and no-one's using it,
+ * then free up the relevant structures and hash table entries.
+ */
+
+ cleanup:
+ if (varPtr->flags & VAR_UNDEFINED) {
+ CleanupVar(varPtr, arrayPtr);
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UnsetVar --
+ *
+ * Delete a variable, so that it may not be accessed anymore.
+ *
+ * Results:
+ * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
+ * if the variable can't be unset. In the event of an error,
+ * if the TCL_LEAVE_ERR_MSG flag is set then an error message
+ * is left in interp->result.
+ *
+ * Side effects:
+ * If varName is defined as a local or global variable in interp,
+ * it is deleted.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_UnsetVar(interp, varName, flags)
+ Tcl_Interp *interp; /* Command interpreter in which varName is
+ * to be looked up. */
+ char *varName; /* Name of a variable in interp. May be
+ * either a scalar name or an array name
+ * or an element in an array. */
+ int flags; /* OR-ed combination of any of
+ * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
+{
+ register char *p;
+ int result;
+
+ /*
+ * Figure out whether this is an array reference, then call
+ * Tcl_UnsetVar2 to do all the real work.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = Tcl_UnsetVar2(interp, varName, open+1, flags);
+ *open = '(';
+ *p = ')';
+ return result;
+ }
+ }
+
+ scalar:
+ return Tcl_UnsetVar2(interp, varName, (char *) NULL, flags);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UnsetVar2 --
+ *
+ * Delete a variable, given a 2-part name.
+ *
+ * Results:
+ * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
+ * if the variable can't be unset. In the event of an error,
+ * if the TCL_LEAVE_ERR_MSG flag is set then an error message
+ * is left in interp->result.
+ *
+ * Side effects:
+ * If part1 and part2 indicate a local or global variable in interp,
+ * it is deleted. If part1 is an array name and part2 is NULL, then
+ * the whole array is deleted.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_UnsetVar2(interp, part1, part2, flags)
+ Tcl_Interp *interp; /* Command interpreter in which varName is
+ * to be looked up. */
+ char *part1; /* Name of variable or array. */
+ char *part2; /* Name of element within array or NULL. */
+ int flags; /* OR-ed combination of any of
+ * TCL_GLOBAL_ONLY or TCL_LEAVE_ERR_MSG. */
+{
+ Var *varPtr, dummyVar;
+ Interp *iPtr = (Interp *) interp;
+ Var *arrayPtr;
+ ActiveVarTrace *activePtr;
+ int result;
+
+ varPtr = LookupVar(interp, part1, part2, flags, "unset", 0, &arrayPtr);
+ if (varPtr == NULL) {
+ return TCL_ERROR;
+ }
+ result = (varPtr->flags & VAR_UNDEFINED) ? TCL_ERROR : TCL_OK;
+
+ if ((part2 != NULL) && (arrayPtr->searchPtr != NULL)) {
+ DeleteSearches(arrayPtr);
+ }
+
+ /*
+ * The code below is tricky, because of the possibility that
+ * a trace procedure might try to access a variable being
+ * deleted. To handle this situation gracefully, do things
+ * in three steps:
+ * 1. Copy the contents of the variable to a dummy variable
+ * structure, and mark the original structure as undefined.
+ * 2. Invoke traces and clean up the variable, using the copy.
+ * 3. If at the end of this the original variable is still
+ * undefined and has no outstanding references, then delete
+ * it (but it could have gotten recreated by a trace).
+ */
+
+ dummyVar = *varPtr;
+ varPtr->valueSpace = 0;
+ varPtr->flags = VAR_UNDEFINED;
+ varPtr->tracePtr = NULL;
+
+ /*
+ * Call trace procedures for the variable being deleted and delete
+ * its traces. Be sure to abort any other traces for the variable
+ * that are still pending. Special tricks:
+ * 1. Increment varPtr's refCount around this: CallTraces will
+ * use dummyVar so it won't increment varPtr's refCount.
+ * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to
+ * call unset traces even if other traces are pending.
+ */
+
+ if ((dummyVar.tracePtr != NULL)
+ || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+ varPtr->refCount++;
+ dummyVar.flags &= ~VAR_TRACE_ACTIVE;
+ (void) CallTraces(iPtr, arrayPtr, &dummyVar, part1, part2,
+ (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_UNSETS);
+ while (dummyVar.tracePtr != NULL) {
+ VarTrace *tracePtr = dummyVar.tracePtr;
+ dummyVar.tracePtr = tracePtr->nextPtr;
+ ckfree((char *) tracePtr);
+ }
+ for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
+ activePtr = activePtr->nextPtr) {
+ if (activePtr->varPtr == varPtr) {
+ activePtr->nextTracePtr = NULL;
+ }
+ }
+ varPtr->refCount--;
+ }
+
+ /*
+ * If the variable is an array, delete all of its elements. This
+ * must be done after calling the traces on the array, above (that's
+ * the way traces are defined).
+ */
+
+ if (dummyVar.flags & VAR_ARRAY) {
+ DeleteArray(iPtr, part1, &dummyVar,
+ (flags & TCL_GLOBAL_ONLY) | TCL_TRACE_UNSETS);
+ }
+ if (dummyVar.valueSpace > 0) {
+ ckfree(dummyVar.value.string);
+ }
+ if (result == TCL_ERROR) {
+ if (flags & TCL_LEAVE_ERR_MSG) {
+ VarErrMsg(interp, part1, part2, "unset",
+ (part2 == NULL) ? noSuchVar : noSuchElement);
+ }
+ }
+
+ /*
+ * Finally, if the variable is truly not in use then free up its
+ * record and remove it from the hash table.
+ */
+
+ CleanupVar(varPtr, arrayPtr);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TraceVar --
+ *
+ * Arrange for reads and/or writes to a variable to cause a
+ * procedure to be invoked, which can monitor the operations
+ * and/or change their actions.
+ *
+ * Results:
+ * A standard Tcl return value.
+ *
+ * Side effects:
+ * A trace is set up on the variable given by varName, such that
+ * future references to the variable will be intermediated by
+ * proc. See the manual entry for complete details on the calling
+ * sequence for proc.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_TraceVar(interp, varName, flags, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter in which variable is
+ * to be traced. */
+ char *varName; /* Name of variable; may end with "(index)"
+ * to signify an array reference. */
+ int flags; /* OR-ed collection of bits, including any
+ * of TCL_TRACE_READS, TCL_TRACE_WRITES,
+ * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are
+ * invoked upon varName. */
+ ClientData clientData; /* Arbitrary argument to pass to proc. */
+{
+ register char *p;
+
+ /*
+ * If varName refers to an array (it ends with a parenthesized
+ * element name), then handle it specially.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ int result;
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = Tcl_TraceVar2(interp, varName, open+1, flags,
+ proc, clientData);
+ *open = '(';
+ *p = ')';
+ return result;
+ }
+ }
+
+ scalar:
+ return Tcl_TraceVar2(interp, varName, (char *) NULL, flags,
+ proc, clientData);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_TraceVar2 --
+ *
+ * Arrange for reads and/or writes to a variable to cause a
+ * procedure to be invoked, which can monitor the operations
+ * and/or change their actions.
+ *
+ * Results:
+ * A standard Tcl return value.
+ *
+ * Side effects:
+ * A trace is set up on the variable given by part1 and part2, such
+ * that future references to the variable will be intermediated by
+ * proc. See the manual entry for complete details on the calling
+ * sequence for proc.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter in which variable is
+ * to be traced. */
+ char *part1; /* Name of scalar variable or array. */
+ char *part2; /* Name of element within array; NULL means
+ * trace applies to scalar variable or array
+ * as-a-whole. */
+ int flags; /* OR-ed collection of bits, including any
+ * of TCL_TRACE_READS, TCL_TRACE_WRITES,
+ * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are
+ * invoked upon varName. */
+ ClientData clientData; /* Arbitrary argument to pass to proc. */
+{
+ Var *varPtr, *arrayPtr;
+ register VarTrace *tracePtr;
+
+ varPtr = LookupVar(interp, part1, part2, (flags | TCL_LEAVE_ERR_MSG),
+ "trace", CRT_PART1|CRT_PART2, &arrayPtr);
+ if (varPtr == NULL) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Set up trace information.
+ */
+
+ tracePtr = (VarTrace *) ckalloc(sizeof(VarTrace));
+ tracePtr->traceProc = proc;
+ tracePtr->clientData = clientData;
+ tracePtr->flags = flags &
+ (TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS);
+ tracePtr->nextPtr = varPtr->tracePtr;
+ varPtr->tracePtr = tracePtr;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UntraceVar --
+ *
+ * Remove a previously-created trace for a variable.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If there exists a trace for the variable given by varName
+ * with the given flags, proc, and clientData, then that trace
+ * is removed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_UntraceVar(interp, varName, flags, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter containing traced variable. */
+ char *varName; /* Name of variable; may end with "(index)"
+ * to signify an array reference. */
+ int flags; /* OR-ed collection of bits describing
+ * current trace, including any of
+ * TCL_TRACE_READS, TCL_TRACE_WRITES,
+ * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
+ ClientData clientData; /* Arbitrary argument to pass to proc. */
+{
+ register char *p;
+
+ /*
+ * If varName refers to an array (it ends with a parenthesized
+ * element name), then handle it specially.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ Tcl_UntraceVar2(interp, varName, open+1, flags, proc, clientData);
+ *open = '(';
+ *p = ')';
+ return;
+ }
+ }
+
+ scalar:
+ Tcl_UntraceVar2(interp, varName, (char *) NULL, flags, proc, clientData);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UntraceVar2 --
+ *
+ * Remove a previously-created trace for a variable.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If there exists a trace for the variable given by part1
+ * and part2 with the given flags, proc, and clientData, then
+ * that trace is removed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData)
+ Tcl_Interp *interp; /* Interpreter containing traced variable. */
+ char *part1; /* Name of variable or array. */
+ char *part2; /* Name of element within array; NULL means
+ * trace applies to scalar variable or array
+ * as-a-whole. */
+ int flags; /* OR-ed collection of bits describing
+ * current trace, including any of
+ * TCL_TRACE_READS, TCL_TRACE_WRITES,
+ * TCL_TRACE_UNSETS, and TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
+ ClientData clientData; /* Arbitrary argument to pass to proc. */
+{
+ register VarTrace *tracePtr;
+ VarTrace *prevPtr;
+ Var *varPtr, *arrayPtr;
+ Interp *iPtr = (Interp *) interp;
+ ActiveVarTrace *activePtr;
+
+ varPtr = LookupVar(interp, part1, part2, flags & TCL_GLOBAL_ONLY,
+ (char *) NULL, 0, &arrayPtr);
+ if (varPtr == NULL) {
+ return;
+ }
+
+ flags &= (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS);
+ for (tracePtr = varPtr->tracePtr, prevPtr = NULL; ;
+ prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
+ if (tracePtr == NULL) {
+ return;
+ }
+ if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags)
+ && (tracePtr->clientData == clientData)) {
+ break;
+ }
+ }
+
+ /*
+ * The code below makes it possible to delete traces while traces
+ * are active: it makes sure that the deleted trace won't be
+ * processed by CallTraces.
+ */
+
+ for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
+ activePtr = activePtr->nextPtr) {
+ if (activePtr->nextTracePtr == tracePtr) {
+ activePtr->nextTracePtr = tracePtr->nextPtr;
+ }
+ }
+ if (prevPtr == NULL) {
+ varPtr->tracePtr = tracePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = tracePtr->nextPtr;
+ }
+ ckfree((char *) tracePtr);
+
+ /*
+ * If this is the last trace on the variable, and the variable is
+ * unset and unused, then free up the variable.
+ */
+
+ if (varPtr->flags & VAR_UNDEFINED) {
+ CleanupVar(varPtr, (Var *) NULL);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_VarTraceInfo --
+ *
+ * Return the clientData value associated with a trace on a
+ * variable. This procedure can also be used to step through
+ * all of the traces on a particular variable that have the
+ * same trace procedure.
+ *
+ * Results:
+ * The return value is the clientData value associated with
+ * a trace on the given variable. Information will only be
+ * returned for a trace with proc as trace procedure. If
+ * the clientData argument is NULL then the first such trace is
+ * returned; otherwise, the next relevant one after the one
+ * given by clientData will be returned. If the variable
+ * doesn't exist, or if there are no (more) traces for it,
+ * then NULL is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ClientData
+Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData)
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ char *varName; /* Name of variable; may end with "(index)"
+ * to signify an array reference. */
+ int flags; /* 0 or TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
+ ClientData prevClientData; /* If non-NULL, gives last value returned
+ * by this procedure, so this call will
+ * return the next trace after that one.
+ * If NULL, this call will return the
+ * first trace. */
+{
+ register char *p;
+
+ /*
+ * If varName refers to an array (it ends with a parenthesized
+ * element name), then handle it specially.
+ */
+
+ for (p = varName; *p != '\0'; p++) {
+ if (*p == '(') {
+ ClientData result;
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = Tcl_VarTraceInfo2(interp, varName, open+1, flags, proc,
+ prevClientData);
+ *open = '(';
+ *p = ')';
+ return result;
+ }
+ }
+
+ scalar:
+ return Tcl_VarTraceInfo2(interp, varName, (char *) NULL, flags, proc,
+ prevClientData);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_VarTraceInfo2 --
+ *
+ * Same as Tcl_VarTraceInfo, except takes name in two pieces
+ * instead of one.
+ *
+ * Results:
+ * Same as Tcl_VarTraceInfo.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ClientData
+Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData)
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ char *part1; /* Name of variable or array. */
+ char *part2; /* Name of element within array; NULL means
+ * trace applies to scalar variable or array
+ * as-a-whole. */
+ int flags; /* 0 or TCL_GLOBAL_ONLY. */
+ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */
+ ClientData prevClientData; /* If non-NULL, gives last value returned
+ * by this procedure, so this call will
+ * return the next trace after that one.
+ * If NULL, this call will return the
+ * first trace. */
+{
+ register VarTrace *tracePtr;
+ Var *varPtr, *arrayPtr;
+
+ varPtr = LookupVar(interp, part1, part2, flags & TCL_GLOBAL_ONLY,
+ (char *) NULL, 0, &arrayPtr);
+ if (varPtr == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Find the relevant trace, if any, and return its clientData.
+ */
+
+ tracePtr = varPtr->tracePtr;
+ if (prevClientData != NULL) {
+ for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) {
+ if ((tracePtr->clientData == prevClientData)
+ && (tracePtr->traceProc == proc)) {
+ tracePtr = tracePtr->nextPtr;
+ break;
+ }
+ }
+ }
+ for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) {
+ if (tracePtr->traceProc == proc) {
+ return tracePtr->clientData;
+ }
+ }
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetCmd --
+ *
+ * This procedure is invoked to process the "set" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * A variable's value may be changed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_SetCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ register Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ if (argc == 2) {
+ char *value;
+
+ value = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG);
+ if (value == NULL) {
+ return TCL_ERROR;
+ }
+ interp->result = value;
+ return TCL_OK;
+ } else if (argc == 3) {
+ char *result;
+
+ result = Tcl_SetVar(interp, argv[1], argv[2], TCL_LEAVE_ERR_MSG);
+ if (result == NULL) {
+ return TCL_ERROR;
+ }
+ interp->result = result;
+ return TCL_OK;
+ } else {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " varName ?newValue?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UnsetCmd --
+ *
+ * This procedure is invoked to process the "unset" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_UnsetCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ register Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " varName ?varName ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (i = 1; i < argc; i++) {
+ if (Tcl_UnsetVar(interp, argv[i], TCL_LEAVE_ERR_MSG) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppendCmd --
+ *
+ * This procedure is invoked to process the "append" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * A variable's value may be changed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_AppendCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ register Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i;
+ char *result = NULL; /* (Initialization only needed to keep
+ * the compiler from complaining) */
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " varName value ?value ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ for (i = 2; i < argc; i++) {
+ result = Tcl_SetVar(interp, argv[1], argv[i],
+ TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG);
+ if (result == NULL) {
+ return TCL_ERROR;
+ }
+ }
+ interp->result = result;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_LappendCmd --
+ *
+ * This procedure is invoked to process the "lappend" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * A variable's value may be changed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_LappendCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ register Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i;
+ char *result = NULL; /* (Initialization only needed to keep
+ * the compiler from complaining) */
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " varName value ?value ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ for (i = 2; i < argc; i++) {
+ result = Tcl_SetVar(interp, argv[1], argv[i],
+ TCL_APPEND_VALUE|TCL_LIST_ELEMENT|TCL_LEAVE_ERR_MSG);
+ if (result == NULL) {
+ return TCL_ERROR;
+ }
+ }
+ interp->result = result;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ArrayCmd --
+ *
+ * This procedure is invoked to process the "array" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_ArrayCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ register Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int length;
+ char c;
+ Var *varPtr;
+ Tcl_HashEntry *hPtr;
+ Interp *iPtr = (Interp *) interp;
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " option arrayName ?arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Locate the array variable (and it better be an array).
+ */
+
+ if (iPtr->varFramePtr == NULL) {
+ hPtr = Tcl_FindHashEntry(&iPtr->globalTable, argv[2]);
+ } else {
+ hPtr = Tcl_FindHashEntry(&iPtr->varFramePtr->varTable, argv[2]);
+ }
+ if (hPtr == NULL) {
+ notArray:
+ Tcl_AppendResult(interp, "\"", argv[2], "\" isn't an array",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UPVAR) {
+ varPtr = varPtr->value.upvarPtr;
+ }
+ if (!(varPtr->flags & VAR_ARRAY)) {
+ goto notArray;
+ }
+
+ /*
+ * Dispatch based on the option.
+ */
+
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ if ((c == 'a') && (strncmp(argv[1], "anymore", length) == 0)) {
+ ArraySearch *searchPtr;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " anymore arrayName searchId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]);
+ if (searchPtr == NULL) {
+ return TCL_ERROR;
+ }
+ while (1) {
+ Var *varPtr2;
+
+ if (searchPtr->nextEntry != NULL) {
+ varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry);
+ if (!(varPtr2->flags & VAR_UNDEFINED)) {
+ break;
+ }
+ }
+ searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search);
+ if (searchPtr->nextEntry == NULL) {
+ interp->result = "0";
+ return TCL_OK;
+ }
+ }
+ interp->result = "1";
+ return TCL_OK;
+ } else if ((c == 'd') && (strncmp(argv[1], "donesearch", length) == 0)) {
+ ArraySearch *searchPtr, *prevPtr;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " donesearch arrayName searchId\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]);
+ if (searchPtr == NULL) {
+ return TCL_ERROR;
+ }
+ if (varPtr->searchPtr == searchPtr) {
+ varPtr->searchPtr = searchPtr->nextPtr;
+ } else {
+ for (prevPtr = varPtr->searchPtr; ; prevPtr = prevPtr->nextPtr) {
+ if (prevPtr->nextPtr == searchPtr) {
+ prevPtr->nextPtr = searchPtr->nextPtr;
+ break;
+ }
+ }
+ }
+ ckfree((char *) searchPtr);
+ } else if ((c == 'n') && (strncmp(argv[1], "names", length) == 0)
+ && (length >= 2)) {
+ Tcl_HashSearch search;
+ Var *varPtr2;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " names arrayName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr2->flags & VAR_UNDEFINED) {
+ continue;
+ }
+ Tcl_AppendElement(interp,
+ Tcl_GetHashKey(varPtr->value.tablePtr, hPtr));
+ }
+ } else if ((c == 'n') && (strncmp(argv[1], "nextelement", length) == 0)
+ && (length >= 2)) {
+ ArraySearch *searchPtr;
+ Tcl_HashEntry *hPtr;
+
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " nextelement arrayName searchId\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ searchPtr = ParseSearchId(interp, varPtr, argv[2], argv[3]);
+ if (searchPtr == NULL) {
+ return TCL_ERROR;
+ }
+ while (1) {
+ Var *varPtr2;
+
+ hPtr = searchPtr->nextEntry;
+ if (hPtr == NULL) {
+ hPtr = Tcl_NextHashEntry(&searchPtr->search);
+ if (hPtr == NULL) {
+ return TCL_OK;
+ }
+ } else {
+ searchPtr->nextEntry = NULL;
+ }
+ varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+ if (!(varPtr2->flags & VAR_UNDEFINED)) {
+ break;
+ }
+ }
+ interp->result = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
+ } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)
+ && (length >= 2)) {
+ Tcl_HashSearch search;
+ Var *varPtr2;
+ int size;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " size arrayName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ size = 0;
+ for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr2->flags & VAR_UNDEFINED) {
+ continue;
+ }
+ size++;
+ }
+ sprintf(interp->result, "%d", size);
+ } else if ((c == 's') && (strncmp(argv[1], "startsearch", length) == 0)
+ && (length >= 2)) {
+ ArraySearch *searchPtr;
+
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " startsearch arrayName\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch));
+ if (varPtr->searchPtr == NULL) {
+ searchPtr->id = 1;
+ Tcl_AppendResult(interp, "s-1-", argv[2], (char *) NULL);
+ } else {
+ char string[20];
+
+ searchPtr->id = varPtr->searchPtr->id + 1;
+ sprintf(string, "%d", searchPtr->id);
+ Tcl_AppendResult(interp, "s-", string, "-", argv[2],
+ (char *) NULL);
+ }
+ searchPtr->varPtr = varPtr;
+ searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr,
+ &searchPtr->search);
+ searchPtr->nextPtr = varPtr->searchPtr;
+ varPtr->searchPtr = searchPtr;
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": should be anymore, donesearch, names, nextelement, ",
+ "size, or startsearch", (char *) NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MakeUpvar --
+ *
+ * This procedure does all of the work of the "global" and "upvar"
+ * commands.
+ *
+ * Results:
+ * A standard Tcl completion code. If an error occurs then an
+ * error message is left in iPtr->result.
+ *
+ * Side effects:
+ * The variable given by myName is linked to the variable in
+ * framePtr given by otherP1 and otherP2, so that references to
+ * myName are redirected to the other variable like a symbolic
+* link.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+MakeUpvar(iPtr, framePtr, otherP1, otherP2, myName)
+ Interp *iPtr; /* Interpreter containing variables. Used
+ * for error messages, too. */
+ CallFrame *framePtr; /* Call frame containing "other" variable.
+ * NULL means use global context. */
+ char *otherP1, *otherP2; /* Two-part name of variable in framePtr. */
+ char *myName; /* Name of variable in local table, which
+ * will refer to otherP1/P2. Must be a
+ * scalar. */
+{
+ Tcl_HashEntry *hPtr;
+ Var *otherPtr, *varPtr, *arrayPtr;
+ CallFrame *savedFramePtr;
+ int new;
+
+ /*
+ * In order to use LookupVar to find "other", temporarily replace
+ * the current frame pointer in the interpreter.
+ */
+
+ savedFramePtr = iPtr->varFramePtr;
+ iPtr->varFramePtr = framePtr;
+ otherPtr = LookupVar((Tcl_Interp *) iPtr, otherP1, otherP2,
+ TCL_LEAVE_ERR_MSG, "access", CRT_PART1|CRT_PART2, &arrayPtr);
+ iPtr->varFramePtr = savedFramePtr;
+ if (otherPtr == NULL) {
+ return TCL_ERROR;
+ }
+ if (iPtr->varFramePtr != NULL) {
+ hPtr = Tcl_CreateHashEntry(&iPtr->varFramePtr->varTable, myName, &new);
+ } else {
+ hPtr = Tcl_CreateHashEntry(&iPtr->globalTable, myName, &new);
+ }
+ if (new) {
+ varPtr = NewVar();
+ Tcl_SetHashValue(hPtr, varPtr);
+ varPtr->hPtr = hPtr;
+ } else {
+ /*
+ * The variable already exists. If it's not an upvar then it's
+ * an error. If it is an upvar, then just disconnect it from the
+ * thing it currently refers to.
+ */
+
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (varPtr->flags & VAR_UPVAR) {
+ Var *upvarPtr;
+
+ upvarPtr = varPtr->value.upvarPtr;
+ if (upvarPtr == otherPtr) {
+ return TCL_OK;
+ }
+ upvarPtr->refCount--;
+ if (upvarPtr->flags & VAR_UNDEFINED) {
+ CleanupVar(upvarPtr, (Var *) NULL);
+ }
+ } else if (!(varPtr->flags & VAR_UNDEFINED)) {
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
+ "\" already exists", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ varPtr->flags = (varPtr->flags & ~VAR_UNDEFINED) | VAR_UPVAR;
+ varPtr->value.upvarPtr = otherPtr;
+ otherPtr->refCount++;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GlobalCmd --
+ *
+ * This procedure is invoked to process the "global" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_GlobalCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+
+ if (argc < 2) {
+ Tcl_AppendResult((Tcl_Interp *) iPtr, "wrong # args: should be \"",
+ argv[0], " varName ?varName ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (iPtr->varFramePtr == NULL) {
+ return TCL_OK;
+ }
+
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (MakeUpvar(iPtr, (CallFrame *) NULL, *argv, (char *) NULL, *argv)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UpvarCmd --
+ *
+ * This procedure is invoked to process the "upvar" Tcl command.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result value.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ /* ARGSUSED */
+int
+Tcl_UpvarCmd(dummy, interp, argc, argv)
+ ClientData dummy; /* Not used. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Interp *iPtr = (Interp *) interp;
+ int result;
+ CallFrame *framePtr;
+ register char *p;
+
+ if (argc < 3) {
+ upvarSyntax:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ?level? otherVar localVar ?otherVar localVar ...?\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Find the hash table containing the variable being referenced.
+ */
+
+ result = TclGetFrame(interp, argv[1], &framePtr);
+ if (result == -1) {
+ return TCL_ERROR;
+ }
+ argc -= result+1;
+ if ((argc & 1) != 0) {
+ goto upvarSyntax;
+ }
+ argv += result+1;
+
+ /*
+ * Iterate over all the pairs of (other variable, local variable)
+ * names. For each pair, divide the other variable name into two
+ * parts, then call MakeUpvar to do all the work of creating linking
+ * it to the local variable.
+ */
+
+ for ( ; argc > 0; argc -= 2, argv += 2) {
+ for (p = argv[0]; *p != 0; p++) {
+ if (*p == '(') {
+ char *open = p;
+
+ do {
+ p++;
+ } while (*p != '\0');
+ p--;
+ if (*p != ')') {
+ goto scalar;
+ }
+ *open = '\0';
+ *p = '\0';
+ result = MakeUpvar(iPtr, framePtr, argv[0], open+1, argv[1]);
+ *open = '(';
+ *p = ')';
+ goto checkResult;
+ }
+ }
+ scalar:
+ result = MakeUpvar(iPtr, framePtr, argv[0], (char *) NULL, argv[1]);
+
+ checkResult:
+ if (result != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CallTraces --
+ *
+ * This procedure is invoked to find and invoke relevant
+ * trace procedures associated with a particular operation on
+ * a variable. This procedure invokes traces both on the
+ * variable and on its containing array (where relevant).
+ *
+ * Results:
+ * The return value is NULL if no trace procedures were invoked, or
+ * if all the invoked trace procedures returned successfully.
+ * The return value is non-zero if a trace procedure returned an
+ * error (in this case no more trace procedures were invoked after
+ * the error was returned). In this case the return value is a
+ * pointer to a static string describing the error.
+ *
+ * Side effects:
+ * Almost anything can happen, depending on trace; this procedure
+ * itself doesn't have any side effects.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+CallTraces(iPtr, arrayPtr, varPtr, part1, part2, flags)
+ Interp *iPtr; /* Interpreter containing variable. */
+ register Var *arrayPtr; /* Pointer to array variable that
+ * contains the variable, or NULL if
+ * the variable isn't an element of an
+ * array. */
+ Var *varPtr; /* Variable whose traces are to be
+ * invoked. */
+ char *part1, *part2; /* Variable's two-part name. */
+ int flags; /* Flags to pass to trace procedures:
+ * indicates what's happening to
+ * variable, plus other stuff like
+ * TCL_GLOBAL_ONLY and
+ * TCL_INTERP_DESTROYED. */
+{
+ register VarTrace *tracePtr;
+ ActiveVarTrace active;
+ char *result;
+
+ /*
+ * If there are already similar trace procedures active for the
+ * variable, don't call them again.
+ */
+
+ if (varPtr->flags & VAR_TRACE_ACTIVE) {
+ return NULL;
+ }
+ varPtr->flags |= VAR_TRACE_ACTIVE;
+ varPtr->refCount++;
+
+ /*
+ * Invoke traces on the array containing the variable, if relevant.
+ */
+
+ result = NULL;
+ active.nextPtr = iPtr->activeTracePtr;
+ iPtr->activeTracePtr = &active;
+ if (arrayPtr != NULL) {
+ arrayPtr->refCount++;
+ active.varPtr = arrayPtr;
+ for (tracePtr = arrayPtr->tracePtr; tracePtr != NULL;
+ tracePtr = active.nextTracePtr) {
+ active.nextTracePtr = tracePtr->nextPtr;
+ if (!(tracePtr->flags & flags)) {
+ continue;
+ }
+ result = (*tracePtr->traceProc)(tracePtr->clientData,
+ (Tcl_Interp *) iPtr, part1, part2, flags);
+ if (result != NULL) {
+ if (flags & TCL_TRACE_UNSETS) {
+ result = NULL;
+ } else {
+ goto done;
+ }
+ }
+ }
+ }
+
+ /*
+ * Invoke traces on the variable itself.
+ */
+
+ if (flags & TCL_TRACE_UNSETS) {
+ flags |= TCL_TRACE_DESTROYED;
+ }
+ active.varPtr = varPtr;
+ for (tracePtr = varPtr->tracePtr; tracePtr != NULL;
+ tracePtr = active.nextTracePtr) {
+ active.nextTracePtr = tracePtr->nextPtr;
+ if (!(tracePtr->flags & flags)) {
+ continue;
+ }
+ result = (*tracePtr->traceProc)(tracePtr->clientData,
+ (Tcl_Interp *) iPtr, part1, part2, flags);
+ if (result != NULL) {
+ if (flags & TCL_TRACE_UNSETS) {
+ result = NULL;
+ } else {
+ goto done;
+ }
+ }
+ }
+
+ /*
+ * Restore the variable's flags, remove the record of our active
+ * traces, and then return.
+ */
+
+ done:
+ if (arrayPtr != NULL) {
+ arrayPtr->refCount--;
+ }
+ varPtr->flags &= ~VAR_TRACE_ACTIVE;
+ varPtr->refCount--;
+ iPtr->activeTracePtr = active.nextPtr;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NewVar --
+ *
+ * Create a new variable with a given amount of storage
+ * space.
+ *
+ * Results:
+ * The return value is a pointer to the new variable structure.
+ * The variable will not be part of any hash table yet. Its
+ * initial value is empty.
+ *
+ * Side effects:
+ * Storage gets allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Var *
+NewVar()
+{
+ register Var *varPtr;
+
+ varPtr = (Var *) ckalloc(sizeof(Var));
+ varPtr->valueLength = 0;
+ varPtr->valueSpace = 0;
+ varPtr->value.string = NULL;
+ varPtr->hPtr = NULL;
+ varPtr->refCount = 0;
+ varPtr->tracePtr = NULL;
+ varPtr->searchPtr = NULL;
+ varPtr->flags = VAR_UNDEFINED;
+ return varPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ParseSearchId --
+ *
+ * This procedure translates from a string to a pointer to an
+ * active array search (if there is one that matches the string).
+ *
+ * Results:
+ * The return value is a pointer to the array search indicated
+ * by string, or NULL if there isn't one. If NULL is returned,
+ * interp->result contains an error message.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static ArraySearch *
+ParseSearchId(interp, varPtr, varName, string)
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ Var *varPtr; /* Array variable search is for. */
+ char *varName; /* Name of array variable that search is
+ * supposed to be for. */
+ char *string; /* String containing id of search. Must have
+ * form "search-num-var" where "num" is a
+ * decimal number and "var" is a variable
+ * name. */
+{
+ char *end;
+ int id;
+ ArraySearch *searchPtr;
+
+ /*
+ * Parse the id into the three parts separated by dashes.
+ */
+
+ if ((string[0] != 's') || (string[1] != '-')) {
+ syntax:
+ Tcl_AppendResult(interp, "illegal search identifier \"", string,
+ "\"", (char *) NULL);
+ return NULL;
+ }
+ id = strtoul(string+2, &end, 10);
+ if ((end == (string+2)) || (*end != '-')) {
+ goto syntax;
+ }
+ if (strcmp(end+1, varName) != 0) {
+ Tcl_AppendResult(interp, "search identifier \"", string,
+ "\" isn't for variable \"", varName, "\"", (char *) NULL);
+ return NULL;
+ }
+
+ /*
+ * Search through the list of active searches on the interpreter
+ * to see if the desired one exists.
+ */
+
+ for (searchPtr = varPtr->searchPtr; searchPtr != NULL;
+ searchPtr = searchPtr->nextPtr) {
+ if (searchPtr->id == id) {
+ return searchPtr;
+ }
+ }
+ Tcl_AppendResult(interp, "couldn't find search \"", string, "\"",
+ (char *) NULL);
+ return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DeleteSearches --
+ *
+ * This procedure is called to free up all of the searches
+ * associated with an array variable.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory is released to the storage allocator.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DeleteSearches(arrayVarPtr)
+ register Var *arrayVarPtr; /* Variable whose searches are
+ * to be deleted. */
+{
+ ArraySearch *searchPtr;
+
+ while (arrayVarPtr->searchPtr != NULL) {
+ searchPtr = arrayVarPtr->searchPtr;
+ arrayVarPtr->searchPtr = searchPtr->nextPtr;
+ ckfree((char *) searchPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclDeleteVars --
+ *
+ * This procedure is called to recycle all the storage space
+ * associated with a table of variables. For this procedure
+ * to work correctly, it must not be possible for any of the
+ * variable in the table to be accessed from Tcl commands
+ * (e.g. from trace procedures).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Variables are deleted and trace procedures are invoked, if
+ * any are declared.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclDeleteVars(iPtr, tablePtr)
+ Interp *iPtr; /* Interpreter to which variables belong. */
+ Tcl_HashTable *tablePtr; /* Hash table containing variables to
+ * delete. */
+{
+ Tcl_HashSearch search;
+ Tcl_HashEntry *hPtr;
+ register Var *varPtr;
+ Var *upvarPtr;
+ int flags;
+ ActiveVarTrace *activePtr;
+
+ flags = TCL_TRACE_UNSETS;
+ if (tablePtr == &iPtr->globalTable) {
+ flags |= TCL_INTERP_DESTROYED | TCL_GLOBAL_ONLY;
+ }
+ for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
+ hPtr = Tcl_NextHashEntry(&search)) {
+ varPtr = (Var *) Tcl_GetHashValue(hPtr);
+
+ /*
+ * For global/upvar variables referenced in procedures, decrement
+ * the reference count on the variable referred to, and free up
+ * the referenced variable if it's no longer needed.
+ */
+
+ if (varPtr->flags & VAR_UPVAR) {
+ upvarPtr = varPtr->value.upvarPtr;
+ upvarPtr->refCount--;
+ if (upvarPtr->flags & VAR_UNDEFINED) {
+ CleanupVar(upvarPtr, (Var *) NULL);
+ }
+ }
+
+ /*
+ * Invoke traces on the variable that is being deleted, then
+ * free up the variable's space (no need to free the hash entry
+ * here, unless we're dealing with a global variable: the
+ * hash entries will be deleted automatically when the whole
+ * table is deleted).
+ */
+
+ if (varPtr->tracePtr != NULL) {
+ (void) CallTraces(iPtr, (Var *) NULL, varPtr,
+ Tcl_GetHashKey(tablePtr, hPtr), (char *) NULL, flags);
+ while (varPtr->tracePtr != NULL) {
+ VarTrace *tracePtr = varPtr->tracePtr;
+ varPtr->tracePtr = tracePtr->nextPtr;
+ ckfree((char *) tracePtr);
+ }
+ for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
+ activePtr = activePtr->nextPtr) {
+ if (activePtr->varPtr == varPtr) {
+ activePtr->nextTracePtr = NULL;
+ }
+ }
+ }
+ if (varPtr->flags & VAR_ARRAY) {
+ DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr, flags);
+ }
+ if (varPtr->valueSpace > 0) {
+ /*
+ * SPECIAL TRICK: it's possible that the interpreter's result
+ * currently points to this variable (for example, a "set" or
+ * "lappend" command was the last command in a procedure that's
+ * being returned from). If this is the case, then just pass
+ * ownership of the value string to the Tcl interpreter.
+ */
+
+ if (iPtr->result == varPtr->value.string) {
+ iPtr->freeProc = (Tcl_FreeProc *) free;
+ } else {
+ ckfree(varPtr->value.string);
+ }
+ varPtr->valueSpace = 0;
+ }
+ varPtr->hPtr = NULL;
+ varPtr->tracePtr = NULL;
+ varPtr->flags = VAR_UNDEFINED;
+ if (varPtr->refCount == 0) {
+ ckfree((char *) varPtr);
+ }
+ }
+ Tcl_DeleteHashTable(tablePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DeleteArray --
+ *
+ * This procedure is called to free up everything in an array
+ * variable. It's the caller's responsibility to make sure
+ * that the array is no longer accessible before this procedure
+ * is called.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * All storage associated with varPtr's array elements is deleted
+ * (including the hash table). Delete trace procedures for
+ * array elements are invoked.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DeleteArray(iPtr, arrayName, varPtr, flags)
+ Interp *iPtr; /* Interpreter containing array. */
+ char *arrayName; /* Name of array (used for trace
+ * callbacks). */
+ Var *varPtr; /* Pointer to variable structure. */
+ int flags; /* Flags to pass to CallTraces:
+ * TCL_TRACE_UNSETS and sometimes
+ * TCL_INTERP_DESTROYED and/or
+ * TCL_GLOBAL_ONLY. */
+{
+ Tcl_HashSearch search;
+ register Tcl_HashEntry *hPtr;
+ register Var *elPtr;
+ ActiveVarTrace *activePtr;
+
+ DeleteSearches(varPtr);
+ for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
+ hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ elPtr = (Var *) Tcl_GetHashValue(hPtr);
+ if (elPtr->valueSpace != 0) {
+ /*
+ * SPECIAL TRICK: it's possible that the interpreter's result
+ * currently points to this element (for example, a "set" or
+ * "lappend" command was the last command in a procedure that's
+ * being returned from). If this is the case, then just pass
+ * ownership of the value string to the Tcl interpreter.
+ */
+
+ if (iPtr->result == elPtr->value.string) {
+ iPtr->freeProc = (Tcl_FreeProc *) free;
+ } else {
+ ckfree(elPtr->value.string);
+ }
+ elPtr->valueSpace = 0;
+ }
+ elPtr->hPtr = NULL;
+ if (elPtr->tracePtr != NULL) {
+ elPtr->flags &= ~VAR_TRACE_ACTIVE;
+ (void) CallTraces(iPtr, (Var *) NULL, elPtr, arrayName,
+ Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags);
+ while (elPtr->tracePtr != NULL) {
+ VarTrace *tracePtr = elPtr->tracePtr;
+ elPtr->tracePtr = tracePtr->nextPtr;
+ ckfree((char *) tracePtr);
+ }
+ for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
+ activePtr = activePtr->nextPtr) {
+ if (activePtr->varPtr == elPtr) {
+ activePtr->nextTracePtr = NULL;
+ }
+ }
+ }
+ elPtr->flags = VAR_UNDEFINED;
+ if (elPtr->refCount == 0) {
+ ckfree((char *) elPtr);
+ }
+ }
+ Tcl_DeleteHashTable(varPtr->value.tablePtr);
+ ckfree((char *) varPtr->value.tablePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CleanupVar --
+ *
+ * This procedure is called when it looks like it may be OK
+ * to free up the variable's record and hash table entry, and
+ * those of its containing parent. It's called, for example,
+ * when a trace on a variable deletes the variable.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If the variable (or its containing array) really is dead then
+ * its record, and possibly its hash table entry, gets freed up.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+CleanupVar(varPtr, arrayPtr)
+ Var *varPtr; /* Pointer to variable that may be a
+ * candidate for being expunged. */
+ Var *arrayPtr; /* Array that contains the variable, or
+ * NULL if this variable isn't an array
+ * element. */
+{
+ if ((varPtr->flags & VAR_UNDEFINED) && (varPtr->refCount == 0)
+ && (varPtr->tracePtr == NULL)) {
+ if (varPtr->hPtr != NULL) {
+ Tcl_DeleteHashEntry(varPtr->hPtr);
+ }
+ ckfree((char *) varPtr);
+ }
+ if (arrayPtr != NULL) {
+ if ((arrayPtr->flags & VAR_UNDEFINED) && (arrayPtr->refCount == 0)
+ && (arrayPtr->tracePtr == NULL)) {
+ if (arrayPtr->hPtr != NULL) {
+ Tcl_DeleteHashEntry(arrayPtr->hPtr);
+ }
+ ckfree((char *) arrayPtr);
+ }
+ }
+ return;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VarErrMsg --
+ *
+ * Generate a reasonable error message describing why a variable
+ * operation failed.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Interp->result is reset to hold a message identifying the
+ * variable given by part1 and part2 and describing why the
+ * variable operation failed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+VarErrMsg(interp, part1, part2, operation, reason)
+ Tcl_Interp *interp; /* Interpreter in which to record message. */
+ char *part1, *part2; /* Variable's two-part name. */
+ char *operation; /* String describing operation that failed,
+ * e.g. "read", "set", or "unset". */
+ char *reason; /* String describing why operation failed. */
+{
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "can't ", operation, " \"", part1, (char *) NULL);
+ if (part2 != NULL) {
+ Tcl_AppendResult(interp, "(", part2, ")", (char *) NULL);
+ }
+ Tcl_AppendResult(interp, "\": ", reason, (char *) NULL);
+}
diff --git a/vendor/x11iraf/obm/Tcl/tests/README b/vendor/x11iraf/obm/Tcl/tests/README
new file mode 100644
index 00000000..593174a5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/README
@@ -0,0 +1,93 @@
+Tcl Test Suite
+--------------
+
+This directory contains a set of validation tests for the Tcl
+commands. Each of the files whose name ends in ".test" is
+intended to fully exercise one or a few Tcl commands. The
+commands tested by a given file are listed in the first line
+of the file.
+
+You can run the tests in two ways:
+ (a) type "make test" in the parent directory to this one; this
+ will run all of the tests.
+ (b) start up tcltest in this directory, then "source" the test
+ file (for example, type "source parse.test"). To run all
+ of the tests, type "source all".
+In either case no output will be generated if all goes well, except
+for a listing of the tests.. If there are errors then additional
+messages will appear in the format described below.
+
+The rest of this file provides additional information on the
+features of the testing environment.
+
+This approach to testing was designed and initially implemented
+by Mary Ann May-Pumphrey of Sun Microsystems. Many thanks to
+her for donating her work back to the public Tcl release.
+
+Definitions file:
+-----------------
+
+The file "defs" defines a collection of procedures and variables
+used to run the tests. It is read in automatically by each of the
+.test files if needed, but once it has been read once it will not
+be read again by the .test files. If you change defs while running
+tests you'll have to "source" it by hand to load its new contents.
+
+Test output:
+------------
+
+Normally, output only appears when there are errors. However, if
+the variable VERBOSE is set to 1 then tests will be run in "verbose"
+mode and output will be generated for each test regardless of
+whether it succeeded or failed. Test output consists of the
+following information:
+
+ - the test identifier (which can be used to locate the test code
+ in the .test file)
+ - a brief description of the test
+ - the contents of the test code
+ - the actual results produced by the tests
+ - a "PASSED" or "FAILED" message
+ - the expected results (if the test failed)
+
+You can set VERBOSE either interactively (after the defs file has been
+read in), or you can change the default value in "defs".
+
+Selecting tests for execution:
+------------------------------
+
+Normally, all the tests in a file are run whenever the file is
+"source"d. However, you can select a specific set of tests using
+the global variable TESTS. This variable contains a pattern; any
+test whose identifier matches TESTS will be run. For example,
+the following interactive command causes all of the "for" tests in
+groups 2 and 4 to be executed:
+
+ set TESTS {for-[24]*}
+
+TESTS defaults to *, but you can change the default in "defs" if
+you wish.
+
+Saving keystrokes:
+------------------
+
+A convenience procedure named "dotests" is included in file
+"defs". It takes two arguments--the name of the test file (such
+as "parse.test"), and a pattern selecting the tests you want to
+execute. It sets TESTS to the second argument, calls "source" on
+the file specified in the first argument, and restores TESTS to
+its pre-call value at the end.
+
+Batch vs. interactive execution:
+--------------------------------
+
+The tests can be run in either batch or interactive mode. Batch
+mode refers to using I/O redirection from a UNIX shell. For example,
+the following command causes the tests in the file named "parse.test"
+to be executed:
+
+ tclTest < parse.test > parse.test.results
+
+Users who want to execute the tests in this fashion need to first
+ensure that the file "defs" has proper values for the global
+variables that control the testing environment (VERBOSE and TESTS).
diff --git a/vendor/x11iraf/obm/Tcl/tests/all b/vendor/x11iraf/obm/Tcl/tests/all
new file mode 100644
index 00000000..890e9a2d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/all
@@ -0,0 +1,10 @@
+# This file contains a top-level script to run all of the Tcl
+# tests. Execute it by invoking "source all" when running tclTest
+# in this directory.
+#
+# $Header: /sprite/src/lib/tcl/tests/RCS/all,v 1.4 91/09/08 13:43:07 ouster Exp $ (Berkeley)
+
+foreach i [lsort [glob *.test]] {
+ puts stdout $i
+ source $i
+}
diff --git a/vendor/x11iraf/obm/Tcl/tests/append.test b/vendor/x11iraf/obm/Tcl/tests/append.test
new file mode 100644
index 00000000..e7f86b5c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/append.test
@@ -0,0 +1,122 @@
+# Commands covered: append lappend
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/append.test,v 1.6 93/06/19 14:28:25 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {unset x}
+test append-1.1 {append command} {
+ catch {unset x}
+ list [append x 1 2 abc "long string"] $x
+} {{12abclong string} {12abclong string}}
+test append-1.2 {append command} {
+ set x ""
+ list [append x first] [append x second] [append x third] $x
+} {first firstsecond firstsecondthird firstsecondthird}
+
+test append-2.1 {long appends} {
+ set x ""
+ for {set i 0} {$i < 1000} {set i [expr $i+1]} {
+ append x "foobar "
+ }
+ set y "foobar"
+ set y "$y $y $y $y $y $y $y $y $y $y"
+ set y "$y $y $y $y $y $y $y $y $y $y"
+ set y "$y $y $y $y $y $y $y $y $y $y "
+ expr {$x == $y}
+} 1
+
+test append-3.1 {append errors} {
+ list [catch {append} msg] $msg
+} {1 {wrong # args: should be "append varName value ?value ...?"}}
+test append-3.2 {append errors} {
+ list [catch {append x} msg] $msg
+} {1 {wrong # args: should be "append varName value ?value ...?"}}
+test append-3.3 {append errors} {
+ set x ""
+ list [catch {append x(0) 44} msg] $msg
+} {1 {can't set "x(0)": variable isn't array}}
+
+test append-4.1 {lappend command} {
+ catch {unset x}
+ list [lappend x 1 2 abc "long string"] $x
+} {{1 2 abc {long string}} {1 2 abc {long string}}}
+test append-4.2 {lappend command} {
+ set x ""
+ list [lappend x first] [lappend x second] [lappend x third] $x
+} {first {first second} {first second third} {first second third}}
+test append-4.3 {lappend command} {
+ proc foo {} {
+ global x
+ set x old
+ unset x
+ lappend x new
+ }
+ set result [foo]
+ rename foo {}
+ set result
+} {new}
+test append-4.3 {lappend command} {
+ set x {}
+ lappend x \{\ abc
+} {\{\ abc}
+test append-4.3 {lappend command} {
+ set x {}
+ lappend x \{ abc
+} {\{ abc}
+
+proc check {var size} {
+ set l [llength $var]
+ if {$l != $size} {
+ return "length mismatch: should have been $size, was $l"
+ }
+ for {set i 0} {$i < $size} {set i [expr $i+1]} {
+ set j [lindex $var $i]
+ if {$j != "item $i"} {
+ return "element $i should have been \"item $i\", was \"$j\"
+ }
+ }
+ return ok
+}
+test append-5.1 {long lappends} {
+ set x ""
+ for {set i 0} {$i < 300} {set i [expr $i+1]} {
+ lappend x "item $i"
+ }
+ check $x 300
+} ok
+
+test append-6.1 {lappend errors} {
+ list [catch {lappend} msg] $msg
+} {1 {wrong # args: should be "lappend varName value ?value ...?"}}
+test append-6.2 {lappend errors} {
+ list [catch {lappend x} msg] $msg
+} {1 {wrong # args: should be "lappend varName value ?value ...?"}}
+test append-6.3 {lappend errors} {
+ set x ""
+ list [catch {lappend x(0) 44} msg] $msg
+} {1 {can't set "x(0)": variable isn't array}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/async.test b/vendor/x11iraf/obm/Tcl/tests/async.test
new file mode 100644
index 00000000..dc11c24d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/async.test
@@ -0,0 +1,145 @@
+# Commands covered: none
+#
+# This file contains a collection of tests for Tcl_AsyncCreate and related
+# library procedures. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/async.test,v 1.2 93/08/14 17:07:43 ouster Exp $ (Berkeley)
+
+if {[info commands testasync] == {}} {
+ puts "This application hasn't been compiled with the \"testasync\""
+ puts "command, so I can't test Tcl_AsyncCreate et al."
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc async1 {result code} {
+ global aresult acode
+ set aresult $result
+ set acode $code
+ return "new result"
+}
+proc async2 {result code} {
+ global aresult acode
+ set aresult $result
+ set acode $code
+ return -code error "xyzzy"
+}
+proc async3 {result code} {
+ global aresult
+ set aresult "test pattern"
+ return -code $code $result
+}
+
+set handler1 [testasync create async1]
+set handler2 [testasync create async2]
+set handler3 [testasync create async3]
+test async-1.1 {basic async handlers} {
+ set aresult xxx
+ set acode yyy
+ list [catch {testasync mark $handler1 "original" 0} msg] $msg \
+ $acode $aresult
+} {0 {new result} 0 original}
+test async-1.2 {basic async handlers} {
+ set aresult xxx
+ set acode yyy
+ list [catch {testasync mark $handler1 "original" 1} msg] $msg \
+ $acode $aresult
+} {0 {new result} 1 original}
+test async-1.3 {basic async handlers} {
+ set aresult xxx
+ set acode yyy
+ list [catch {testasync mark $handler2 "old" 0} msg] $msg \
+ $acode $aresult
+} {1 xyzzy 0 old}
+test async-1.4 {basic async handlers} {
+ set aresult xxx
+ set acode yyy
+ list [catch {testasync mark $handler2 "old" 3} msg] $msg \
+ $acode $aresult
+} {1 xyzzy 3 old}
+test async-1.5 {basic async handlers} {
+ set aresult xxx
+ list [catch {testasync mark $handler3 "foobar" 0} msg] $msg $aresult
+} {0 foobar {test pattern}}
+test async-1.6 {basic async handlers} {
+ set aresult xxx
+ list [catch {testasync mark $handler3 "foobar" 1} msg] $msg $aresult
+} {1 foobar {test pattern}}
+
+proc mult1 {result code} {
+ global x
+ lappend x mult1
+ return -code 7 mult1
+}
+set hm1 [testasync create mult1]
+proc mult2 {result code} {
+ global x
+ lappend x mult2
+ return -code 9 mult2
+}
+set hm2 [testasync create mult2]
+proc mult3 {result code} {
+ global x hm1 hm2
+ lappend x [catch {testasync mark $hm2 serial2 0}]
+ lappend x [catch {testasync mark $hm1 serial1 0}]
+ lappend x mult3
+ return -code 11 mult3
+}
+set hm3 [testasync create mult3]
+
+test async-2.1 {multiple handlers} {
+ set x {}
+ list [catch {testasync mark $hm3 "foobar" 5} msg] $msg $x
+} {9 mult2 {0 0 mult3 mult1 mult2}}
+
+proc del1 {result code} {
+ global x hm1 hm2 hm3 hm4
+ lappend x [catch {testasync mark $hm3 serial2 0}]
+ lappend x [catch {testasync mark $hm1 serial1 0}]
+ lappend x [catch {testasync mark $hm4 serial1 0}]
+ testasync delete $hm1
+ testasync delete $hm2
+ testasync delete $hm3
+ lappend x del1
+ return -code 13 del1
+}
+proc del2 {result code} {
+ global x
+ lappend x del2
+ return -code 3 del2
+}
+testasync delete $handler1
+testasync delete $hm2
+testasync delete $hm3
+set hm2 [testasync create del1]
+set hm3 [testasync create mult2]
+set hm4 [testasync create del2]
+
+test async-3.1 {deleting handlers} {
+ set x {}
+ list [catch {testasync mark $hm2 "foobar" 5} msg] $msg $x
+} {3 del2 {0 0 0 del1 del2}}
+
+testasync delete
diff --git a/vendor/x11iraf/obm/Tcl/tests/case.test b/vendor/x11iraf/obm/Tcl/tests/case.test
new file mode 100644
index 00000000..6b1cb4a6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/case.test
@@ -0,0 +1,126 @@
+# Commands covered: case
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/case.test,v 1.11 93/06/17 11:22:41 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+# Commands covered: case
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/case.test,v 1.11 93/06/17 11:22:41 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test case-1.1 {simple pattern} {
+ case a in a {format 1} b {format 2} c {format 3} default {format 4}
+} 1
+test case-1.2 {simple pattern} {
+ case b a {format 1} b {format 2} c {format 3} default {format 4}
+} 2
+test case-1.3 {simple pattern} {
+ case x in a {format 1} b {format 2} c {format 3} default {format 4}
+} 4
+test case-1.4 {simple pattern} {
+ case x a {format 1} b {format 2} c {format 3}
+} {}
+test case-1.5 {simple pattern matches many times} {
+ case b a {format 1} b {format 2} b {format 3} b {format 4}
+} 2
+test case-1.6 {fancier pattern} {
+ case cx a {format 1} *c {format 2} *x {format 3} default {format 4}
+} 3
+test case-1.7 {list of patterns} {
+ case abc in {a b c} {format 1} {def abc ghi} {format 2}
+} 2
+
+test case-2.1 {error in executed command} {
+ list [catch {case a in a {error "Just a test"} default {format 1}} msg] \
+ $msg $errorInfo
+} {1 {Just a test} {Just a test
+ while executing
+"error "Just a test""
+ ("a" arm line 1)
+ invoked from within
+"case a in a {error "Just a test"} default {format 1}"}}
+test case-2.2 {error: not enough args} {
+ list [catch {case} msg] $msg
+} {1 {wrong # args: should be "case string ?in? patList body ... ?default body?"}}
+test case-2.3 {error: pattern with no body} {
+ list [catch {case a b} msg] $msg
+} {1 {extra case pattern with no body}}
+test case-2.4 {error: pattern with no body} {
+ list [catch {case a in b {format 1} c} msg] $msg
+} {1 {extra case pattern with no body}}
+test case-2.5 {error in default command} {
+ list [catch {case foo in a {error case1} default {error case2} \
+ b {error case 3}} msg] $msg $errorInfo
+} {1 case2 {case2
+ while executing
+"error case2"
+ ("default" arm line 1)
+ invoked from within
+"case foo in a {error case1} default {error case2} b {error case 3}"}}
+
+test case-3.1 {single-argument form for pattern/command pairs} {
+ case b in {
+ a {format 1}
+ b {format 2}
+ default {format 6}
+ }
+} {2}
+test case-3.2 {single-argument form for pattern/command pairs} {
+ case b {
+ a {format 1}
+ b {format 2}
+ default {format 6}
+ }
+} {2}
+test case-3.3 {single-argument form for pattern/command pairs} {
+ list [catch {case z in {a 2 b}} msg] $msg
+} {1 {extra case pattern with no body}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/cd.test b/vendor/x11iraf/obm/Tcl/tests/cd.test
new file mode 100644
index 00000000..d1eb3357
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/cd.test
@@ -0,0 +1,121 @@
+# Commands covered: cd, pwd
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/cd.test,v 1.21 93/10/07 17:21:21 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {exec rm -rf cd.dir}
+exec mkdir cd.dir
+exec cat << "Sample text" > cd.dir/test.file
+set cwd [exec pwd]
+
+test cd-1.1 {simple pwd check} {
+ pwd
+} $cwd
+
+cd cd.dir
+if $atBerkeley {
+ test cd-2.1 {changing directories} {
+ list [exec pwd]
+ } $cwd/cd.dir
+ test cd-2.2 {changing directories} {
+ pwd
+ } $cwd/cd.dir
+}
+test cd-2.3 {changing directories} {
+ exec cat test.file
+} "Sample text"
+cd ..
+test cd-2.4 {changing directories} {
+ exec pwd
+} $cwd
+test cd-2.5 {changing directories} {
+ pwd
+} $cwd
+test cd-2.6 {changing directories} {
+ exec cat cd.dir/test.file
+} "Sample text"
+
+# The tests below seem to fail on lots of machines for a variety
+# of reasons, such as the auto-mounter, home directories that are
+# symbolic links, etc.
+
+if $atBerkeley {
+ set home [exec sh -c "cd; pwd"]
+ test cd-2.7 {changing directories} {
+ cd ~
+ set x [list [exec pwd] [pwd]]
+ cd $cwd
+ set x
+ } "$home $home"
+ test cd-2.8 {changing directories} {
+ cd
+ set x [list [exec pwd] [pwd]]
+ cd $cwd
+ set x
+ } "$home $home"
+}
+
+test cd-3.1 {cd return value} {
+ cd .
+} {}
+
+test cd-4.1 {errors in cd command} {
+ list [catch {cd 1 2} msg] $msg $errorCode
+} {1 {wrong # args: should be "cd dirName"} NONE}
+test cd-4.2 {errors in cd command} {
+ string tolower [list [catch {cd _bad_dir} msg] $msg $errorCode]
+} {1 {couldn't change working directory to "_bad_dir": no such file or directory} {posix enoent {no such file or directory}}}
+test cd-4.3 {errors in cd command} {
+ string tolower [list [catch {cd cd.dir/test.file} msg] $msg $errorCode]
+} {1 {couldn't change working directory to "cd.dir/test.file": not a directory} {posix enotdir {not a directory}}}
+test cd-4.4 {errors in cd command} {
+ set home $env(HOME)
+ unset env(HOME)
+ set x [list [catch cd msg] $msg]
+ set env(HOME) $home
+ set x
+} {1 {couldn't find HOME environment variable to expand "~"}}
+
+test cd-5.1 {errors in pwd command} {
+ list [catch {pwd a} msg] $msg
+} {1 {wrong # args: should be "pwd"}}
+if $atBerkeley {
+ exec mkdir cd.dir/child
+ cd cd.dir/child
+ exec chmod 111 ..
+ if {$user != "root"} {
+ test cd-5.2 {errors in pwd command} {
+ catch pwd msg
+ } 1
+ }
+ cd $cwd
+ exec chmod 775 cd.dir
+}
+
+catch {exec rm -rf cd.dir}
+format ""
diff --git a/vendor/x11iraf/obm/Tcl/tests/cmdinfo.test b/vendor/x11iraf/obm/Tcl/tests/cmdinfo.test
new file mode 100644
index 00000000..8998363d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/cmdinfo.test
@@ -0,0 +1,79 @@
+# Commands covered: none
+#
+# This file contains a collection of tests for Tcl_GetCommandInfo,
+# Tcl_SetCommandInfo, Tcl_CreateCommand, and Tcl_DeleteCommand.
+# Sourcing this file into Tcl runs the tests and generates output for
+# errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/cmdinfo.test,v 1.1 93/07/01 16:23:09 ouster Exp $ (Berkeley)
+
+if {[info commands testcmdinfo] == {}} {
+ puts "This application hasn't been compiled with the \"testcmdinfo\""
+ puts "command, so I can't test Tcl_GetCommandInfo etc."
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test cmdinfo-1.1 {command procedure and clientData} {
+ testcmdinfo create x1
+ testcmdinfo get x1
+} {CmdProc1 original CmdDelProc1 original}
+test cmdinfo-1.2 {command procedure and clientData} {
+ testcmdinfo create x1
+ x1
+} {CmdProc1 original}
+test cmdinfo-1.3 {command procedure and clientData} {
+ testcmdinfo create x1
+ testcmdinfo modify x1
+ testcmdinfo get x1
+} {CmdProc2 new_command_data CmdDelProc2 new_delete_data}
+test cmdinfo-1.4 {command procedure and clientData} {
+ testcmdinfo create x1
+ testcmdinfo modify x1
+ x1
+} {CmdProc2 new_command_data}
+
+test cmdinfo-2.1 {command deletion callbacks} {
+ testcmdinfo create x1
+ testcmdinfo delete x1
+} {CmdDelProc1 original}
+test cmdinfo-2.2 {command deletion callbacks} {
+ testcmdinfo create x1
+ testcmdinfo modify x1
+ testcmdinfo delete x1
+} {CmdDelProc2 new_delete_data}
+
+test cmdinfo-3.1 {Tcl_Get/SetCommandInfo return values} {
+ testcmdinfo get non_existent
+} {??}
+test cmdinfo-3.2 {Tcl_Get/SetCommandInfo return values} {
+ testcmdinfo create x1
+ testcmdinfo modify x1
+} 1
+test cmdinfo-3.3 {Tcl_Get/SetCommandInfo return values} {
+ testcmdinfo modify non_existent
+} 0
+
+catch {rename x1 ""}
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/concat.test b/vendor/x11iraf/obm/Tcl/tests/concat.test
new file mode 100644
index 00000000..a758765d
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/concat.test
@@ -0,0 +1,53 @@
+# Commands covered: concat
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/concat.test,v 1.6 93/10/28 16:13:57 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test concat-1.1 {simple concatenation} {
+ concat a b c d e f g
+} {a b c d e f g}
+test concat-1.2 {merging lists together} {
+ concat a {b c d} {e f g h}
+} {a b c d e f g h}
+test concat-1.3 {merge lists, retain sub-lists} {
+ concat a {b {c d}} {{e f}} g h
+} {a b {c d} {e f} g h}
+test concat-1.4 {special characters} {
+ concat a\{ {b \{c d} \{d
+} "a{ b \\{c d {d"
+
+test concat-2.1 {error: no arguments} {
+ list [catch concat msg] $msg
+} {0 {}}
+
+test concat-3.1 {pruning off extra white space} {
+ concat {} {a b c}
+} {a b c}
+test concat-3.2 {pruning off extra white space} {
+ concat x y " a b c \n\t " " " " def "
+} {x y a b c def}
diff --git a/vendor/x11iraf/obm/Tcl/tests/dcall.test b/vendor/x11iraf/obm/Tcl/tests/dcall.test
new file mode 100644
index 00000000..a54d7191
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/dcall.test
@@ -0,0 +1,54 @@
+# Commands covered: none
+#
+# This file contains a collection of tests for Tcl_CallWhenDeleted.
+# Sourcing this file into Tcl runs the tests and generates output for
+# errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/dcall.test,v 1.3 93/09/09 16:43:05 ouster Exp $ (Berkeley)
+
+if {[info commands testdcall] == {}} {
+ puts "This application hasn't been compiled with the \"testdcall\""
+ puts "command, so I can't test Tcl_CallWhenDeleted."
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test dcall-1.1 {deletion callbacks} {
+ testdcall 1 2 3
+} {1 2 3}
+test dcall-1.2 {deletion callbacks} {
+ testdcall
+} {}
+test dcall-1.3 {deletion callbacks} {
+ testdcall 20 21 22 -22
+} {20 21}
+test dcall-1.4 {deletion callbacks} {
+ testdcall 20 21 22 -20
+} {21 22}
+test dcall-1.5 {deletion callbacks} {
+ testdcall 20 21 22 -21
+} {20 22}
+test dcall-1.6 {deletion callbacks} {
+ testdcall 20 21 22 -21 -22 -20
+} {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/defs b/vendor/x11iraf/obm/Tcl/tests/defs
new file mode 100644
index 00000000..63f24404
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/defs
@@ -0,0 +1,94 @@
+# This file contains support code for the Tcl test suite. It is
+# normally sourced by the individual files in the test suite before
+# they run their tests. This improved approach to testing was designed
+# and initially implemented by Mary Ann May-Pumphrey of Sun Microsystems.
+
+set VERBOSE 0
+set TESTS {}
+set auto_noexec 1
+set auto_noload 1
+catch {rename unknown ""}
+
+# If tests are being run as root, issue a warning message and set a
+# variable to prevent some tests from running at all.
+
+set user {}
+catch {set user [exec whoami]}
+if {$user == "root"} {
+ puts stdout "Warning: you're executing as root. I'll have to"
+ puts stdout "skip some of the tests, since they'll fail as root."
+}
+
+# Some of the tests don't work on some system configurations due to
+# configuration quirks, not due to Tcl problems; in order to prevent
+# false alarms, these tests are only run in the master source directory
+# at Berkeley. The presence of a file "Berkeley" in this directory is
+# used to indicate that these tests should be run.
+
+set atBerkeley [file exists Berkeley]
+
+proc print_verbose {test_name test_description contents_of_test code answer} {
+ puts stdout "\n"
+ puts stdout "==== $test_name $test_description"
+ puts stdout "==== Contents of test case:"
+ puts stdout "$contents_of_test"
+ if {$code != 0} {
+ if {$code == 1} {
+ puts stdout "==== Test generated error:"
+ puts stdout $answer
+ } elseif {$code == 2} {
+ puts stdout "==== Test generated return exception; result was:"
+ puts stdout $answer
+ } elseif {$code == 3} {
+ puts stdout "==== Test generated break exception"
+ } elseif {$code == 4} {
+ puts stdout "==== Test generated continue exception"
+ } else {
+ puts stdout "==== Test generated exception $code; message was:"
+ puts stdout $answer
+ }
+ } else {
+ puts stdout "==== Result was:"
+ puts stdout "$answer"
+ }
+}
+
+proc test {test_name test_description contents_of_test passing_results} {
+ global VERBOSE
+ global TESTS
+ if {[string compare $TESTS ""] != 0} then {
+ set ok 0
+ foreach test $TESTS {
+ if [string match $test $test_name] then {
+ set ok 1
+ break
+ }
+ }
+ if !$ok then return
+ }
+ set code [catch {uplevel $contents_of_test} answer]
+ if {$code != 0} {
+ print_verbose $test_name $test_description $contents_of_test \
+ $code $answer
+ } elseif {[string compare $answer $passing_results] == 0} then {
+ if $VERBOSE then {
+ print_verbose $test_name $test_description $contents_of_test \
+ $code $answer
+ puts stdout "++++ $test_name PASSED"
+ }
+ } else {
+ print_verbose $test_name $test_description $contents_of_test $code \
+ $answer
+ puts stdout "---- Result should have been:"
+ puts stdout "$passing_results"
+ puts stdout "---- $test_name FAILED"
+ }
+}
+
+proc dotests {file args} {
+ global TESTS
+ set savedTests $TESTS
+ set TESTS $args
+ source $file
+ set TESTS $savedTests
+}
diff --git a/vendor/x11iraf/obm/Tcl/tests/dstring.test b/vendor/x11iraf/obm/Tcl/tests/dstring.test
new file mode 100644
index 00000000..563dc896
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/dstring.test
@@ -0,0 +1,192 @@
+# Commands covered: none
+#
+# This file contains a collection of tests for Tcl's dynamic string
+# library procedures. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/dstring.test,v 1.3 93/10/11 09:06:01 ouster Exp $ (Berkeley)
+
+if {[info commands testdstring] == {}} {
+ puts "This application hasn't been compiled with the \"testdstring\""
+ puts "command, so I can't test Tcl_DStringAppend et al."
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test dstring-1.1 {appending and retrieving} {
+ testdstring free
+ testdstring append "abc" -1
+ list [testdstring get] [testdstring length]
+} {abc 3}
+test dstring-1.2 {appending and retrieving} {
+ testdstring free
+ testdstring append "abc" -1
+ testdstring append " xyzzy" 3
+ testdstring append " 12345" -1
+ list [testdstring get] [testdstring length]
+} {{abc xy 12345} 12}
+test dstring-1.3 {appending and retrieving} {
+ testdstring free
+ foreach l {a b c d e f g h i j k l m n o p} {
+ testdstring append $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l\n -1
+ }
+ list [testdstring get] [testdstring length]
+} {{aaaaaaaaaaaaaaaaaaaaa
+bbbbbbbbbbbbbbbbbbbbb
+ccccccccccccccccccccc
+ddddddddddddddddddddd
+eeeeeeeeeeeeeeeeeeeee
+fffffffffffffffffffff
+ggggggggggggggggggggg
+hhhhhhhhhhhhhhhhhhhhh
+iiiiiiiiiiiiiiiiiiiii
+jjjjjjjjjjjjjjjjjjjjj
+kkkkkkkkkkkkkkkkkkkkk
+lllllllllllllllllllll
+mmmmmmmmmmmmmmmmmmmmm
+nnnnnnnnnnnnnnnnnnnnn
+ooooooooooooooooooooo
+ppppppppppppppppppppp
+} 352}
+
+test dstring-2.1 {appending list elements} {
+ testdstring free
+ testdstring element "abc"
+ testdstring element "d e f"
+ list [testdstring get] [testdstring length]
+} {{abc {d e f}} 11}
+test dstring-2.2 {appending list elements} {
+ testdstring free
+ testdstring element "x"
+ testdstring element "\{"
+ testdstring element "ab\}"
+ testdstring get
+} {x \{ ab\}}
+test dstring-2.3 {appending list elements} {
+ testdstring free
+ foreach l {a b c d e f g h i j k l m n o p} {
+ testdstring element $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l
+ }
+ testdstring get
+} {aaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccc ddddddddddddddddddddd eeeeeeeeeeeeeeeeeeeee fffffffffffffffffffff ggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiiiiiiii jjjjjjjjjjjjjjjjjjjjj kkkkkkkkkkkkkkkkkkkkk lllllllllllllllllllll mmmmmmmmmmmmmmmmmmmmm nnnnnnnnnnnnnnnnnnnnn ooooooooooooooooooooo ppppppppppppppppppppp}
+
+test dstring-3.1 {nested sublists} {
+ testdstring free
+ testdstring start
+ testdstring element foo
+ testdstring element bar
+ testdstring end
+ testdstring element another
+ testdstring get
+} {{foo bar} another}
+test dstring-3.2 {nested sublists} {
+ testdstring free
+ testdstring start
+ testdstring start
+ testdstring element abc
+ testdstring element def
+ testdstring end
+ testdstring end
+ testdstring element ghi
+ testdstring get
+} {{{abc def}} ghi}
+test dstring-3.3 {nested sublists} {
+ testdstring free
+ testdstring start
+ testdstring start
+ testdstring start
+ testdstring element foo
+ testdstring element foo2
+ testdstring end
+ testdstring end
+ testdstring element foo3
+ testdstring end
+ testdstring element foo4
+ testdstring get
+} {{{{foo foo2}} foo3} foo4}
+test dstring-3.4 {nested sublists} {
+ testdstring free
+ testdstring element before
+ testdstring start
+ testdstring element during
+ testdstring element more
+ testdstring end
+ testdstring element last
+ testdstring get
+} {before {during more} last}
+test dstring-3.4 {nested sublists} {
+ testdstring free
+ testdstring element "\{"
+ testdstring start
+ testdstring element first
+ testdstring element second
+ testdstring end
+ testdstring get
+} {\{ {first second}}
+
+test dstring-4.1 {truncation} {
+ testdstring free
+ testdstring append "abcdefg" -1
+ testdstring trunc 3
+ list [testdstring get] [testdstring length]
+} {abc 3}
+test dstring-4.2 {truncation} {
+ testdstring free
+ testdstring append "xyzzy" -1
+ testdstring trunc 0
+ list [testdstring get] [testdstring length]
+} {{} 0}
+
+test dstring-5.1 {copying to result} {
+ testdstring free
+ testdstring append xyz -1
+ testdstring result
+} xyz
+test dstring-5.2 {copying to result} {
+ testdstring free
+ foreach l {a b c d e f g h i j k l m n o p} {
+ testdstring append $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l\n -1
+ }
+ set a [testdstring result]
+ testdstring append abc -1
+ list $a [testdstring get]
+} {{aaaaaaaaaaaaaaaaaaaaa
+bbbbbbbbbbbbbbbbbbbbb
+ccccccccccccccccccccc
+ddddddddddddddddddddd
+eeeeeeeeeeeeeeeeeeeee
+fffffffffffffffffffff
+ggggggggggggggggggggg
+hhhhhhhhhhhhhhhhhhhhh
+iiiiiiiiiiiiiiiiiiiii
+jjjjjjjjjjjjjjjjjjjjj
+kkkkkkkkkkkkkkkkkkkkk
+lllllllllllllllllllll
+mmmmmmmmmmmmmmmmmmmmm
+nnnnnnnnnnnnnnnnnnnnn
+ooooooooooooooooooooo
+ppppppppppppppppppppp
+} abc}
+
+testdstring free
diff --git a/vendor/x11iraf/obm/Tcl/tests/env.test b/vendor/x11iraf/obm/Tcl/tests/env.test
new file mode 100644
index 00000000..43e92490
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/env.test
@@ -0,0 +1,122 @@
+# Commands covered: none (tests environment variable implementation)
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/env.test,v 1.7 93/10/14 14:59:14 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# If there is no "printenv" program on this system, then it's just too
+# much trouble to run this test (can't necessarily run csh to get the
+# environment: on some systems it barfs if there isn't a minimum set
+# predefined environment variables. Also, printenv returns a non-zero
+# status on some systems, so read the environment using a procedure
+# that catches errors.
+
+set printenv {}
+if [info exists env(PATH)] {
+ set dirs [split $env(PATH) :]
+} else {
+ set dirs {/bin /usr/bin /usr/ucb /usr/local /usr/public /usr/etc}
+}
+foreach i $dirs {
+ if [file executable $i/printenv] {
+ # The following hack is needed because of weirdness with
+ # environment variables in symbolic lines on Apollos (?!#?).
+ if ![catch {exec sh -c "cd $i; pwd"} x] {
+ set printenv $x/printenv
+ } else {
+ set printenv $i/printenv
+ }
+ break
+ }
+}
+if {$printenv == ""} {
+ puts stdout "Skipping env tests: need \"printenv\" to read environment."
+ return ""
+}
+proc getenv {} {
+ global printenv
+ catch {exec $printenv} out
+ if {$out == "child process exited abnormally"} {
+ set out {}
+ }
+ return $out
+}
+
+# Save the current environment variables at the start of the test.
+
+foreach name [array names env] {
+ set env2($name) $env($name)
+ unset env($name)
+}
+
+test env-1.1 {adding environment variables} {
+ getenv
+} {}
+
+set env(NAME1) "test string"
+test env-1.2 {adding environment variables} {
+ getenv
+} {NAME1=test string}
+
+set env(NAME2) "more"
+test env-1.3 {adding environment variables} {
+ getenv
+} {NAME1=test string
+NAME2=more}
+
+set env(XYZZY) "garbage"
+test env-1.4 {adding environment variables} {
+ getenv
+} {NAME1=test string
+NAME2=more
+XYZZY=garbage}
+
+set env(NAME2) "new value"
+test env-2.1 {changing environment variables} {
+ getenv
+} {NAME1=test string
+NAME2=new value
+XYZZY=garbage}
+
+unset env(NAME2)
+test env-3.1 {unsetting environment variables} {
+ getenv
+} {NAME1=test string
+XYZZY=garbage}
+unset env(NAME1)
+test env-3.2 {unsetting environment variables} {
+ getenv
+} {XYZZY=garbage}
+
+# Restore the environment variables at the end of the test.
+
+foreach name [array names env] {
+ unset env($name)
+}
+foreach name [array names env2] {
+ set env($name) $env2($name)
+}
diff --git a/vendor/x11iraf/obm/Tcl/tests/error.test b/vendor/x11iraf/obm/Tcl/tests/error.test
new file mode 100644
index 00000000..e2410aab
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/error.test
@@ -0,0 +1,185 @@
+# Commands covered: error, catch
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/error.test,v 1.12 93/02/06 15:54:01 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc foo {} {
+ global errorInfo
+ set a [catch {format [error glorp2]} b]
+ error {Human-generated}
+}
+
+proc foo2 {} {
+ global errorInfo
+ set a [catch {format [error glorp2]} b]
+ error {Human-generated} $errorInfo
+}
+
+# Catch errors occurring in commands and errors from "error" command
+
+test error-1.1 {simple errors from commands} {
+ catch {format [string compare]} b
+} 1
+
+test error-1.2 {simple errors from commands} {
+ catch {format [string compare]} b
+ set b
+} {wrong # args: should be "string compare string1 string2"}
+
+test error-1.3 {simple errors from commands} {
+ catch {format [string compare]} b
+ set errorInfo
+} {wrong # args: should be "string compare string1 string2"
+ while executing
+"string compare"
+ invoked from within
+"format [string compare]..."}
+
+test error-1.4 {simple errors from commands} {
+ catch {error glorp} b
+} 1
+
+test error-1.5 {simple errors from commands} {
+ catch {error glorp} b
+ set b
+} glorp
+
+test error-1.6 {simple errors from commands} {
+ catch {catch a b c} b
+} 1
+
+test error-1.7 {simple errors from commands} {
+ catch {catch a b c} b
+ set b
+} {wrong # args: should be "catch command ?varName?"}
+
+test error-2.1 {simple errors from commands} {
+ catch catch
+} 1
+
+# Check errors nested in procedures. Also check the optional argument
+# to "error" to generate a new error trace.
+
+test error-2.1 {errors in nested procedures} {
+ catch foo b
+} 1
+
+test error-2.2 {errors in nested procedures} {
+ catch foo b
+ set b
+} {Human-generated}
+
+test error-2.3 {errors in nested procedures} {
+ catch foo b
+ set errorInfo
+} {Human-generated
+ while executing
+"error {Human-generated}"
+ (procedure "foo" line 4)
+ invoked from within
+"foo"}
+
+test error-2.4 {errors in nested procedures} {
+ catch foo2 b
+} 1
+
+test error-2.5 {errors in nested procedures} {
+ catch foo2 b
+ set b
+} {Human-generated}
+
+test error-2.6 {errors in nested procedures} {
+ catch foo2 b
+ set errorInfo
+} {glorp2
+ while executing
+"error glorp2"
+ invoked from within
+"format [error glorp2]..."
+ (procedure "foo2" line 1)
+ invoked from within
+"foo2"}
+
+# Error conditions related to "catch".
+
+test error-3.1 {errors in catch command} {
+ list [catch {catch} msg] $msg
+} {1 {wrong # args: should be "catch command ?varName?"}}
+test error-3.2 {errors in catch command} {
+ list [catch {catch a b c} msg] $msg
+} {1 {wrong # args: should be "catch command ?varName?"}}
+test error-3.3 {errors in catch command} {
+ catch {unset a}
+ set a(0) 22
+ list [catch {catch {format 44} a} msg] $msg
+} {1 {couldn't save command result in variable}}
+catch {unset a}
+
+# More tests related to errorInfo and errorCode
+
+test error-4.1 {errorInfo and errorCode variables} {
+ list [catch {error msg1 msg2 msg3} msg] $msg $errorInfo $errorCode
+} {1 msg1 msg2 msg3}
+test error-4.2 {errorInfo and errorCode variables} {
+ list [catch {error msg1 {} msg3} msg] $msg $errorInfo $errorCode
+} {1 msg1 {msg1
+ while executing
+"error msg1 {} msg3"} msg3}
+test error-4.3 {errorInfo and errorCode variables} {
+ list [catch {error msg1 {}} msg] $msg $errorInfo $errorCode
+} {1 msg1 {msg1
+ while executing
+"error msg1 {}"} NONE}
+test error-4.4 {errorInfo and errorCode variables} {
+ set errorCode bogus
+ list [catch {error msg1} msg] $msg $errorInfo $errorCode
+} {1 msg1 {msg1
+ while executing
+"error msg1"} NONE}
+test error-4.5 {errorInfo and errorCode variables} {
+ set errorCode bogus
+ list [catch {error msg1 msg2 {}} msg] $msg $errorInfo $errorCode
+} {1 msg1 msg2 {}}
+
+# Errors in error command itself
+
+test error-5.1 {errors in error command} {
+ list [catch {error} msg] $msg
+} {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}}
+test error-5.2 {errors in error command} {
+ list [catch {error a b c d} msg] $msg
+} {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}}
+
+# Make sure that catch resets error information
+
+test error-6.1 {catch must reset error state} {
+ catch {error outer [catch {error inner inner.errorInfo inner.errorCode}]}
+ list $errorCode $errorInfo
+} {NONE 1}
+
+return ""
diff --git a/vendor/x11iraf/obm/Tcl/tests/eval.test b/vendor/x11iraf/obm/Tcl/tests/eval.test
new file mode 100644
index 00000000..b75460ff
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/eval.test
@@ -0,0 +1,69 @@
+# Commands covered: eval
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/eval.test,v 1.5 93/02/06 15:54:14 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test eval-1.1 {single argument} {
+ eval {format 22}
+} 22
+test eval-1.2 {multiple arguments} {
+ set a {$b}
+ set b xyzzy
+ eval format $a
+} xyzzy
+test eval-1.3 {single argument} {
+ eval concat a b c d e f g
+} {a b c d e f g}
+
+test eval-2.1 {error: not enough arguments} {catch eval} 1
+test eval-2.2 {error: not enough arguments} {
+ catch eval msg
+ set msg
+} {wrong # args: should be "eval arg ?arg ...?"}
+test eval-2.3 {error in eval'ed command} {
+ catch {eval {error "test error"}}
+} 1
+test eval-2.4 {error in eval'ed command} {
+ catch {eval {error "test error"}} msg
+ set msg
+} {test error}
+test eval-2.5 {error in eval'ed command: setting errorInfo} {
+ catch {eval {
+ set a 1
+ error "test error"
+ }} msg
+ set errorInfo
+} "test error
+ while executing
+\"error \"test error\"\"
+ (\"eval\" body line 3)
+ invoked from within
+\"eval {
+ set a 1
+ error \"test error\"
+ }\""
diff --git a/vendor/x11iraf/obm/Tcl/tests/exec.test b/vendor/x11iraf/obm/Tcl/tests/exec.test
new file mode 100644
index 00000000..3528b526
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/exec.test
@@ -0,0 +1,435 @@
+# Commands covered: exec
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/exec.test,v 1.30 93/09/16 16:57:43 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# Basic operations.
+
+test exec-1.1 {basic exec operation} {
+ exec echo a b c
+} "a b c"
+test exec-1.2 {pipelining} {
+ exec echo a b c d | cat | cat
+} "a b c d"
+test exec-1.3 {pipelining} {
+ set a [exec echo a b c d | cat | wc]
+ list [scan $a "%d %d %d" b c d] $b $c $d
+} {3 1 4 8}
+
+# I/O redirection: input from Tcl command.
+
+test exec-2.1 {redirecting input from immediate source} {
+ exec cat << "Sample text"
+} {Sample text}
+test exec-2.2 {redirecting input from immediate source} {
+ exec << "Sample text" cat | cat
+} {Sample text}
+test exec-2.3 {redirecting input from immediate source} {
+ exec cat << "Sample text" | cat
+} {Sample text}
+test exec-2.4 {redirecting input from immediate source} {
+ exec cat | cat << "Sample text"
+} {Sample text}
+test exec-2.5 {redirecting input from immediate source} {
+ exec cat "<<Joined to arrows"
+} {Joined to arrows}
+
+# I/O redirection: output to file.
+
+catch {exec rm -f gorp.file}
+test exec-3.1 {redirecting output to file} {
+ exec echo "Some simple words" > gorp.file
+ exec cat gorp.file
+} "Some simple words"
+test exec-3.2 {redirecting output to file} {
+ exec echo "More simple words" | >gorp.file cat | cat
+ exec cat gorp.file
+} "More simple words"
+test exec-3.3 {redirecting output to file} {
+ exec > gorp.file echo "Different simple words" | cat | cat
+ exec cat gorp.file
+} "Different simple words"
+test exec-3.4 {redirecting output to file} {
+ exec echo "Some simple words" >gorp.file
+ exec cat gorp.file
+} "Some simple words"
+test exec-3.5 {redirecting output to file} {
+ exec echo "First line" >gorp.file
+ exec echo "Second line" >> gorp.file
+ exec cat gorp.file
+} "First line\nSecond line"
+test exec-3.6 {redirecting output to file} {
+ exec echo "First line" >gorp.file
+ exec echo "Second line" >>gorp.file
+ exec cat gorp.file
+} "First line\nSecond line"
+test exec-3.7 {redirecting output to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec echo "More text" >@ $f
+ exec echo >@$f "Even more"
+ puts $f "Line 3"
+ close $f
+ exec cat gorp.file
+} "Line 1\nMore text\nEven more\nLine 3"
+
+# I/O redirection: output and stderr to file.
+
+catch {exec rm -f gorp.file}
+test exec-4.1 {redirecting output and stderr to file} {
+ exec echo "test output" >& gorp.file
+ exec cat gorp.file
+} "test output"
+test exec-4.2 {redirecting output and stderr to file} {
+ list [exec sh -c "echo foo bar 1>&2" >&gorp.file] \
+ [exec cat gorp.file]
+} {{} {foo bar}}
+test exec-4.3 {redirecting output and stderr to file} {
+ exec echo "first line" > gorp.file
+ list [exec sh -c "echo foo bar 1>&2" >>&gorp.file] \
+ [exec cat gorp.file]
+} "{} {first line\nfoo bar}"
+test exec-4.4 {redirecting output and stderr to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec echo "More text" >&@ $f
+ exec echo >&@$f "Even more"
+ puts $f "Line 3"
+ close $f
+ exec cat gorp.file
+} "Line 1\nMore text\nEven more\nLine 3"
+test exec-4.5 {redirecting output and stderr to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec >&@ $f sh -c "echo foo bar 1>&2"
+ exec >&@$f sh -c "echo xyzzy 1>&2"
+ puts $f "Line 3"
+ close $f
+ exec cat gorp.file
+} "Line 1\nfoo bar\nxyzzy\nLine 3"
+
+# I/O redirection: input from file.
+
+exec echo "Just a few thoughts" > gorp.file
+test exec-5.1 {redirecting input from file} {
+ exec cat < gorp.file
+} {Just a few thoughts}
+test exec-5.2 {redirecting input from file} {
+ exec cat | cat < gorp.file
+} {Just a few thoughts}
+test exec-5.3 {redirecting input from file} {
+ exec cat < gorp.file | cat
+} {Just a few thoughts}
+test exec-5.4 {redirecting input from file} {
+ exec < gorp.file cat | cat
+} {Just a few thoughts}
+test exec-5.5 {redirecting input from file} {
+ exec cat <gorp.file
+} {Just a few thoughts}
+test exec-5.6 {redirecting input from file} {
+ set f [open gorp.file r]
+ set result [exec cat <@ $f]
+ close $f
+ set result
+} {Just a few thoughts}
+test exec-5.7 {redirecting input from file} {
+ set f [open gorp.file r]
+ set result [exec <@$f cat]
+ close $f
+ set result
+} {Just a few thoughts}
+
+# I/O redirection: standard error through a pipeline.
+
+test exec-6.1 {redirecting stderr through a pipeline} {
+ exec sh -c "echo foo bar" |& cat
+} "foo bar"
+test exec-6.2 {redirecting stderr through a pipeline} {
+ exec sh -c "echo foo bar 1>&2" |& cat
+} "foo bar"
+test exec-6.3 {redirecting stderr through a pipeline} {
+ exec sh -c "echo foo bar 1>&2" |& sh -c "echo second msg 1>& 2; cat" |& cat
+} "second msg\nfoo bar"
+
+# I/O redirection: combinations.
+
+catch {exec rm -f gorp.file2}
+test exec-7.1 {multiple I/O redirections} {
+ exec << "command input" > gorp.file2 cat < gorp.file
+ exec cat gorp.file2
+} {Just a few thoughts}
+test exec-7.2 {multiple I/O redirections} {
+ exec < gorp.file << "command input" cat
+} {command input}
+
+# Long input to command and output from command.
+
+set a "0123456789 xxxxxxxxx abcdefghi ABCDEFGHIJK\n"
+set a [concat $a $a $a $a]
+set a [concat $a $a $a $a]
+set a [concat $a $a $a $a]
+set a [concat $a $a $a $a]
+test exec-8.1 {long input and output} {
+ exec cat << $a
+} $a
+
+# Commands that return errors.
+
+test exec-9.1 {commands returning errors} {
+ set x [catch {exec gorp456} msg]
+ list $x $msg [lindex $errorCode 0] [lrange $errorCode 2 end]
+} {1 {couldn't find "gorp456" to execute} CHILDSTATUS 1}
+test exec-9.2 {commands returning errors} {
+ set x [catch {exec foo123 | gorp456} msg]
+ set x1 {couldn't find "foo123" to execute
+couldn't find "gorp456" to execute}
+ set x2 {couldn't find "gorp456" to execute
+couldn't find "foo123" to execute}
+ set y [expr {($msg == $x1) || ($msg == $x2)}]
+ list $x $y [lindex $errorCode 0] [lrange $errorCode 2 end]
+} {1 1 CHILDSTATUS 1}
+test exec-9.3 {commands returning errors} {
+ list [catch {exec sleep 1 | sh -c "exit 43" | sleep 1} msg] $msg
+} {1 {child process exited abnormally}}
+test exec-9.4 {commands returning errors} {
+ list [catch {exec gorp456 | echo a b c} msg] $msg
+} {1 {a b c
+couldn't find "gorp456" to execute}}
+test exec-9.5 {commands returning errors} {
+ list [catch {exec sh -c "echo error msg 1>&2"} msg] $msg
+} {1 {error msg}}
+test exec-9.6 {commands returning errors} {
+ list [catch {exec sh -c "echo error msg 1>&2" | sh -c "echo error msg 1>&2"} msg] $msg
+} {1 {error msg
+error msg}}
+
+# Errors in executing the Tcl command, as opposed to errors in the
+# processes that are invoked.
+
+test exec-10.1 {errors in exec invocation} {
+ list [catch {exec} msg] $msg
+} {1 {wrong # args: should be "exec ?switches? arg ?arg ...?"}}
+test exec-10.2 {errors in exec invocation} {
+ list [catch {exec | cat} msg] $msg
+} {1 {illegal use of | or |& in command}}
+test exec-10.3 {errors in exec invocation} {
+ list [catch {exec cat |} msg] $msg
+} {1 {illegal use of | or |& in command}}
+test exec-10.4 {errors in exec invocation} {
+ list [catch {exec cat | | cat} msg] $msg
+} {1 {illegal use of | or |& in command}}
+test exec-10.5 {errors in exec invocation} {
+ list [catch {exec cat | |& cat} msg] $msg
+} {1 {illegal use of | or |& in command}}
+test exec-10.6 {errors in exec invocation} {
+ list [catch {exec cat |&} msg] $msg
+} {1 {illegal use of | or |& in command}}
+test exec-10.7 {errors in exec invocation} {
+ list [catch {exec cat <} msg] $msg
+} {1 {can't specify "<" as last word in command}}
+test exec-10.8 {errors in exec invocation} {
+ list [catch {exec cat >} msg] $msg
+} {1 {can't specify ">" as last word in command}}
+test exec-10.9 {errors in exec invocation} {
+ list [catch {exec cat <<} msg] $msg
+} {1 {can't specify "<<" as last word in command}}
+test exec-10.10 {errors in exec invocation} {
+ list [catch {exec cat >>} msg] $msg
+} {1 {can't specify ">>" as last word in command}}
+test exec-10.11 {errors in exec invocation} {
+ list [catch {exec cat >&} msg] $msg
+} {1 {can't specify ">&" as last word in command}}
+test exec-10.12 {errors in exec invocation} {
+ list [catch {exec cat >>&} msg] $msg
+} {1 {can't specify ">>&" as last word in command}}
+test exec-10.13 {errors in exec invocation} {
+ list [catch {exec cat >@} msg] $msg
+} {1 {can't specify ">@" as last word in command}}
+test exec-10.14 {errors in exec invocation} {
+ list [catch {exec cat <@} msg] $msg
+} {1 {can't specify "<@" as last word in command}}
+test exec-10.15 {errors in exec invocation} {
+ list [catch {exec cat < a/b/c} msg] [string tolower $msg]
+} {1 {couldn't read file "a/b/c": no such file or directory}}
+test exec-10.16 {errors in exec invocation} {
+ list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg]
+} {1 {couldn't write file "a/b/c": no such file or directory}}
+test exec-10.17 {errors in exec invocation} {
+ list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg]
+} {1 {couldn't write file "a/b/c": no such file or directory}}
+set f [open gorp.file w]
+test exec-10.18 {errors in exec invocation} {
+ list [catch {exec cat <@ $f} msg] $msg
+} "1 {\"$f\" wasn't opened for reading}"
+close $f
+set f [open gorp.file r]
+test exec-10.19 {errors in exec invocation} {
+ list [catch {exec cat >@ $f} msg] $msg
+} "1 {\"$f\" wasn't opened for writing}"
+close $f
+
+# Commands in background.
+
+test exec-11.1 {commands in background} {
+ set x [lindex [time {exec sleep 2 &}] 0]
+ expr $x<1000000
+} 1
+test exec-11.2 {commands in background} {
+ list [catch {exec echo a &b} msg] $msg
+} {0 {a &b}}
+test exec-11.3 {commands in background} {
+ llength [exec sleep 1 &]
+} 1
+test exec-11.4 {commands in background} {
+ llength [exec sleep 1 | sleep 1 | sleep 1 &]
+} 3
+
+# Make sure that background commands are properly reaped when
+# they eventually die.
+
+exec sleep 3
+if $atBerkeley {
+ test exec-12.1 {reaping background processes} {
+ for {set i 0} {$i < 20} {incr i} {
+ exec echo foo > /dev/null &
+ }
+ exec sleep 1
+ catch {exec ps | fgrep "echo foo" | fgrep -v fgrep | wc} msg
+ lindex $msg 0
+ } 0
+ test exec-12.2 {reaping background processes} {
+ exec sleep 2 | sleep 2 | sleep 2 &
+ catch {exec ps | fgrep "sleep 2" | fgrep -v fgrep | wc} msg
+ set x [lindex $msg 0]
+ exec sleep 3
+ catch {exec ps | fgrep "sleep 2" | fgrep -v fgrep | wc} msg
+ list $x [lindex $msg 0]
+ } {3 0}
+ test exec-12.3 {reaping background processes} {
+ exec sleep 1000 &
+ exec sleep 1000 &
+ set x [exec ps | fgrep "sleep 1000" | fgrep -v fgrep]
+ set pids {}
+ foreach i [split $x \n] {
+ lappend pids [lindex $i 0]
+ }
+ foreach i $pids {
+ catch {exec kill -STOP $i}
+ }
+ catch {exec ps | fgrep "sleep 1000" | fgrep -v fgrep | wc} msg
+ set x [lindex $msg 0]
+
+ foreach i $pids {
+ catch {exec kill -KILL $i}
+ }
+ catch {exec ps | fgrep "sleep 1000" | fgrep -v fgrep | wc} msg
+ list $x [lindex $msg 0]
+ } {2 0}
+}
+
+# Make sure "errorCode" is set correctly.
+
+test exec-13.1 {setting errorCode variable} {
+ list [catch {exec cat < a/b/c} msg] [string tolower $errorCode]
+} {1 {posix enoent {no such file or directory}}}
+test exec-13.2 {setting errorCode variable} {
+ list [catch {exec cat > a/b/c} msg] [string tolower $errorCode]
+} {1 {posix enoent {no such file or directory}}}
+test exec-13.3 {setting errorCode variable} {
+ set x [catch {exec _weirdo_command_} msg]
+ list $x $msg [lindex $errorCode 0] [lrange $errorCode 2 end]
+} {1 {couldn't find "_weirdo_command_" to execute} CHILDSTATUS 1}
+
+# Switches before the first argument
+
+test exec-14.1 {-keepnewline switch} {
+ exec -keepnewline echo foo
+} "foo\n"
+test exec-14.2 {-keepnewline switch} {
+ list [catch {exec -keepnewline} msg] $msg
+} {1 {wrong # args: should be "exec ?switches? arg ?arg ...?"}}
+test exec-14.3 {unknown switch} {
+ list [catch {exec -gorp} msg] $msg
+} {1 {bad switch "-gorp": must be -keepnewline or --}}
+test exec-14.4 {-- switch} {
+ list [catch {exec -- -gorp} msg] $msg
+} {1 {couldn't find "-gorp" to execute}}
+
+# Redirecting standard error separately from standard output
+
+test exec-15.1 {standard error redirection} {
+ exec echo "First line" > gorp.file
+ list [exec sh -c "echo foo bar 1>&2" 2> gorp.file] \
+ [exec cat gorp.file]
+} {{} {foo bar}}
+test exec-15.2 {standard error redirection} {
+ list [exec sh -c "echo foo bar 1>&2" | echo biz baz >gorp.file \
+ 2> gorp.file2] [exec cat gorp.file] \
+ [exec cat gorp.file2]
+} {{} {biz baz} {foo bar}}
+test exec-15.3 {standard error redirection} {
+ list [exec sh -c "echo foo bar 1>&2" | echo biz baz 2>gorp.file \
+ > gorp.file2] [exec cat gorp.file] \
+ [exec cat gorp.file2]
+} {{} {foo bar} {biz baz}}
+test exec-15.4 {standard error redirection} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec sh -c "echo foo bar 1>&2" 2>@ $f
+ puts $f "Line 3"
+ close $f
+ exec cat gorp.file
+} {Line 1
+foo bar
+Line 3}
+test exec-15.5 {standard error redirection} {
+ exec echo "First line" > gorp.file
+ exec sh -c "echo foo bar 1>&2" 2>> gorp.file
+ exec cat gorp.file
+} {First line
+foo bar}
+test exec-15.6 {standard error redirection} {
+ exec sh -c "echo foo bar 1>&2" > gorp.file2 2> gorp.file \
+ >& gorp.file 2> gorp.file2 | echo biz baz
+ list [exec cat gorp.file] [exec cat gorp.file2]
+} {{biz baz} {foo bar}}
+
+if $atBerkeley {
+ test exec-16.1 {restore signal settings before exec} {
+ set f [open {|cat exec.test} r]
+ list [catch {close $f} msg] [string tolower $msg]
+ } {1 {child killed: write on pipe with no readers}}
+}
+
+catch {exec rm -f gorp.file}
+catch {exec rm -f gorp.file2}
+return {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/expr.test b/vendor/x11iraf/obm/Tcl/tests/expr.test
new file mode 100644
index 00000000..199134fd
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/expr.test
@@ -0,0 +1,822 @@
+# Commands covered: expr
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/expr.test,v 1.30 93/09/08 16:46:45 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+if {([catch {expr T1()} msg] == 1) && ($msg == {unknown math function "T1"})} {
+ set gotT1 0
+ puts "This application hasn't been compiled with the \"T1\" and"
+ puts "\"T2\" math functions, so I'll skip some of the expr tests."
+} else {
+ set gotT1 1
+}
+
+# First, test all of the integer operators individually.
+
+test expr-1.1 {integer operators} {expr -4} -4
+test expr-1.2 {integer operators} {expr -(1+4)} -5
+test expr-1.3 {integer operators} {expr ~3} -4
+test expr-1.4 {integer operators} {expr !2} 0
+test expr-1.5 {integer operators} {expr !0} 1
+test expr-1.6 {integer operators} {expr 4*6} 24
+test expr-1.7 {integer operators} {expr 36/12} 3
+test expr-1.8 {integer operators} {expr 27/4} 6
+test expr-1.9 {integer operators} {expr 27%4} 3
+test expr-1.10 {integer operators} {expr 2+2} 4
+test expr-1.11 {integer operators} {expr 2-6} -4
+test expr-1.12 {integer operators} {expr 1<<3} 8
+test expr-1.13 {integer operators} {expr 0xff>>2} 63
+test expr-1.14 {integer operators} {expr -1>>2} -1
+test expr-1.15 {integer operators} {expr 3>2} 1
+test expr-1.16 {integer operators} {expr 2>2} 0
+test expr-1.17 {integer operators} {expr 1>2} 0
+test expr-1.18 {integer operators} {expr 3<2} 0
+test expr-1.19 {integer operators} {expr 2<2} 0
+test expr-1.20 {integer operators} {expr 1<2} 1
+test expr-1.21 {integer operators} {expr 3>=2} 1
+test expr-1.22 {integer operators} {expr 2>=2} 1
+test expr-1.23 {integer operators} {expr 1>=2} 0
+test expr-1.24 {integer operators} {expr 3<=2} 0
+test expr-1.25 {integer operators} {expr 2<=2} 1
+test expr-1.26 {integer operators} {expr 1<=2} 1
+test expr-1.27 {integer operators} {expr 3==2} 0
+test expr-1.28 {integer operators} {expr 2==2} 1
+test expr-1.29 {integer operators} {expr 3!=2} 1
+test expr-1.30 {integer operators} {expr 2!=2} 0
+test expr-1.31 {integer operators} {expr 7&0x13} 3
+test expr-1.32 {integer operators} {expr 7^0x13} 20
+test expr-1.33 {integer operators} {expr 7|0x13} 23
+test expr-1.34 {integer operators} {expr 0&&1} 0
+test expr-1.35 {integer operators} {expr 0&&0} 0
+test expr-1.36 {integer operators} {expr 1&&3} 1
+test expr-1.37 {integer operators} {expr 0||1} 1
+test expr-1.38 {integer operators} {expr 3||0} 1
+test expr-1.39 {integer operators} {expr 0||0} 0
+test expr-1.40 {integer operators} {expr 3>2?44:66} 44
+test expr-1.41 {integer operators} {expr 2>3?44:66} 66
+test expr-1.42 {integer operators} {expr 36/5} 7
+test expr-1.43 {integer operators} {expr 36%5} 1
+test expr-1.44 {integer operators} {expr -36/5} -8
+test expr-1.45 {integer operators} {expr -36%5} 4
+test expr-1.46 {integer operators} {expr 36/-5} -8
+test expr-1.47 {integer operators} {expr 36%-5} -4
+test expr-1.48 {integer operators} {expr -36/-5} 7
+test expr-1.49 {integer operators} {expr -36%-5} -1
+
+# Check the floating-point operators individually, along with
+# automatic conversion to integers where needed.
+
+test expr-2.1 {floating-point operators} {expr -4.2} -4.2
+test expr-2.2 {floating-point operators} {expr -(1.1+4.2)} -5.3
+test expr-2.3 {floating-point operators} {expr !2.1} 0
+test expr-2.4 {floating-point operators} {expr !0.0} 1
+test expr-2.5 {floating-point operators} {expr 4.2*6.3} 26.46
+test expr-2.6 {floating-point operators} {expr 36.0/12.0} 3.0
+test expr-2.7 {floating-point operators} {expr 27/4.0} 6.75
+test expr-2.8 {floating-point operators} {expr 2.3+2.1} 4.4
+test expr-2.9 {floating-point operators} {expr 2.3-6.5} -4.2
+test expr-2.10 {floating-point operators} {expr 3.1>2.1} 1
+test expr-2.11 {floating-point operators} {expr {2.1 > 2.1}} 0
+test expr-2.12 {floating-point operators} {expr 1.23>2.34e+1} 0
+test expr-2.13 {floating-point operators} {expr 3.45<2.34} 0
+test expr-2.14 {floating-point operators} {expr 0.002e3<--200e-2} 0
+test expr-2.15 {floating-point operators} {expr 1.1<2.1} 1
+test expr-2.16 {floating-point operators} {expr 3.1>=2.2} 1
+test expr-2.17 {floating-point operators} {expr 2.345>=2.345} 1
+test expr-2.18 {floating-point operators} {expr 1.1>=2.2} 0
+test expr-2.19 {floating-point operators} {expr 3.0<=2.0} 0
+test expr-2.20 {floating-point operators} {expr 2.2<=2.2} 1
+test expr-2.21 {floating-point operators} {expr 2.2<=2.2001} 1
+test expr-2.22 {floating-point operators} {expr 3.2==2.2} 0
+test expr-2.23 {floating-point operators} {expr 2.2==2.2} 1
+test expr-2.24 {floating-point operators} {expr 3.2!=2.2} 1
+test expr-2.25 {floating-point operators} {expr 2.2!=2.2} 0
+test expr-2.26 {floating-point operators} {expr 0.0&&0.0} 0
+test expr-2.27 {floating-point operators} {expr 0.0&&1.3} 0
+test expr-2.28 {floating-point operators} {expr 1.3&&0.0} 0
+test expr-2.29 {floating-point operators} {expr 1.3&&3.3} 1
+test expr-2.30 {floating-point operators} {expr 0.0||0.0} 0
+test expr-2.31 {floating-point operators} {expr 0.0||1.3} 1
+test expr-2.32 {floating-point operators} {expr 1.3||0.0} 1
+test expr-2.33 {floating-point operators} {expr 3.3||0.0} 1
+test expr-2.34 {floating-point operators} {expr 3.3>2.3?44.3:66.3} 44.3
+test expr-2.35 {floating-point operators} {expr 2.3>3.3?44.3:66.3} 66.3
+test expr-2.36 {floating-point operators} {
+ list [catch {expr 028.1 + 09.2} msg] $msg
+} {0 37.3}
+
+# Operators that aren't legal on floating-point numbers
+
+test expr-3.1 {illegal floating-point operations} {
+ list [catch {expr ~4.0} msg] $msg
+} {1 {can't use floating-point value as operand of "~"}}
+test expr-3.2 {illegal floating-point operations} {
+ list [catch {expr 27%4.0} msg] $msg
+} {1 {can't use floating-point value as operand of "%"}}
+test expr-3.3 {illegal floating-point operations} {
+ list [catch {expr 27.0%4} msg] $msg
+} {1 {can't use floating-point value as operand of "%"}}
+test expr-3.4 {illegal floating-point operations} {
+ list [catch {expr 1.0<<3} msg] $msg
+} {1 {can't use floating-point value as operand of "<<"}}
+test expr-3.5 {illegal floating-point operations} {
+ list [catch {expr 3<<1.0} msg] $msg
+} {1 {can't use floating-point value as operand of "<<"}}
+test expr-3.6 {illegal floating-point operations} {
+ list [catch {expr 24.0>>3} msg] $msg
+} {1 {can't use floating-point value as operand of ">>"}}
+test expr-3.7 {illegal floating-point operations} {
+ list [catch {expr 24>>3.0} msg] $msg
+} {1 {can't use floating-point value as operand of ">>"}}
+test expr-3.8 {illegal floating-point operations} {
+ list [catch {expr 24&3.0} msg] $msg
+} {1 {can't use floating-point value as operand of "&"}}
+test expr-3.9 {illegal floating-point operations} {
+ list [catch {expr 24.0|3} msg] $msg
+} {1 {can't use floating-point value as operand of "|"}}
+test expr-3.10 {illegal floating-point operations} {
+ list [catch {expr 24.0^3} msg] $msg
+} {1 {can't use floating-point value as operand of "^"}}
+
+# Check the string operators individually.
+
+test expr-4.1 {string operators} {expr {"abc" > "def"}} 0
+test expr-4.2 {string operators} {expr {"def" > "def"}} 0
+test expr-4.3 {string operators} {expr {"g" > "def"}} 1
+test expr-4.4 {string operators} {expr {"abc" < "abd"}} 1
+test expr-4.5 {string operators} {expr {"abd" < "abd"}} 0
+test expr-4.6 {string operators} {expr {"abe" < "abd"}} 0
+test expr-4.7 {string operators} {expr {"abc" >= "def"}} 0
+test expr-4.8 {string operators} {expr {"def" >= "def"}} 1
+test expr-4.9 {string operators} {expr {"g" >= "def"}} 1
+test expr-4.10 {string operators} {expr {"abc" <= "abd"}} 1
+test expr-4.11 {string operators} {expr {"abd" <= "abd"}} 1
+test expr-4.12 {string operators} {expr {"abe" <= "abd"}} 0
+test expr-4.13 {string operators} {expr {"abc" == "abd"}} 0
+test expr-4.14 {string operators} {expr {"abd" == "abd"}} 1
+test expr-4.15 {string operators} {expr {"abc" != "abd"}} 1
+test expr-4.16 {string operators} {expr {"abd" != "abd"}} 0
+test expr-4.17 {string operators} {expr {"0y" < "0x12"}} 1
+test expr-4.18 {string operators} {expr {"." < " "}} 0
+test expr-4.19 {string operators} {expr {"0" == "+"}} 0
+test expr-4.20 {string operators} {expr {"0" == "-"}} 0
+test expr-4.21 {string operators} {expr {1?"foo":"bar"}} foo
+test expr-4.22 {string operators} {expr {0?"foo":"bar"}} bar
+
+# Operators that aren't legal on string operands.
+
+test expr-5.1 {illegal string operations} {
+ list [catch {expr {-"a"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "-"}}
+test expr-5.2 {illegal string operations} {
+ list [catch {expr {~"a"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "~"}}
+test expr-5.3 {illegal string operations} {
+ list [catch {expr {!"a"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "!"}}
+test expr-5.4 {illegal string operations} {
+ list [catch {expr {"a"*"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "*"}}
+test expr-5.5 {illegal string operations} {
+ list [catch {expr {"a"/"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "/"}}
+test expr-5.6 {illegal string operations} {
+ list [catch {expr {"a"%"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "%"}}
+test expr-5.7 {illegal string operations} {
+ list [catch {expr {"a"+"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "+"}}
+test expr-5.8 {illegal string operations} {
+ list [catch {expr {"a"-"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "-"}}
+test expr-5.9 {illegal string operations} {
+ list [catch {expr {"a"<<"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "<<"}}
+test expr-5.10 {illegal string operations} {
+ list [catch {expr {"a">>"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of ">>"}}
+test expr-5.11 {illegal string operations} {
+ list [catch {expr {"a"&"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "&"}}
+test expr-5.12 {illegal string operations} {
+ list [catch {expr {"a"^"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "^"}}
+test expr-5.13 {illegal string operations} {
+ list [catch {expr {"a"|"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "|"}}
+test expr-5.14 {illegal string operations} {
+ list [catch {expr {"a"&&"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "&&"}}
+test expr-5.15 {illegal string operations} {
+ list [catch {expr {"a"||"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "||"}}
+test expr-5.16 {illegal string operations} {
+ list [catch {expr {"a"?4:2}} msg] $msg
+} {1 {can't use non-numeric string as operand of "?"}}
+
+# Check precedence pairwise.
+
+test expr-6.1 {precedence checks} {expr -~3} 4
+test expr-6.2 {precedence checks} {expr -!3} 0
+test expr-6.3 {precedence checks} {expr -~0} 1
+
+test expr-7.1 {precedence checks} {expr 2*4/6} 1
+test expr-7.2 {precedence checks} {expr 24/6*3} 12
+test expr-7.3 {precedence checks} {expr 24/6/2} 2
+
+test expr-8.1 {precedence checks} {expr -2+4} 2
+test expr-8.2 {precedence checks} {expr -2-4} -6
+
+test expr-9.1 {precedence checks} {expr 2*3+4} 10
+test expr-9.2 {precedence checks} {expr 8/2+4} 8
+test expr-9.3 {precedence checks} {expr 8%3+4} 6
+test expr-9.4 {precedence checks} {expr 2*3-1} 5
+test expr-9.5 {precedence checks} {expr 8/2-1} 3
+test expr-9.6 {precedence checks} {expr 8%3-1} 1
+
+test expr-10.1 {precedence checks} {expr 6-3-2} 1
+
+test expr-11.1 {precedence checks} {expr 7+1>>2} 2
+test expr-11.2 {precedence checks} {expr 7+1<<2} 32
+test expr-11.3 {precedence checks} {expr 7>>3-2} 3
+test expr-11.4 {precedence checks} {expr 7<<3-2} 14
+
+test expr-12.1 {precedence checks} {expr 6>>1>4} 0
+test expr-12.2 {precedence checks} {expr 6>>1<2} 0
+test expr-12.3 {precedence checks} {expr 6>>1>=3} 1
+test expr-12.4 {precedence checks} {expr 6>>1<=2} 0
+test expr-12.5 {precedence checks} {expr 6<<1>5} 1
+test expr-12.6 {precedence checks} {expr 6<<1<5} 0
+test expr-12.7 {precedence checks} {expr 5<=6<<1} 1
+test expr-12.8 {precedence checks} {expr 5>=6<<1} 0
+
+test expr-13.1 {precedence checks} {expr 2<3<4} 1
+test expr-13.2 {precedence checks} {expr 0<4>2} 0
+test expr-13.3 {precedence checks} {expr 4>2<1} 0
+test expr-13.4 {precedence checks} {expr 4>3>2} 0
+test expr-13.5 {precedence checks} {expr 4>3>=2} 0
+test expr-13.6 {precedence checks} {expr 4>=3>2} 0
+test expr-13.7 {precedence checks} {expr 4>=3>=2} 0
+test expr-13.8 {precedence checks} {expr 0<=4>=2} 0
+test expr-13.9 {precedence checks} {expr 4>=2<=0} 0
+test expr-10.10 {precedence checks} {expr 2<=3<=4} 1
+
+test expr-14.1 {precedence checks} {expr 1==4>3} 1
+test expr-14.2 {precedence checks} {expr 0!=4>3} 1
+test expr-14.3 {precedence checks} {expr 1==3<4} 1
+test expr-14.4 {precedence checks} {expr 0!=3<4} 1
+test expr-14.5 {precedence checks} {expr 1==4>=3} 1
+test expr-14.6 {precedence checks} {expr 0!=4>=3} 1
+test expr-14.7 {precedence checks} {expr 1==3<=4} 1
+test expr-14.8 {precedence checks} {expr 0!=3<=4} 1
+
+test expr-15.1 {precedence checks} {expr 1==3==3} 0
+test expr-15.2 {precedence checks} {expr 3==3!=2} 1
+test expr-15.3 {precedence checks} {expr 2!=3==3} 0
+test expr-15.4 {precedence checks} {expr 2!=1!=1} 0
+
+test expr-16.1 {precedence checks} {expr 2&3==2} 0
+test expr-16.2 {precedence checks} {expr 1&3!=3} 0
+
+test expr-17.1 {precedence checks} {expr 7&3^0x10} 19
+test expr-17.2 {precedence checks} {expr 7^0x10&3} 7
+
+test expr-18.1 {precedence checks} {expr 7^0x10|3} 23
+test expr-18.2 {precedence checks} {expr 7|0x10^3} 23
+
+test expr-19.1 {precedence checks} {expr 7|3&&1} 1
+test expr-19.2 {precedence checks} {expr 1&&3|7} 1
+test expr-19.3 {precedence checks} {expr 0&&1||1} 1
+test expr-19.4 {precedence checks} {expr 1||1&&0} 1
+
+test expr-20.1 {precedence checks} {expr 1||0?3:4} 3
+test expr-20.2 {precedence checks} {expr 1?0:4||1} 0
+
+# Parentheses.
+
+test expr-21.1 {parenthesization} {expr (2+4)*6} 36
+test expr-21.2 {parenthesization} {expr (1?0:4)||1} 1
+
+# Embedded commands and variable names.
+
+set a 16
+test expr-22.1 {embedded variables} {expr {2*$a}} 32
+test expr-22.2 {embedded variables} {
+ set x -5
+ set y 10
+ expr {$x + $y}
+} {5}
+test expr-22.3 {embedded variables} {
+ set x " -5"
+ set y " +10"
+ expr {$x + $y}
+} {5}
+test expr-22.4 {embedded commands and variables} {expr {[set a] - 14}} 2
+test expr-22.5 {embedded commands and variables} {
+ list [catch {expr {12 - [bad_command_name]}} msg] $msg
+} {1 {invalid command name: "bad_command_name"}}
+
+# Double-quotes and things inside them.
+
+test expr-23.1 {double-quotes} {expr {"abc"}} abc
+test expr-23.2 {double-quotes} {
+ set a 189
+ expr {"$a.bc"}
+} 189.bc
+test expr-23.3 {double-quotes} {
+ set b2 xyx
+ expr {"$b2$b2$b2.[set b2].[set b2]"}
+} xyxxyxxyx.xyx.xyx
+test expr-23.4 {double-quotes} {expr {"11\}\}22"}} 11}}22
+test expr-23.5 {double-quotes} {expr {"\*bc"}} {*bc}
+test expr-23.6 {double-quotes} {
+ catch {unset bogus__}
+ list [catch {expr {"$bogus__"}} msg] $msg
+} {1 {can't read "bogus__": no such variable}}
+test expr-23.7 {double-quotes} {
+ list [catch {expr {"a[error Testing]bc"}} msg] $msg
+} {1 Testing}
+
+# Numbers in various bases.
+
+test expr-24.1 {numbers in different bases} {expr 0x20} 32
+test expr-24.2 {numbers in different bases} {expr 015} 13
+
+# Conversions between various data types.
+
+test expr-25.1 {type conversions} {expr 2+2.5} 4.5
+test expr-25.2 {type conversions} {expr 2.5+2} 4.5
+test expr-25.3 {type conversions} {expr 2-2.5} -0.5
+test expr-25.4 {type conversions} {expr 2/2.5} 0.8
+test expr-25.5 {type conversions} {expr 2>2.5} 0
+test expr-25.6 {type conversions} {expr 2.5>2} 1
+test expr-25.7 {type conversions} {expr 2<2.5} 1
+test expr-25.8 {type conversions} {expr 2>=2.5} 0
+test expr-25.9 {type conversions} {expr 2<=2.5} 1
+test expr-25.10 {type conversions} {expr 2==2.5} 0
+test expr-25.11 {type conversions} {expr 2!=2.5} 1
+test expr-25.12 {type conversions} {expr 2>"ab"} 0
+test expr-25.13 {type conversions} {expr {2>" "}} 1
+test expr-25.14 {type conversions} {expr {"24.1a" > 24.1}} 1
+test expr-25.15 {type conversions} {expr {24.1 > "24.1a"}} 0
+test expr-25.16 {type conversions} {expr 2+2.5} 4.5
+test expr-25.17 {type conversions} {expr 2+2.5} 4.5
+test expr-25.18 {type conversions} {expr 2.0e2} 200.0
+test expr-25.19 {type conversions} {expr 2.0e15} 2e+15
+test expr-25.20 {type conversions} {expr 10.0} 10.0
+
+# Various error conditions.
+
+test expr-26.1 {error conditions} {
+ list [catch {expr 2+"a"} msg] $msg
+} {1 {can't use non-numeric string as operand of "+"}}
+test expr-26.2 {error conditions} {
+ list [catch {expr 2+4*} msg] $msg
+} {1 {syntax error in expression "2+4*"}}
+test expr-26.3 {error conditions} {
+ list [catch {expr 2+4*(} msg] $msg
+} {1 {syntax error in expression "2+4*("}}
+catch {unset _non_existent_}
+test expr-26.4 {error conditions} {
+ list [catch {expr 2+$_non_existent_} msg] $msg
+} {1 {can't read "_non_existent_": no such variable}}
+set a xx
+test expr-26.5 {error conditions} {
+ list [catch {expr {2+$a}} msg] $msg
+} {1 {can't use non-numeric string as operand of "+"}}
+test expr-26.6 {error conditions} {
+ list [catch {expr {2+[set a]}} msg] $msg
+} {1 {can't use non-numeric string as operand of "+"}}
+test expr-26.7 {error conditions} {
+ list [catch {expr {2+(4}} msg] $msg
+} {1 {unmatched parentheses in expression "2+(4"}}
+test expr-26.8 {error conditions} {
+ list [catch {expr 2/0} msg] $msg $errorCode
+} {1 {divide by zero} {ARITH DIVZERO {divide by zero}}}
+test expr-26.9 {error conditions} {
+ list [catch {expr 2%0} msg] $msg $errorCode
+} {1 {divide by zero} {ARITH DIVZERO {divide by zero}}}
+test expr-26.10 {error conditions} {
+ list [catch {expr 2.0/0.0} msg] $msg $errorCode
+} {1 {divide by zero} {ARITH DIVZERO {divide by zero}}}
+test expr-26.11 {error conditions} {
+ list [catch {expr 2#} msg] $msg
+} {1 {syntax error in expression "2#"}}
+test expr-26.12 {error conditions} {
+ list [catch {expr a.b} msg] $msg
+} {1 {syntax error in expression "a.b"}}
+test expr-26.13 {error conditions} {
+ list [catch {expr {"a"/"b"}} msg] $msg
+} {1 {can't use non-numeric string as operand of "/"}}
+test expr-26.14 {error conditions} {
+ list [catch {expr 2:3} msg] $msg
+} {1 {can't have : operator without ? first}}
+test expr-26.15 {error conditions} {
+ list [catch {expr a@b} msg] $msg
+} {1 {syntax error in expression "a@b"}}
+test expr-26.16 {error conditions} {
+ list [catch {expr a[b} msg] $msg
+} {1 {missing close-bracket}}
+test expr-26.17 {error conditions} {
+ list [catch {expr a`b} msg] $msg
+} {1 {syntax error in expression "a`b"}}
+test expr-26.18 {error conditions} {
+ list [catch {expr \"a\"\{b} msg] $msg
+} {1 {missing close-brace}}
+test expr-26.19 {error conditions} {
+ list [catch {expr a} msg] $msg
+} {1 {syntax error in expression "a"}}
+test expr-26.20 {error conditions} {
+ list [catch expr msg] $msg
+} {1 {wrong # args: should be "expr arg ?arg ...?"}}
+
+# Cancelled evaluation.
+
+test expr-27.1 {cancelled evaluation} {
+ set a 1
+ expr {0&&[set a 2]}
+ set a
+} 1
+test expr-27.2 {cancelled evaluation} {
+ set a 1
+ expr {1||[set a 2]}
+ set a
+} 1
+test expr-27.3 {cancelled evaluation} {
+ set a 1
+ expr {0?[set a 2]:1}
+ set a
+} 1
+test expr-27.4 {cancelled evaluation} {
+ set a 1
+ expr {1?2:[set a 2]}
+ set a
+} 1
+catch {unset x}
+test expr-27.5 {cancelled evaluation} {
+ list [catch {expr {[info exists x] && $x}} msg] $msg
+} {0 0}
+test expr-27.6 {cancelled evaluation} {
+ list [catch {expr {0 && [concat $x]}} msg] $msg
+} {0 0}
+
+# Tcl_ExprBool as used in "if" statements
+
+test expr-28.1 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {2} {set a 2}
+ set a
+} 2
+test expr-28.2 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {0} {set a 2}
+ set a
+} 1
+test expr-28.3 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {1.2} {set a 2}
+ set a
+} 2
+test expr-28.4 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {-1.1} {set a 2}
+ set a
+} 2
+test expr-28.5 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {0.0} {set a 2}
+ set a
+} 1
+test expr-28.6 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"YES"} {set a 2}
+ set a
+} 2
+test expr-28.7 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"no"} {set a 2}
+ set a
+} 1
+test expr-28.8 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"true"} {set a 2}
+ set a
+} 2
+test expr-28.9 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"fAlse"} {set a 2}
+ set a
+} 1
+test expr-28.10 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"on"} {set a 2}
+ set a
+} 2
+test expr-28.11 {Tcl_ExprBoolean usage} {
+ set a 1
+ if {"Off"} {set a 2}
+ set a
+} 1
+test expr-28.12 {Tcl_ExprBool usage} {
+ list [catch {if {"abc"} {}} msg] $msg
+} {1 {expected boolean value but got "abc"}}
+
+# Operands enclosed in braces
+
+test expr-29.1 {braces} {expr {{abc}}} abc
+test expr-29.2 {braces} {expr {{00010}}} 8
+test expr-29.3 {braces} {expr {{3.1200000}}} 3.12
+test expr-29.4 {braces} {expr {{a{b}{1 {2 3}}c}}} "a{b}{1 {2 3}}c"
+test expr-29.5 {braces} {
+ list [catch {expr "\{abc"} msg] $msg
+} {1 {missing close-brace}}
+
+# Very long values
+
+test expr-30.1 {long values} {
+ set a "0000 1111 2222 3333 4444"
+ set a "$a | $a | $a | $a | $a"
+ set a "$a || $a || $a || $a || $a"
+ expr {$a}
+} {0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444}
+test expr-30.2 {long values} {
+ set a "000000000000000000000000000000"
+ set a "$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a${a}5"
+ expr $a
+} 5
+
+# Expressions spanning multiple arguments
+
+test expr-31.1 {multiple arguments to expr command} {
+ expr 4 + ( 6 *12) -3
+} 73
+test expr-31.2 {multiple arguments to expr command} {
+ list [catch {expr 2 + (3 + 4} msg] $msg
+} {1 {unmatched parentheses in expression "2 + (3 + 4"}}
+test expr-31.3 {multiple arguments to expr command} {
+ list [catch {expr 2 + 3 +} msg] $msg
+} {1 {syntax error in expression "2 + 3 +"}}
+test expr-31.4 {multiple arguments to expr command} {
+ list [catch {expr 2 + 3 )} msg] $msg
+} {1 {syntax error in expression "2 + 3 )"}}
+
+# Math functions
+
+test expr-32.1 {math functions in expressions} {
+ expr acos(0.5)
+} {1.0472}
+test expr-32.2 {math functions in expressions} {
+ expr asin(0.5)
+} {0.523599}
+test expr-32.3 {math functions in expressions} {
+ expr atan(1.0)
+} {0.785398}
+test expr-32.4 {math functions in expressions} {
+ expr atan2(2.0, 2.0)
+} {0.785398}
+test expr-32.5 {math functions in expressions} {
+ expr ceil(1.999)
+} {2.0}
+test expr-32.6 {math functions in expressions} {
+ expr cos(.1)
+} {0.995004}
+test expr-32.7 {math functions in expressions} {
+ expr cosh(.1)
+} {1.005}
+test expr-32.8 {math functions in expressions} {
+ expr exp(1.0)
+} {2.71828}
+test expr-32.9 {math functions in expressions} {
+ expr floor(2.000)
+} {2.0}
+test expr-32.10 {math functions in expressions} {
+ expr floor(2.001)
+} {2.0}
+test expr-32.11 {math functions in expressions} {
+ expr fmod(7.3, 3.2)
+} {0.9}
+test expr-32.12 {math functions in expressions} {
+ expr hypot(3.0, 4.0)
+} {5.0}
+test expr-32.13 {math functions in expressions} {
+ expr log(2.8)
+} {1.02962}
+test expr-32.14 {math functions in expressions} {
+ expr log10(2.8)
+} {0.447158}
+test expr-32.15 {math functions in expressions} {
+ expr pow(2.1, 3.1)
+} {9.97424}
+test expr-32.16 {math functions in expressions} {
+ expr sin(.1)
+} {0.0998334}
+test expr-32.17 {math functions in expressions} {
+ expr sinh(.1)
+} {0.100167}
+test expr-32.18 {math functions in expressions} {
+ expr sqrt(2.0)
+} {1.41421}
+test expr-32.19 {math functions in expressions} {
+ expr tan(0.8)
+} {1.02964}
+test expr-32.20 {math functions in expressions} {
+ expr tanh(0.8)
+} {0.664037}
+test expr-32.21 {math functions in expressions} {
+ expr abs(-1.8)
+} {1.8}
+test expr-32.22 {math functions in expressions} {
+ expr abs(10.0)
+} {10.0}
+test expr-32.23 {math functions in expressions} {
+ expr abs(-4)
+} {4}
+test expr-32.24 {math functions in expressions} {
+ expr abs(66)
+} {66}
+if ($atBerkeley) {
+ test expr-32.25 {math functions in expressions} {
+ list [catch {expr abs(0x80000000)} msg] $msg
+ } {1 {integer value too large to represent}}
+}
+test expr-32.26 {math functions in expressions} {
+ expr double(1)
+} {1.0}
+test expr-32.27 {math functions in expressions} {
+ expr double(1.1)
+} {1.1}
+test expr-32.28 {math functions in expressions} {
+ expr int(1)
+} {1}
+test expr-32.29 {math functions in expressions} {
+ expr int(1.4)
+} {1}
+test expr-32.30 {math functions in expressions} {
+ expr int(1.6)
+} {1}
+test expr-32.31 {math functions in expressions} {
+ expr int(-1.4)
+} {-1}
+test expr-32.32 {math functions in expressions} {
+ expr int(-1.6)
+} {-1}
+test expr-32.33 {math functions in expressions} {
+ list [catch {expr int(1e60)} msg] $msg
+} {1 {integer value too large to represent}}
+test expr-32.34 {math functions in expressions} {
+ list [catch {expr int(-1e60)} msg] $msg
+} {1 {integer value too large to represent}}
+test expr-32.35 {math functions in expressions} {
+ expr round(1.49)
+} {1}
+test expr-32.36 {math functions in expressions} {
+ expr round(1.51)
+} {2}
+test expr-32.37 {math functions in expressions} {
+ expr round(-1.49)
+} {-1}
+test expr-32.38 {math functions in expressions} {
+ expr round(-1.51)
+} {-2}
+test expr-32.39 {math functions in expressions} {
+ list [catch {expr round(1e60)} msg] $msg
+} {1 {integer value too large to represent}}
+test expr-32.40 {math functions in expressions} {
+ list [catch {expr round(-1e60)} msg] $msg
+} {1 {integer value too large to represent}}
+test expr-32.41 {math functions in expressions} {
+ list [catch {expr pow(1.0 + 3.0 - 2, .8 * 5)} msg] $msg
+} {0 16.0}
+test expr-32.42 {math functions in expressions} {
+ list [catch {expr hypot(5*.8,3)} msg] $msg
+} {0 5.0}
+if $gotT1 {
+ test expr-32.43 {math functions in expressions} {
+ expr 2*T1()
+ } 246
+ test expr-32.44 {math functions in expressions} {
+ expr T2()*3
+ } 1035
+}
+
+test expr-33.1 {conversions and fancy args to math functions} {
+ expr hypot ( 3 , 4 )
+} 5.0
+test expr-33.2 {conversions and fancy args to math functions} {
+ expr hypot ( (2.0+1.0) , 4 )
+} 5.0
+test expr-33.3 {conversions and fancy args to math functions} {
+ expr hypot ( 3 , (3.0 + 1.0) )
+} 5.0
+test expr-33.4 {conversions and fancy args to math functions} {
+ expr cos(acos(0.1))
+} 0.1
+
+test expr-34.1 {errors in math functions} {
+ list [catch {expr func_2(1.0)} msg] $msg
+} {1 {unknown math function "func_2"}}
+test expr-34.2 {errors in math functions} {
+ list [catch {expr func|(1.0)} msg] $msg
+} {1 {syntax error in expression "func|(1.0)"}}
+test expr-34.3 {errors in math functions} {
+ list [catch {expr {hypot("a b", 2.0)}} msg] $msg
+} {1 {argument to math function didn't have numeric value}}
+test expr-34.4 {errors in math functions} {
+ list [catch {expr hypot(1.0 2.0)} msg] $msg
+} {1 {syntax error in expression "hypot(1.0 2.0)"}}
+test expr-34.5 {errors in math functions} {
+ list [catch {expr hypot(1.0, 2.0} msg] $msg
+} {1 {syntax error in expression "hypot(1.0, 2.0"}}
+test expr-34.6 {errors in math functions} {
+ list [catch {expr hypot(1.0 ,} msg] $msg
+} {1 {syntax error in expression "hypot(1.0 ,"}}
+test expr-34.7 {errors in math functions} {
+ list [catch {expr hypot(1.0)} msg] $msg
+} {1 {too few arguments for math function}}
+test expr-34.8 {errors in math functions} {
+ list [catch {expr hypot(1.0, 2.0, 3.0)} msg] $msg
+} {1 {too many arguments for math function}}
+test expr-34.9 {errors in math functions} {
+ list [catch {expr acos(-2.0)} msg] $msg $errorCode
+} {1 {domain error: argument not in valid range} {ARITH DOMAIN {domain error: argument not in valid range}}}
+if $atBerkeley {
+ test expr-34.10 {errors in math functions} {
+ list [catch {expr pow(-3, 1000001)} msg] $msg $errorCode
+ } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}}
+}
+test expr-34.11 {errors in math functions} {
+ list [catch {expr pow(3, 1000001)} msg] $msg $errorCode
+} {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}}
+test expr-34.12 {errors in math functions} {
+ list [catch {expr -14.0*exp(100000)} msg] $msg $errorCode
+} {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}}
+test expr-34.13 {errors in math functions} {
+ list [catch {expr int(1.0e30)} msg] $msg $errorCode
+} {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}}
+test expr-34.14 {errors in math functions} {
+ list [catch {expr int(-1.0e30)} msg] $msg $errorCode
+} {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}}
+test expr-34.15 {errors in math functions} {
+ list [catch {expr round(1.0e30)} msg] $msg $errorCode
+} {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}}
+test expr-34.16 {errors in math functions} {
+ list [catch {expr round(-1.0e30)} msg] $msg $errorCode
+} {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}}
+if $gotT1 {
+ test expr-34.17 {errors in math functions} {
+ list [catch {expr T1(4)} msg] $msg
+ } {1 {syntax error in expression "T1(4)"}}
+}
+
+catch {unset tcl_precision}
+test expr-35.1 {tcl_precision variable} {
+ expr 2.0/3
+} 0.666667
+set tcl_precision 1
+test expr-35.2 {tcl_precision variable} {
+ expr 2.0/3
+} 0.7
+test expr-35.3 {tcl_precision variable} {
+ expr 2.0/3
+} 0.7
+test expr-35.4 {tcl_precision variable} {
+ list [catch {set tcl_precision 0} msg] $msg [expr 2.0/3]
+} {1 {can't set "tcl_precision": improper value for precision} 0.7}
+test expr-35.5 {tcl_precision variable} {
+ list [catch {set tcl_precision 101} msg] $msg [expr 2.0/3]
+} {1 {can't set "tcl_precision": improper value for precision} 0.7}
+test expr-35.6 {tcl_precision variable} {
+ list [catch {set tcl_precision {}} msg] $msg [expr 2.0/3]
+} {1 {can't set "tcl_precision": improper value for precision} 0.7}
+test expr-35.7 {tcl_precision variable} {
+ list [catch {set tcl_precision {1 2 3}} msg] $msg [expr 2.0/3]
+} {1 {can't set "tcl_precision": improper value for precision} 0.7}
+catch {unset tcl_precision}
+test expr-35.8 {tcl_precision variable} {
+ expr 2.0/3
+} 0.666667
diff --git a/vendor/x11iraf/obm/Tcl/tests/file.test b/vendor/x11iraf/obm/Tcl/tests/file.test
new file mode 100644
index 00000000..83603342
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/file.test
@@ -0,0 +1,326 @@
+# Commands covered: file
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/file.test,v 1.22 93/04/16 16:46:42 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# rootname and ext
+
+test file-1.1 {rootname and extension options} {file ext abc.def} .def
+test file-1.2 {rootname and extension options} {file ro abc.def} abc
+test file-1.3 {rootname and extension options} {file extension a/b/c.d} .d
+test file-1.4 {rootname and extension options} {file rootname a/b/c.d} a/b/c
+test file-1.5 {rootname and extension options} {file extension a/b.c/d} {}
+test file-1.6 {rootname and extension options} {file rootname a/b.c/d} a/b.c/d
+set num 7
+foreach outer { {} a .a a. a.a } {
+ foreach inner { {} a .a a. a.a } {
+ set thing [format %s/%s $outer $inner]
+ test file-1.$num {rootname and extension options} {
+ format %s%s [file rootname $thing] [file ext $thing]
+ } $thing
+ set num [expr $num+1]
+ }
+}
+
+# dirname and tail
+
+test file-2.1 {dirname and tail options} {file dirname .def} .
+test file-2.2 {dirname and tail options} {file tail abc.def} abc.def
+test file-2.3 {dirname and tail options} {file d a/b/c.d} a/b
+test file-2.4 {dirname and tail options} {file ta a/b/c.d} c.d
+test file-2.5 {dirname and tail options} {file dirname a/b.c/d} a/b.c
+test file-2.6 {dirname and tail options} {file tail a/b.c/d} d
+set num 7
+foreach outer { a .a a. a.a } {
+ foreach inner { {} a .a a. a.a } {
+ set thing [format %s/%s $outer $inner]
+ test file-2.$num {dirname and tail options} {
+ format %s/%s [file dirname $thing] [file tail $thing]
+ } $thing
+ set num [expr $num+1]
+ }
+}
+
+# exists
+
+catch {exec chmod 777 dir.file}
+catch {exec rm -f dir.file/gorp.file}
+catch {exec rm -f gorp.file}
+catch {exec rmdir dir.file}
+catch {exec rm -f link.file}
+test file-3.1 {exists option} {file exists gorp.file} 0
+test file-3.2 {exists option} {file exists dir.file/gorp.file} 0
+exec cat > gorp.file << abcde
+exec mkdir dir.file
+exec cat > dir.file/gorp.file << 12345
+test file-3.3 {exists option} {file exists gorp.file} 1
+test file-3.4 {exists option} {file exi dir.file/gorp.file} 1
+
+# The test below has to be done in /tmp rather than the current
+# directory in order to guarantee (?) a local file system: some
+# NFS file systems won't do the stuff below correctly.
+
+catch {exec rm /tmp/tcl.foo.dir/file}
+catch {exec rmdir /tmp/tcl.foo.dir}
+exec mkdir /tmp/tcl.foo.dir
+exec cat > /tmp/tcl.foo.dir/file << 12345
+exec chmod 000 /tmp/tcl.foo.dir
+if {$user != "root"} {
+ test file-3.5 {exists option} {file exists /tmp/tcl.foo.dir/file} 0
+}
+exec chmod 775 /tmp/tcl.foo.dir
+exec rm /tmp/tcl.foo.dir/file
+exec rmdir /tmp/tcl.foo.dir
+
+# executable
+
+exec chmod 000 dir.file
+if {$user != "root"} {
+ test file-4.1 {executable option} {file executable gorp.file} 0
+}
+exec chmod 775 gorp.file
+test file-4.2 {executable option} {file exe gorp.file} 1
+
+# isdirectory
+
+test file-5.1 {isdirectory option} {file isdirectory gorp.file} 0
+test file-5.2 {isdirectory option} {file isd dir.file} 1
+
+# isfile
+
+test file-6.1 {isfile option} {file isfile gorp.file} 1
+test file-6.2 {isfile option} {file isfile dir.file} 0
+
+# isowned
+
+test file-7.1 {owned option} {file owned gorp.file} 1
+if {$user != "root"} {
+ test file-7.2 {owned option} {file owned /} 0
+}
+
+# readable
+
+exec chmod 444 gorp.file
+test file-8.1 {readable option} {file readable gorp.file} 1
+exec chmod 333 gorp.file
+if {$user != "root"} {
+ test file-8.2 {readable option} {file reada gorp.file} 0
+}
+
+# writable
+
+exec chmod 555 gorp.file
+if {$user != "root"} {
+ test file-9.1 {writable option} {file writable gorp.file} 0
+}
+exec chmod 222 gorp.file
+test file-9.2 {writable option} {file w gorp.file} 1
+
+# stat
+
+exec cat > gorp.file << "Test string"
+exec chmod 765 gorp.file
+test file-10.1 {stat option} {
+ catch {unset stat}
+ file stat gorp.file stat
+ lsort [array names stat]
+} {atime ctime dev gid ino mode mtime nlink size type uid}
+test file-10.2 {stat option} {
+ catch {unset stat}
+ file stat gorp.file stat
+ list $stat(nlink) $stat(size) [expr $stat(mode)&0777] $stat(type)
+} {1 11 501 file}
+test file-10.3 {stat option} {
+ string tolower [list [catch {file stat _bogus_ stat} msg] \
+ $msg $errorCode]
+} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+test file-10.4 {stat option} {
+ list [catch {file stat _bogus_} msg] $msg $errorCode
+} {1 {wrong # args: should be "file stat name varName"} NONE}
+test file-10.5 {stat option} {
+ list [catch {file stat _bogus_ a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "file stat name varName"} NONE}
+test file-10.6 {stat option} {
+ catch {unset x}
+ set x 44
+ list [catch {file stat gorp.file x} msg] $msg $errorCode
+} {1 {can't set "x(dev)": variable isn't array} NONE}
+catch {unset stat}
+
+# mtime, and size (I've given up trying to find a test for "atime": there
+# seem to be too many quirks in the way file systems handle this to come
+# up with a reproducible test).
+
+test file-11.1 {mtime and atime and size options} {
+ catch {unset stat}
+ file stat gorp.file stat
+ list [expr {[file mtime gorp.file] == $stat(mtime)}] \
+ [expr {[file atime gorp.file] == $stat(atime)}] \
+ [file size gorp.file]
+} {1 1 11}
+test file-11.2 {mtime option} {
+ set old [file mtime gorp.file]
+ exec sleep 2
+ set f [open gorp.file w]
+ puts $f "More text"
+ close $f
+ set new [file mtime gorp.file]
+ expr {($new > $old) && ($new <= ($old+5))}
+} {1}
+test file-11.3 {size option} {
+ set oldsize [file size gorp.file]
+ set f [open gorp.file a]
+ puts $f "More text"
+ close $f
+ expr {[file size gorp.file] - $oldsize}
+} {10}
+test file-11.4 {errors in atime option} {
+ list [catch {file atime _bogus_ x} msg] $msg $errorCode
+} {1 {wrong # args: should be "file atime name"} NONE}
+test file-11.5 {errors in atime option} {
+ string tolower [list [catch {file atime _bogus_} msg] \
+ $msg $errorCode]
+} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+test file-11.6 {errors in mtime option} {
+ list [catch {file mtime _bogus_ x} msg] $msg $errorCode
+} {1 {wrong # args: should be "file mtime name"} NONE}
+test file-11.7 {errors in mtime option} {
+ string tolower [list [catch {file mtime _bogus_} msg] $msg \
+ $errorCode]
+} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+test file-11.8 {errors in size option} {
+ list [catch {file size _bogus_ x} msg] $msg $errorCode
+} {1 {wrong # args: should be "file size name"} NONE}
+test file-11.9 {errors in size option} {
+ string tolower [list [catch {file size _bogus_} msg] $msg \
+ $errorCode]
+} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+
+# type
+
+test file-12.1 {type option} {
+ file type dir.file
+} directory
+test file-12.2 {type option} {
+ file type gorp.file
+} file
+if $atBerkeley {
+ exec ln -s a/b/c link.file
+ test file-12.3 {type option} {
+ file type link.file
+ } link
+ exec rm link.file
+}
+test file-12.4 {errors in type option} {
+ list [catch {file type a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "file type name"} NONE}
+test file-12.5 {errors in type option} {
+ string tolower [list [catch {file type _bogus_} msg] $msg $errorCode]
+} {1 {couldn't stat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+
+# lstat and readlink: run these tests only at Berkeley, since not all
+# sites will have symbolic links
+
+if $atBerkeley {
+ exec ln -s gorp.file link.file
+ test file-13.1 {lstat option} {
+ catch {unset stat}
+ file lstat link.file stat
+ lsort [array names stat]
+ } {atime ctime dev gid ino mode mtime nlink size type uid}
+ test file-13.1 {lstat option} {
+ catch {unset stat}
+ file lstat link.file stat
+ list $stat(nlink) [expr $stat(mode)&0777] $stat(type)
+ } {1 511 link}
+ test file-13.3 {errors in lstat option} {
+ string tolower [list [catch {file lstat _bogus_ stat} msg] \
+ $msg $errorCode]
+ } {1 {couldn't lstat "_bogus_": no such file or directory} {posix enoent {no such file or directory}}}
+ test file-13.4 {errors in lstat option} {
+ list [catch {file lstat _bogus_} msg] $msg $errorCode
+ } {1 {wrong # args: should be "file lstat name varName"} NONE}
+ test file-13.5 {errors in lstat option} {
+ list [catch {file lstat _bogus_ a b} msg] $msg $errorCode
+ } {1 {wrong # args: should be "file lstat name varName"} NONE}
+ test file-13.6 {errors in lstat option} {
+ catch {unset x}
+ set x 44
+ list [catch {file lstat gorp.file x} msg] $msg $errorCode
+ } {1 {can't set "x(dev)": variable isn't array} NONE}
+ catch {unset stat}
+
+ test file-14.1 {readlink option} {
+ file readlink link.file
+ } gorp.file
+ test file-14.2 {errors in readlink option} {
+ list [catch {file readlink a b} msg] $msg $errorCode
+ } {1 {wrong # args: should be "file readlink name"} NONE}
+ test file-14.3 {errors in readlink option} {
+ list [catch {file readlink _bogus_} msg] $msg $errorCode
+ } {1 {couldn't readlink "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}}
+
+ exec rm link.file
+}
+
+# Error conditions
+
+test file-15.1 {error conditions} {
+ list [catch file msg] $msg
+} {1 {wrong # args: should be "file option name ?arg ...?"}}
+test file-15.2 {error conditions} {
+ list [catch {file x} msg] $msg
+} {1 {wrong # args: should be "file option name ?arg ...?"}}
+test file-15.3 {error conditions} {
+ list [catch {file exists x too} msg] $msg
+} {1 {wrong # args: should be "file exists name"}}
+test file-15.4 {error conditions} {
+ list [catch {file gorp x} msg] $msg
+} {1 {bad option "gorp": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.5 {error conditions} {
+ list [catch {file ex x} msg] $msg
+} {1 {bad option "ex": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.6 {error conditions} {
+ list [catch {file is x} msg] $msg
+} {1 {bad option "is": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.7 {error conditions} {
+ list [catch {file read x} msg] $msg
+} {1 {bad option "read": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.8 {error conditions} {
+ list [catch {file s x} msg] $msg
+} {1 {bad option "s": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.9 {error conditions} {
+ list [catch {file t x} msg] $msg
+} {1 {bad option "t": should be atime, dirname, executable, exists, extension, isdirectory, isfile, lstat, mtime, owned, readable, readlink, root, size, stat, tail, type, or writable}}
+test file-15.10 {error conditions} {
+ list [catch {file rootname ~woohgy} msg] $msg
+} {1 {user "woohgy" doesn't exist}}
+
+exec chmod 777 dir.file
+exec rm dir.file/gorp.file gorp.file
+exec rmdir dir.file
diff --git a/vendor/x11iraf/obm/Tcl/tests/for.test b/vendor/x11iraf/obm/Tcl/tests/for.test
new file mode 100644
index 00000000..2fafcc5a
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/for.test
@@ -0,0 +1,169 @@
+# Commands covered: foreach, for, continue, break
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/for.test,v 1.8 93/02/06 15:54:05 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# Basic "foreach" operation.
+
+test for-1.1 {basic foreach tests} {
+ set a {}
+ foreach i {a b c d} {
+ set a [concat $a $i]
+ }
+ set a
+} {a b c d}
+test for-1.2 {basic foreach tests} {
+ set a {}
+ foreach i {a b {{c d} e} {123 {{x}}}} {
+ set a [concat $a $i]
+ }
+ set a
+} {a b {c d} e 123 {{x}}}
+test for-1.3 {basic foreach tests} {catch {foreach} msg} 1
+test for-1.4 {basic foreach tests} {
+ catch {foreach} msg
+ set msg
+} {wrong # args: should be "foreach varName list command"}
+test for-1.5 {basic foreach tests} {catch {foreach i} msg} 1
+test for-1.6 {basic foreach tests} {
+ catch {foreach i} msg
+ set msg
+} {wrong # args: should be "foreach varName list command"}
+test for-1.7 {basic foreach tests} {catch {foreach i j} msg} 1
+test for-1.8 {basic foreach tests} {
+ catch {foreach i j} msg
+ set msg
+} {wrong # args: should be "foreach varName list command"}
+test for-1.9 {basic foreach tests} {catch {foreach i j k l} msg} 1
+test for-1.10 {basic foreach tests} {
+ catch {foreach i j k l} msg
+ set msg
+} {wrong # args: should be "foreach varName list command"}
+test for-1.11 {basic foreach tests} {
+ set a {}
+ foreach i {} {
+ set a [concat $a $i]
+ }
+ set a
+} {}
+test for-1.11 {foreach errors} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {foreach a {1 2 3} {}} msg] $msg
+} {1 {couldn't set loop variable}}
+catch {unset a}
+
+# Check "continue".
+
+test for-2.1 {continue tests} {catch continue} 4
+test for-2.2 {continue tests} {
+ set a {}
+ foreach i {a b c d} {
+ if {[string compare $i "b"] == 0} continue
+ set a [concat $a $i]
+ }
+ set a
+} {a c d}
+test for-2.3 {continue tests} {
+ set a {}
+ foreach i {a b c d} {
+ if {[string compare $i "b"] != 0} continue
+ set a [concat $a $i]
+ }
+ set a
+} {b}
+test for-2.4 {continue tests} {catch {continue foo} msg} 1
+test for-2.5 {continue tests} {
+ catch {continue foo} msg
+ set msg
+} {wrong # args: should be "continue"}
+
+# Check "break".
+
+test for-3.1 {break tests} {catch break} 3
+test for-3.2 {break tests} {
+ set a {}
+ foreach i {a b c d} {
+ if {[string compare $i "c"] == 0} break
+ set a [concat $a $i]
+ }
+ set a
+} {a b}
+test for-3.3 {break tests} {catch {break foo} msg} 1
+test for-3.4 {break tests} {
+ catch {break foo} msg
+ set msg
+} {wrong # args: should be "break"}
+
+# Check "for" and its use of continue and break.
+
+test for-4.1 {for tests} {
+ set a {}
+ for {set i 1} {$i<6} {set i [expr $i+1]} {
+ set a [concat $a $i]
+ }
+ set a
+} {1 2 3 4 5}
+test for-4.2 {for tests} {
+ set a {}
+ for {set i 1} {$i<6} {set i [expr $i+1]} {
+ if $i==4 continue
+ set a [concat $a $i]
+ }
+ set a
+} {1 2 3 5}
+test for-4.3 {for tests} {
+ set a {}
+ for {set i 1} {$i<6} {set i [expr $i+1]} {
+ if $i==4 break
+ set a [concat $a $i]
+ }
+ set a
+} {1 2 3}
+test for-4.4 {for tests} {catch {for 1 2 3} msg} 1
+test for-4.5 {for tests} {
+ catch {for 1 2 3} msg
+ set msg
+} {wrong # args: should be "for start test next command"}
+test for-4.6 {for tests} {catch {for 1 2 3 4 5} msg} 1
+test for-4.7 {for tests} {
+ catch {for 1 2 3 4 5} msg
+ set msg
+} {wrong # args: should be "for start test next command"}
+test for-4.8 {for tests} {
+ set a {xyz}
+ for {set i 1} {$i<6} {set i [expr $i+1]} {}
+ set a
+} xyz
+test for-4.9 {for tests} {
+ set a {}
+ for {set i 1} {$i<6} {set i [expr $i+1]; if $i==4 break} {
+ set a [concat $a $i]
+ }
+ set a
+} {1 2 3}
diff --git a/vendor/x11iraf/obm/Tcl/tests/format.test b/vendor/x11iraf/obm/Tcl/tests/format.test
new file mode 100644
index 00000000..e31ba501
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/format.test
@@ -0,0 +1,379 @@
+# Commands covered: format
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/format.test,v 1.16 93/07/17 15:25:01 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# The following code is needed because some versions of SCO Unix have
+# a round-off error in sprintf which would cause some of the tests to
+# fail. Someday I hope this code shouldn't be necessary (code added
+# 9/9/91).
+
+set roundOffBug 0
+if {"[format %7.1e 68.514]" == "6.8e+01"} {
+ puts stdout "Note: this system has a sprintf round-off bug, some tests skipped\n"
+ set roundOffBug 1
+}
+
+test format-1.1 {integer formatting} {
+ format "%*d %d %d %d" 6 34 16923 -12 -1
+} { 34 16923 -12 -1}
+if $atBerkeley {
+ test format-1.2 {integer formatting} {
+ format "%4d %4d %4d %4d %d %#x %#X" 6 34 16923 -12 -1 0 0
+ } { 6 34 16923 -12 -1 0 0}
+}
+
+# %u output depends on word length, so don't run these tests except
+# at Berkeley, where word length is known.
+
+if $atBerkeley {
+ test format-1.3 {integer formatting} {
+ format "%4u %4u %4u %4u %d %#o" 6 34 16923 -12 -1 0
+ } { 6 34 16923 4294967284 -1 0}
+}
+test format-1.4 {integer formatting} {
+ format "%-4d %-4i %-4d %-4ld" 6 34 16923 -12 -1
+} {6 34 16923 -12 }
+test format-1.5 {integer formatting} {
+ format "%04d %04d %04d %04i" 6 34 16923 -12 -1
+} {0006 0034 16923 -012}
+test format-1.6 {integer formatting} {
+ format "%00*d" 6 34
+} {000034}
+
+# Printing negative numbers in hex or octal format depends on word
+# length; only run at Berkeley where word length is known.
+
+if $atBerkeley {
+ test format-1.7 {integer formatting} {
+ format "%4x %4x %4x %4x" 6 34 16923 -12 -1
+ } { 6 22 421b fffffff4}
+ test format-1.8 {integer formatting} {
+ format "%#x %#X %#X %#x" 6 34 16923 -12 -1
+ } {0x6 0X22 0X421B 0xfffffff4}
+ test format-1.9 {integer formatting} {
+ format "%#20x %#20x %#20x %#20x" 6 34 16923 -12 -1
+ } { 0x6 0x22 0x421b 0xfffffff4}
+ test format-1.10 {integer formatting} {
+ format "%-#20x %-#20x %-#20x %-#20x" 6 34 16923 -12 -1
+ } {0x6 0x22 0x421b 0xfffffff4 }
+ test format-1.11 {integer formatting} {
+ format "%-#20o %#-20o %#-20o %#-20o" 6 34 16923 -12 -1
+ } {06 042 041033 037777777764 }
+}
+
+test format-2.1 {string formatting} {
+ format "%s %s %c %s" abcd {This is a very long test string.} 120 x
+} {abcd This is a very long test string. x x}
+test format-2.2 {string formatting} {
+ format "%20s %20s %20c %20s" abcd {This is a very long test string.} 120 x
+} { abcd This is a very long test string. x x}
+test format-2.3 {string formatting} {
+ format "%.10s %.10s %c %.10s" abcd {This is a very long test string.} 120 x
+} {abcd This is a x x}
+test format-2.4 {string formatting} {
+ format "%s %s %% %c %s" abcd {This is a very long test string.} 120 x
+} {abcd This is a very long test string. % x x}
+
+test format-3.1 {e and f formats} {
+ format "%e %e %e %e" 34.2e12 68.514 -.125 -16000. .000053
+} {3.420000e+13 6.851400e+01 -1.250000e-01 -1.600000e+04}
+test format-3.2 {e and f formats} {
+ format "%20e %20e %20e %20e" 34.2e12 68.514 -.125 -16000. .000053
+} { 3.420000e+13 6.851400e+01 -1.250000e-01 -1.600000e+04}
+if {!$roundOffBug} {
+ test format-3.3 {e and f formats} {
+ format "%.1e %.1e %.1e %.1e" 34.2e12 68.514 -.126 -16000. .000053
+ } {3.4e+13 6.9e+01 -1.3e-01 -1.6e+04}
+ test format-3.4 {e and f formats} {
+ format "%020e %020e %020e %020e" 34.2e12 68.514 -.126 -16000. .000053
+ } {000000003.420000e+13 000000006.851400e+01 -00000001.260000e-01 -00000001.600000e+04}
+ test format-3.5 {e and f formats} {
+ format "%7.1e %7.1e %7.1e %7.1e" 34.2e12 68.514 -.126 -16000. .000053
+ } {3.4e+13 6.9e+01 -1.3e-01 -1.6e+04}
+ test format-3.6 {e and f formats} {
+ format "%f %f %f %f" 34.2e12 68.514 -.125 -16000. .000053
+ } {34200000000000.000000 68.514000 -0.125000 -16000.000000}
+}
+test format-3.7 {e and f formats} {
+ format "%.4f %.4f %.4f %.4f %.4f" 34.2e12 68.514 -.125 -16000. .000053
+} {34200000000000.0000 68.5140 -0.1250 -16000.0000 0.0001}
+test format-3.8 {e and f formats} {
+ format "%.4e %.5e %.6e" -9.99996 -9.99996 9.99996
+} {-1.0000e+01 -9.99996e+00 9.999960e+00}
+test format-3.9 {e and f formats} {
+ format "%.4f %.5f %.6f" -9.99996 -9.99996 9.99996
+} {-10.0000 -9.99996 9.999960}
+test format-3.10 {e and f formats} {
+ format "%20f %-20f %020f" -9.99996 -9.99996 9.99996
+} { -9.999960 -9.999960 0000000000009.999960}
+test format-3.11 {e and f formats} {
+ format "%-020f %020f" -9.99996 -9.99996 9.99996
+} {-9.999960 -000000000009.999960}
+test format-3.12 {e and f formats} {
+ format "%.0e %#.0e" -9.99996 -9.99996 9.99996
+} {-1e+01 -1.e+01}
+test format-3.13 {e and f formats} {
+ format "%.0f %#.0f" -9.99996 -9.99996 9.99996
+} {-10 -10.}
+test format-3.14 {e and f formats} {
+ format "%.4f %.5f %.6f" -9.99996 -9.99996 9.99996
+} {-10.0000 -9.99996 9.999960}
+test format-3.15 {e and f formats} {
+ format "%3.0f %3.0f %3.0f %3.0f" 1.0 1.1 1.01 1.001
+} { 1 1 1 1}
+test format-3.16 {e and f formats} {
+ format "%3.1f %3.1f %3.1f %3.1f" 0.0 0.1 0.01 0.001
+} {0.0 0.1 0.0 0.0}
+
+test format-4.1 {g-format} {
+ format "%.3g" 12341.0
+} {1.23e+04}
+test format-4.2 {g-format} {
+ format "%.3G" 1234.12345
+} {1.23E+03}
+test format-4.3 {g-format} {
+ format "%.3g" 123.412345
+} {123}
+test format-4.4 {g-format} {
+ format "%.3g" 12.3412345
+} {12.3}
+test format-4.5 {g-format} {
+ format "%.3g" 1.23412345
+} {1.23}
+test format-4.6 {g-format} {
+ format "%.3g" 1.23412345
+} {1.23}
+test format-4.7 {g-format} {
+ format "%.3g" .123412345
+} {0.123}
+test format-4.8 {g-format} {
+ format "%.3g" .012341
+} {0.0123}
+test format-4.9 {g-format} {
+ format "%.3g" .0012341
+} {0.00123}
+test format-4.10 {g-format} {
+ format "%.3g" .00012341
+} {0.000123}
+test format-4.11 {g-format} {
+ format "%.3g" .00001234
+} {1.23e-05}
+test format-4.12 {g-format} {
+ format "%.4g" 9999.6
+} {1e+04}
+test format-4.13 {g-format} {
+ format "%.4g" 999.96
+} {1000}
+test format-4.14 {g-format} {
+ format "%.3g" 1.0
+} {1}
+test format-4.15 {g-format} {
+ format "%.3g" .1
+} {0.1}
+test format-4.16 {g-format} {
+ format "%.3g" .01
+} {0.01}
+test format-4.17 {g-format} {
+ format "%.3g" .001
+} {0.001}
+test format-4.19 {g-format} {
+ format "%.3g" .00001
+} {1e-05}
+test format-4.20 {g-format} {
+ format "%#.3g" 1234.0
+} {1.23e+03}
+test format-4.21 {g-format} {
+ format "%#.3G" 9999.5
+} {1.00E+04}
+
+test format-5.1 {floating-point zeroes} {
+ format "%e %f %g" 0.0 0.0 0.0 0.0
+} {0.000000e+00 0.000000 0}
+test format-5.2 {floating-point zeroes} {
+ format "%.4e %.4f %.4g" 0.0 0.0 0.0 0.0
+} {0.0000e+00 0.0000 0}
+test format-5.3 {floating-point zeroes} {
+ format "%#.4e %#.4f %#.4g" 0.0 0.0 0.0 0.0
+} {0.0000e+00 0.0000 0.000}
+test format-5.4 {floating-point zeroes} {
+ format "%.0e %.0f %.0g" 0.0 0.0 0.0 0.0
+} {0e+00 0 0}
+test format-5.5 {floating-point zeroes} {
+ format "%#.0e %#.0f %#.0g" 0.0 0.0 0.0 0.0
+} {0.e+00 0. 0.}
+test format-5.6 {floating-point zeroes} {
+ format "%3.0f %3.0f %3.0f %3.0f" 0.0 0.0 0.0 0.0
+} { 0 0 0 0}
+test format-5.7 {floating-point zeroes} {
+ format "%3.0f %3.0f %3.0f %3.0f" 1.0 1.1 1.01 1.001
+} { 1 1 1 1}
+test format-5.8 {floating-point zeroes} {
+ format "%3.1f %3.1f %3.1f %3.1f" 0.0 0.1 0.01 0.001
+} {0.0 0.1 0.0 0.0}
+
+test format-6.1 {various syntax features} {
+ format "%*.*f" 12 3 12.345678901
+} { 12.346}
+test format-6.2 {various syntax features} {
+ format "%0*.*f" 12 3 12.345678901
+} {00000012.346}
+test format-6.3 {various syntax features} {
+ format "\*\t\\n"
+} {* \n}
+
+test format-7.1 {error conditions} {
+ catch format
+} 1
+test format-7.2 {error conditions} {
+ catch format msg
+ set msg
+} {wrong # args: should be "format formatString ?arg arg ...?"}
+test format-7.3 {error conditions} {
+ catch {format %*d}
+} 1
+test format-7.4 {error conditions} {
+ catch {format %*d} msg
+ set msg
+} {not enough arguments for all format specifiers}
+test format-7.5 {error conditions} {
+ catch {format %*.*f 12}
+} 1
+test format-7.6 {error conditions} {
+ catch {format %*.*f 12} msg
+ set msg
+} {not enough arguments for all format specifiers}
+test format-7.7 {error conditions} {
+ catch {format %*.*f 12 3}
+} 1
+test format-7.8 {error conditions} {
+ catch {format %*.*f 12 3} msg
+ set msg
+} {not enough arguments for all format specifiers}
+test format-7.9 {error conditions} {
+ list [catch {format %*d x 3} msg] $msg
+} {1 {expected integer but got "x"}}
+test format-7.10 {error conditions} {
+ list [catch {format %*.*f 2 xyz 3} msg] $msg
+} {1 {expected integer but got "xyz"}}
+test format-7.11 {error conditions} {
+ catch {format %d 2a}
+} 1
+test format-7.12 {error conditions} {
+ catch {format %d 2a} msg
+ set msg
+} {expected integer but got "2a"}
+test format-7.13 {error conditions} {
+ catch {format %c 2x}
+} 1
+test format-7.14 {error conditions} {
+ catch {format %c 2x} msg
+ set msg
+} {expected integer but got "2x"}
+test format-7.15 {error conditions} {
+ catch {format %f 2.1z}
+} 1
+test format-7.16 {error conditions} {
+ catch {format %f 2.1z} msg
+ set msg
+} {expected floating-point number but got "2.1z"}
+test format-7.17 {error conditions} {
+ catch {format ab%}
+} 1
+test format-7.18 {error conditions} {
+ catch {format ab% 12} msg
+ set msg
+} {format string ended in middle of field specifier}
+test format-7.19 {error conditions} {
+ catch {format %q x}
+} 1
+test format-7.20 {error conditions} {
+ catch {format %q x} msg
+ set msg
+} {bad field specifier "q"}
+test format-7.21 {error conditions} {
+ catch {format %d}
+} 1
+test format-7.22 {error conditions} {
+ catch {format %d} msg
+ set msg
+} {not enough arguments for all format specifiers}
+
+test format-8.1 {long result} {
+ set a {1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
+ format {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG %s %s %s} $a $a $a
+} {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
+
+if $atBerkeley {
+ test format-9.1 {"h" format specifier} {
+ format %hd 0xffff
+ } -1
+ test format-9.2 {"h" format specifier} {
+ format %hx 0x10fff
+ } fff
+ test format-9.3 {"h" format specifier} {
+ format %hd 0x10000
+ } 0
+}
+
+test format-10.1 {XPG3 %$n specifiers} {
+ format {%2$d %1$d} 4 5
+} {5 4}
+test format-10.2 {XPG3 %$n specifiers} {
+ format {%2$d %1$d %1$d %3$d} 4 5 6
+} {5 4 4 6}
+test format-10.3 {XPG3 %$n specifiers} {
+ list [catch {format {%2$d %3$d} 4 5} msg] $msg
+} {1 {"%n$" argument index out of range}}
+test format-10.4 {XPG3 %$n specifiers} {
+ list [catch {format {%2$d %0$d} 4 5 6} msg] $msg
+} {1 {"%n$" argument index out of range}}
+test format-10.5 {XPG3 %$n specifiers} {
+ list [catch {format {%d %1$d} 4 5 6} msg] $msg
+} {1 {cannot mix "%" and "%n$" conversion specifiers}}
+test format-10.6 {XPG3 %$n specifiers} {
+ list [catch {format {%2$d %d} 4 5 6} msg] $msg
+} {1 {cannot mix "%" and "%n$" conversion specifiers}}
+test format-10.7 {XPG3 %$n specifiers} {
+ list [catch {format {%2$d %3d} 4 5 6} msg] $msg
+} {1 {cannot mix "%" and "%n$" conversion specifiers}}
+test format-10.8 {XPG3 %$n specifiers} {
+ format {%2$*d %3$d} 1 10 4
+} { 4 4}
+test format-10.9 {XPG3 %$n specifiers} {
+ format {%2$.*s %4$d} 1 5 abcdefghijklmnop 44
+} {abcde 44}
+test format-10.10 {XPG3 %$n specifiers} {
+ list [catch {format {%2$*d} 4} msg] $msg
+} {1 {"%n$" argument index out of range}}
+test format-10.11 {XPG3 %$n specifiers} {
+ list [catch {format {%2$*d} 4 5} msg] $msg
+} {1 {"%n$" argument index out of range}}
+test format-10.12 {XPG3 %$n specifiers} {
+ list [catch {format {%2$*d} 4 5 6} msg] $msg
+} {0 { 6}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/glob.test b/vendor/x11iraf/obm/Tcl/tests/glob.test
new file mode 100644
index 00000000..ba134ed8
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/glob.test
@@ -0,0 +1,153 @@
+# Commands covered: glob
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/glob.test,v 1.23 93/08/28 15:57:40 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# First, create some subdirectories to use for testing.
+
+exec rm -rf globTest
+exec mkdir globTest globTest/a1 globTest/a2 globTest/a3
+exec mkdir globTest/a1/b1 globTest/a1/b2 globTest/a2/b3
+exec cat << abc > globTest/x1.c
+exec cat << abc > globTest/y1.c
+exec cat << abc > globTest/z1.c
+exec cat << abc > "globTest/weird name.c"
+exec cat << abc > globTest/.1
+exec cat << abc > globTest/a1/b1/x2.c
+exec cat << abc > globTest/a1/b2/y2.c
+
+test glob-1.1 {simple globbing} {
+ lsort [glob globTest/x1.c globTest/y1.c globTest/foo]
+} {globTest/x1.c globTest/y1.c}
+test glob-1.2 {simple globbing} {
+ glob {}
+} .
+
+test glob-2.1 {globbing with braces} {
+ glob -nocomplain "{a1,a2}"
+} {}
+test glob-2.2 {globbing with braces} {
+ lsort [glob globTest/{a,b,x,y}1.c]
+} {globTest/x1.c globTest/y1.c}
+test glob-2.3 {globbing with braces} {
+ lsort [glob {globTest/{x1,y2,weird name}.c}]
+} {{globTest/weird name.c} globTest/x1.c}
+test glob-2.4 {globbing with braces} {
+ lsort [glob globTest/{x1.c,a1/*}]
+} {globTest/a1/b1 globTest/a1/b2 globTest/x1.c}
+
+test glob-3.1 {asterisks, question marks, and brackets} {
+ lsort [glob g*/*.c]
+} {{globTest/weird name.c} globTest/x1.c globTest/y1.c globTest/z1.c}
+test glob-3.2 {asterisks, question marks, and brackets} {
+ lsort [glob globTest/?1.c]
+} {globTest/x1.c globTest/y1.c globTest/z1.c}
+test glob-3.3 {asterisks, question marks, and brackets} {
+ lsort [glob */*/*/*.c]
+} {globTest/a1/b1/x2.c globTest/a1/b2/y2.c}
+test glob-3.4 {asterisks, question marks, and brackets} {
+ lsort [glob globTest/*]
+} {globTest/a1 globTest/a2 globTest/a3 {globTest/weird name.c} globTest/x1.c globTest/y1.c globTest/z1.c}
+test glob-3.5 {asterisks, question marks, and brackets} {
+ lsort [glob globTest/.*]
+} {globTest/. globTest/.. globTest/.1}
+test glob-3.6 {asterisks, question marks, and brackets} {
+ lsort [glob globTest/*/*]
+} {globTest/a1/b1 globTest/a1/b2 globTest/a2/b3}
+test glob-3.7 {asterisks, question marks, and brackets} {
+ lsort [glob {globTest/[xyab]1.*}]
+} {globTest/x1.c globTest/y1.c}
+test glob-3.8 {asterisks, question marks, and brackets} {
+ lsort [glob globTest/*/]
+} {globTest/a1/ globTest/a2/ globTest/a3/}
+
+# The tests immediately below can only be run at Berkeley, where
+# the file-system structure is well-known.
+
+if $atBerkeley {
+ test glob-4.1 {tildes} {glob ~/.csh*} "/users/ouster/.cshrc"
+ test glob-4.2 {tildes} {glob ~ouster/.csh*} "/users/ouster/.cshrc"
+}
+
+test glob-5.1 {error conditions} {
+ list [catch {glob} msg] $msg
+} {1 {wrong # args: should be "glob ?switches? name ?name ...?"}}
+test glob-5.2 {error conditions} {
+ list [catch {glob globTest/\{} msg] $msg
+} {1 {unmatched open-brace in file name}}
+test glob-5.3 {error conditions} {
+ list [catch {glob globTest/*/gorp} msg] $msg
+} {1 {no files matched glob pattern "globTest/*/gorp"}}
+test glob-5.4 {error conditions} {
+ list [catch {glob goo/* x*z foo?q} msg] $msg
+} {1 {no files matched glob patterns "goo/* x*z foo?q"}}
+test glob-5.5 {error conditions} {
+ list [catch {lsort [glob globTest/*.c goo/*]} msg] $msg
+} {0 {{globTest/weird name.c} globTest/x1.c globTest/y1.c globTest/z1.c}}
+test glob-5.6 {error conditions} {
+ list [catch {glob ~no-one} msg] $msg
+} {1 {user "no-one" doesn't exist}}
+test glob-5.7 {error conditions} {
+ set home $env(HOME)
+ unset env(HOME)
+ set x [list [catch {glob ~/*} msg] $msg]
+ set env(HOME) $home
+ set x
+} {1 {couldn't find HOME environment variable to expand "~/*"}}
+test glob-5.8 {error conditions} {
+ list [catch {glob globTest/{a1,a2}/\{} msg] $msg
+} {1 {unmatched open-brace in file name}}
+test glob-5.9 {error conditions} {
+ list [catch {glob globTest/*/\{} msg] $msg
+} {1 {unmatched open-brace in file name}}
+
+exec chmod 000 globTest
+if {$user != "root"} {
+ test glob-6.1 {setting errorCode variable} {
+ string tolower [list [catch {glob globTest/*} msg] $msg $errorCode]
+ } {1 {couldn't read directory "globtest": permission denied} {posix eacces {permission denied}}}
+}
+exec chmod 755 globTest
+
+test glob-7.1 {-nocomplain switch} {
+ list [catch {glob -nocomplai} msg] $msg
+} {1 {bad switch "-nocomplai": must be -nocomplain or --}}
+test glob-7.2 {-nocomplain switch} {
+ list [catch {glob -nocomplain} msg] $msg
+} {1 {wrong # args: should be "glob ?switches? name ?name ...?"}}
+test glob-7.3 {-nocomplain switch} {
+ list [catch {glob -nocomplain goo/*} msg] $msg
+} {0 {}}
+test glob-7.4 {-- switch} {
+ list [catch {glob -- -nocomplain} msg] $msg
+} {1 {no files matched glob patterns "-nocomplain"}}
+test glob-7.5 {bogus switch} {
+ list [catch {glob -gorp} msg] $msg
+} {1 {bad switch "-gorp": must be -nocomplain or --}}
+
+exec rm -rf globTest
diff --git a/vendor/x11iraf/obm/Tcl/tests/history.test b/vendor/x11iraf/obm/Tcl/tests/history.test
new file mode 100644
index 00000000..56e337be
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/history.test
@@ -0,0 +1,400 @@
+# Commands covered: history
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/history.test,v 1.8 93/02/06 15:53:54 ouster Exp $ (Berkeley)
+
+if {[info commands history] == ""} {
+ puts stdout "This version of Tcl was built without the history command;\n"
+ puts stdout "history tests will be skipped.\n"
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+set num [history nextid]
+history keep 3
+history add {set a 12345}
+history add {set b [format {A test %s} string]}
+history add {Another test}
+
+# "history event"
+
+test history-1.1 {event option} {history event -1} \
+ {set b [format {A test %s} string]}
+test history-1.2 {event option} {history event $num} \
+ {set a 12345}
+test history-1.3 {event option} {history event [expr $num+2]} \
+ {Another test}
+test history-1.4 {event option} {history event set} \
+ {set b [format {A test %s} string]}
+test history-1.5 {event option} {history e "* a*"} \
+ {set a 12345}
+test history-1.6 {event option} {catch {history event *gorp} msg} 1
+test history-1.7 {event option} {
+ catch {history event *gorp} msg
+ set msg
+} {no event matches "*gorp"}
+test history-1.8 {event option} {history event} \
+ {set b [format {A test %s} string]}
+test history-1.9 {event option} {catch {history event 123 456} msg} 1
+test history-1.10 {event option} {
+ catch {history event 123 456} msg
+ set msg
+} {wrong # args: should be "history event ?event?"}
+
+# "history redo"
+
+set a 0
+history redo -2
+test history-2.1 {redo option} {set a} 12345
+set b 0
+history redo
+test history-2.2 {redo option} {set b} {A test string}
+test history-2.3 {redo option} {catch {history redo -3 -4}} 1
+test history-2.4 {redo option} {
+ catch {history redo -3 -4} msg
+ set msg
+} {wrong # args: should be "history redo ?event?"}
+
+# "history add"
+
+history add "set a 444" exec
+test history-3.1 {add option} {set a} 444
+test history-3.2 {add option} {catch {history add "set a 444" execGorp}} 1
+test history-3.3 {add option} {
+ catch {history add "set a 444" execGorp} msg
+ set msg
+} {bad argument "execGorp": should be "exec"}
+test history-3.4 {add option} {catch {history add "set a 444" a} msg} 1
+test history-3.5 {add option} {
+ catch {history add "set a 444" a} msg
+ set msg
+} {bad argument "a": should be "exec"}
+history add "set a 555" e
+test history-3.6 {add option} {set a} 555
+history add "set a 666"
+test history-3.7 {add option} {set a} 555
+test history-3.8 {add option} {catch {history add "set a 666" e f} msg} 1
+test history-3.9 {add option} {
+ catch {history add "set a 666" e f} msg
+ set msg
+} {wrong # args: should be "history add event ?exec?"}
+
+# "history change"
+
+history change "A test value"
+test history-4.1 {change option} {history event [expr {[history n]-1}]} \
+ "A test value"
+history c "Another test" -1
+test history-4.2 {change option} {history e} "Another test"
+test history-4.3 {change option} {history event [expr {[history n]-1}]} \
+ "A test value"
+test history-4.4 {change option} {catch {history change Foo 4 10}} 1
+test history-4.5 {change option} {
+ catch {history change Foo 4 10} msg
+ set msg
+} {wrong # args: should be "history change newValue ?event?"}
+test history-4.6 {change option} {
+ catch {history change Foo [expr {[history n]-4}]}
+} 1
+test history-4.7 {change option} {
+ catch {history change Foo [expr {[history n]-4}]}
+ set msg
+} {wrong # args: should be "history change newValue ?event?"}
+
+# "history info"
+
+set num [history n]
+history add set\ a\ {b\nc\ d\ e}
+history add {set b 1234}
+history add set\ c\ {a\nb\nc}
+test history-5.1 {info option} {history info} [format {%6d set a {b
+ c d e}
+%6d set b 1234
+%6d set c {a
+ b
+ c}} $num [expr $num+1] [expr $num+2]]
+test history-5.2 {info option} {history i 2} [format {%6d set b 1234
+%6d set c {a
+ b
+ c}} [expr $num+1] [expr $num+2]]
+test history-5.3 {info option} {catch {history i 2 3}} 1
+test history-5.4 {info option} {
+ catch {history i 2 3} msg
+ set msg
+} {wrong # args: should be "history info ?count?"}
+test history-5.5 {info option} {history} [format {%6d set a {b
+ c d e}
+%6d set b 1234
+%6d set c {a
+ b
+ c}} $num [expr $num+1] [expr $num+2]]
+
+# "history keep"
+
+history add "foo1"
+history add "foo2"
+history add "foo3"
+history keep 2
+test history-6.1 {keep option} {history event [expr [history n]-1]} foo3
+test history-6.2 {keep option} {history event -1} foo2
+test history-6.3 {keep option} {catch {history event -3}} 1
+test history-6.4 {keep option} {
+ catch {history event -3} msg
+ set msg
+} {event "-3" is too far in the past}
+history k 5
+test history-6.5 {keep option} {history event -1} foo2
+test history-6.6 {keep option} {history event -2} {}
+test history-6.7 {keep option} {history event -3} {}
+test history-6.8 {keep option} {history event -4} {}
+test history-6.9 {keep option} {catch {history event -5}} 1
+test history-6.10 {keep option} {catch {history keep 4 6}} 1
+test history-6.11 {keep option} {
+ catch {history keep 4 6} msg
+ set msg
+} {wrong # args: should be "history keep number"}
+test history-6.12 {keep option} {catch {history keep}} 1
+test history-6.13 {keep option} {
+ catch {history keep} msg
+ set msg
+} {wrong # args: should be "history keep number"}
+test history-6.14 {keep option} {catch {history keep -3}} 1
+test history-6.15 {keep option} {
+ catch {history keep -3} msg
+ set msg
+} {illegal keep count "-3"}
+
+# "history nextid"
+
+set num [history n]
+history add "Testing"
+history add "Testing2"
+test history-7.1 {nextid option} {history event} "Testing"
+test history-7.2 {nextid option} {history next} [expr $num+2]
+test history-7.3 {nextid option} {catch {history nextid garbage}} 1
+test history-7.4 {nextid option} {
+ catch {history nextid garbage} msg
+ set msg
+} {wrong # args: should be "history nextid"}
+
+# "history substitute"
+
+test history-8.1 {substitute option} {
+ history add "set a {test foo test b c test}"
+ history add "Test command 2"
+ set a 0
+ history substitute foo bar -1
+ set a
+} {test bar test b c test}
+test history-8.2 {substitute option} {
+ history add "set a {test foo test b c test}"
+ history add "Test command 2"
+ set a 0
+ history substitute test gorp
+ set a
+} {gorp foo gorp b c gorp}
+test history-8.3 {substitute option} {
+ history add "set a {test foo test b c test}"
+ history add "Test command 2"
+ set a 0
+ history sub " te" to
+ set a
+} {test footost b ctost}
+test history-8.4 {substitute option} {catch {history sub xxx yyy}} 1
+test history-8.5 {substitute option} {
+ catch {history sub xxx yyy} msg
+ set msg
+} {"xxx" doesn't appear in event}
+test history-8.6 {substitute option} {catch {history s a b -10}} 1
+test history-8.7 {substitute option} {
+ catch {history s a b -10} msg
+ set msg
+} {event "-10" is too far in the past}
+test history-8.8 {substitute option} {catch {history s a b -1 20}} 1
+test history-8.9 {substitute option} {
+ catch {history s a b -1 20} msg
+ set msg
+} {wrong # args: should be "history substitute old new ?event?"}
+
+# "history words"
+
+test history-9.1 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history words 0-$
+} {word0 word1 word2 a b c word6}
+test history-9.2 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history w 2 -1
+} word2
+test history-9.3 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history wo $
+} word6
+test history-9.4 {words option} {catch {history w 1--1} msg} 1
+test history-9.5 {words option} {
+ catch {history w 1--1} msg
+ set msg
+} {bad word selector "1--1": should be num-num or pattern}
+test history-9.6 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history w w
+} {}
+test history-9.7 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history w *2
+} word2
+test history-9.8 {words option} {
+ history add {word0 word1 word2 a b c word6}
+ history add foo
+ history w *or*
+} {word0 word1 word2 word6}
+test history-9.9 {words option} {catch {history words 10}} 1
+test history-9.10 {words option} {
+ catch {history words 10} msg
+ set msg
+} {word selector "10" specified non-existent words}
+test history-9.11 {words option} {catch {history words 1 -1 20}} 1
+test history-9.12 {words option} {
+ catch {history words 1 -1 20} msg
+ set msg
+} {wrong # args: should be "history words num-num/pat ?event?"}
+
+# history revision
+
+test history-10.1 {history revision} {
+ set a 0
+ history a {set a 12345}
+ history a {set a [history e]} exec
+ set a
+} {set a 12345}
+test history-10.2 {history revision} {
+ set a 0
+ history a {set a 12345}
+ history a {set a [history e]} exec
+ history a foo
+ history ev -1
+} {set a {set a 12345}}
+test history-10.3 {history revision} {
+ set a 0
+ history a {set a 12345}
+ history a {set a [history e]} exec
+ history a foo
+ history a {history r -2} exec
+ history a {set a 12345}
+ history ev -1
+} {set a {set a 12345}}
+test history-10.4 {history revision} {
+ history a {set a 12345}
+ history a {history s 123 999} exec
+ history a foo
+ history ev -1
+} {set a 99945}
+test history-10.5 {history revision} {
+ history add {word0 word1 word2 a b c word6}
+ history add {set [history w 3] [list [history w 0] [history w {[ab]}]]} exec
+ set a
+} {word0 {a b}}
+test history-10.6 {history revision} {
+ history add {word0 word1 word2 a b c word6}
+ history add {set [history w 3] [list [history w 0] [history w {[ab]}]]} exec
+ history add foo
+ history ev
+} {set a [list word0 {a b}]}
+test history-10.7 {history revision} {
+ history add {word0 word1 word2 a b c word6}
+ history add {set [history w 3] [list [history w 0] [history w {[ab]}]]} exec
+ history add {format b}
+ history add {word0 word1 word2 a b c word6}
+ set a 0
+ history add {set [history subs b a -2] [list abc [history r -2] [history w 1-3]]} exec
+ history add foo
+ history ev
+} {set [format a] [list abc [format b] {word1 word2 a}]}
+test history-10.8 {history revision} {
+ history add {set a 12345}
+ concat a b c
+ history add {history redo; set b 44} exec
+ history add foo
+ history ev
+} {set a 12345; set b 44}
+test history-10.9 {history revision} {
+ history add {set a 12345}
+ history add {history redo; history change "A simple test"; history subs 45 xx} exec
+ set a
+} 123xx
+test history-10.10 {history revision} {
+ history add {set a 12345}
+ history add {history redo; history change "A simple test"; history subs 45 xx} exec
+ history add foo
+ history e
+} {A simple test}
+test history-10.11 {history revision} {
+ history add {word0 word1 $ a b c word6}
+ history add {set a [history w 4-[history word 2]]} exec
+ set a
+} {b c word6}
+test history-10.12 {history revision} {
+ history add {word0 word1 $ a b c word6}
+ history add {set a [history w 4-[history word 2]]} exec
+ history add foo
+ history e
+} {set a {b c word6}}
+test history-10.13 {history revision} {
+ history add {history word 0} exec
+ history add foo
+ history e
+} {history word 0}
+test history-10.14 {history revision} {
+ history add {set a [history word 0; format c]} exec
+ history add foo
+ history e
+} {set a [history word 0; format c]}
+test history-10.15 {history revision even when nested} {
+ proc x {a b} {history word $a $b}
+ history add {word1 word2 word3 word4}
+ history add {set a [x 1-3 -1]} exec
+ history add foo
+ history e
+} {set a {word2 word3 word4}}
+test history-10.16 {disable history revision in nested history evals} {
+ history add {word1 word2 word3 word4}
+ history add {set a [history words 0]; history add foo; set a [history words 0]} exec
+ history e
+} {set a word1; history add foo; set a [history words 0]}
+
+# miscellaneous
+
+test history-11.1 {miscellaneous} {catch {history gorp} msg} 1
+test history-11.2 {miscellaneous} {
+ catch {history gorp} msg
+ set msg
+} {bad option "gorp": must be add, change, event, info, keep, nextid, redo, substitute, or words}
diff --git a/vendor/x11iraf/obm/Tcl/tests/if.test b/vendor/x11iraf/obm/Tcl/tests/if.test
new file mode 100644
index 00000000..1ab205ed
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/if.test
@@ -0,0 +1,162 @@
+# Commands covered: if
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/if.test,v 1.5 93/02/06 15:54:17 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test if-1.1 {taking proper branch} {
+ set a {}
+ if 0 {set a 1} else {set a 2}
+ set a
+} 2
+test if-1.2 {taking proper branch} {
+ set a {}
+ if 1 {set a 1} else {set a 2}
+ set a
+} 1
+test if-1.3 {taking proper branch} {
+ set a {}
+ if 1<2 {set a 1}
+ set a
+} 1
+test if-1.4 {taking proper branch} {
+ set a {}
+ if 1>2 {set a 1}
+ set a
+} {}
+test if-1.5 {taking proper branch} {
+ set a {}
+ if 0 {set a 1} else {}
+ set a
+} {}
+test if-1.5 {taking proper branch} {
+ set a {}
+ if 0 {set a 1} elseif 1 {set a 2} elseif 1 {set a 3} else {set a 4}
+ set a
+} {2}
+test if-1.6 {taking proper branch} {
+ set a {}
+ if 0 {set a 1} elseif 0 {set a 2} elseif 1 {set a 3} else {set a 4}
+ set a
+} {3}
+test if-1.7 {taking proper branch} {
+ set a {}
+ if 0 {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} else {set a 4}
+ set a
+} {4}
+
+
+test if-2.1 {optional then-else args} {
+ set a 44
+ if 0 then {set a 1} elseif 0 then {set a 3} else {set a 2}
+ set a
+} 2
+test if-2.2 {optional then-else args} {
+ set a 44
+ if 1 then {set a 1} else {set a 2}
+ set a
+} 1
+test if-2.3 {optional then-else args} {
+ set a 44
+ if 0 {set a 1} else {set a 2}
+ set a
+} 2
+test if-2.4 {optional then-else args} {
+ set a 44
+ if 1 {set a 1} else {set a 2}
+ set a
+} 1
+test if-2.5 {optional then-else args} {
+ set a 44
+ if 0 then {set a 1} {set a 2}
+ set a
+} 2
+test if-2.6 {optional then-else args} {
+ set a 44
+ if 1 then {set a 1} {set a 2}
+ set a
+} 1
+test if-2.7 {optional then-else args} {
+ set a 44
+ if 0 then {set a 1} else {set a 2}
+ set a
+} 2
+test if-2.8 {optional then-else args} {
+ set a 44
+ if 0 then {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} {set a 4}
+ set a
+} 4
+
+test if-3.1 {return value} {
+ if 1 then {set a 22; concat abc}
+} abc
+test if-3.2 {return value} {
+ if 0 then {set a 22; concat abc} elseif 1 {concat def} {concat ghi}
+} def
+test if-3.3 {return value} {
+ if 0 then {set a 22; concat abc} else {concat def}
+} def
+test if-3.4 {return value} {
+ if 0 then {set a 22; concat abc}
+} {}
+test if-3.5 {return value} {
+ if 0 then {set a 22; concat abc} elseif 0 {concat def}
+} {}
+
+test if-4.1 {error conditions} {
+ list [catch {if} msg] $msg
+} {1 {wrong # args: no expression after "if" argument}}
+test if-4.2 {error conditions} {
+ list [catch {if {[error "error in condition"]}} msg] $msg
+} {1 {error in condition}}
+test if-4.3 {error conditions} {
+ list [catch {if 2} msg] $msg
+} {1 {wrong # args: no script following "2" argument}}
+test if-4.4 {error conditions} {
+ list [catch {if 2 then} msg] $msg
+} {1 {wrong # args: no script following "then" argument}}
+test if-4.5 {error conditions} {
+ list [catch {if 2 the} msg] $msg
+} {1 {invalid command name: "the"}}
+test if-4.6 {error conditions} {
+ list [catch {if 2 then {[error "error in then clause"]}} msg] $msg
+} {1 {error in then clause}}
+test if-4.7 {error conditions} {
+ list [catch {if 0 then foo elseif} msg] $msg
+} {1 {wrong # args: no expression after "elseif" argument}}
+test if-4.8 {error conditions} {
+ list [catch {if 0 then foo elsei} msg] $msg
+} {1 {invalid command name: "elsei"}}
+test if-4.9 {error conditions} {
+ list [catch {if 0 then foo elseif 0 bar else} msg] $msg
+} {1 {wrong # args: no script following "else" argument}}
+test if-4.10 {error conditions} {
+ list [catch {if 0 then foo elseif 0 bar els} msg] $msg
+} {1 {invalid command name: "els"}}
+test if-4.11 {error conditions} {
+ list [catch {if 0 then foo elseif 0 bar else {[error "error in else clause"]}} msg] $msg
+} {1 {error in else clause}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/incr.test b/vendor/x11iraf/obm/Tcl/tests/incr.test
new file mode 100644
index 00000000..d04fe7f6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/incr.test
@@ -0,0 +1,86 @@
+# Commands covered: lreplace
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/incr.test,v 1.5 93/07/12 11:34:43 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {unset x}
+
+test incr-1.1 {basic incr operation} {
+ set x 23
+ list [incr x] $x
+} {24 24}
+test incr-1.2 {basic incr operation} {
+ set x 106
+ list [incr x -5] $x
+} {101 101}
+test incr-1.3 {basic incr operation} {
+ set x " -106"
+ list [incr x 1] $x
+} {-105 -105}
+test incr-1.3 {basic incr operation} {
+ set x " +106"
+ list [incr x 1] $x
+} {107 107}
+
+test incr-2.1 {incr errors} {
+ list [catch incr msg] $msg
+} {1 {wrong # args: should be "incr varName ?increment?"}}
+test incr-2.2 {incr errors} {
+ list [catch {incr a b c} msg] $msg
+} {1 {wrong # args: should be "incr varName ?increment?"}}
+test incr-2.3 {incr errors} {
+ catch {unset x}
+ list [catch {incr x} msg] $msg $errorInfo
+} {1 {can't read "x": no such variable} {can't read "x": no such variable
+ while executing
+"incr x"}}
+test incr-2.4 {incr errors} {
+ set x abc
+ list [catch {incr x} msg] $msg $errorInfo
+} {1 {expected integer but got "abc"} {expected integer but got "abc"
+ (reading value of variable to increment)
+ invoked from within
+"incr x"}}
+test incr-2.5 {incr errors} {
+ set x 123
+ list [catch {incr x 1a} msg] $msg $errorInfo
+} {1 {expected integer but got "1a"} {expected integer but got "1a"
+ (reading increment)
+ invoked from within
+"incr x 1a"}}
+test incr-2.6 {incr errors} {
+ proc readonly args {error "variable is read-only"}
+ set x 123
+ trace var x w readonly
+ list [catch {incr x 1} msg] $msg $errorInfo
+} {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only
+ while executing
+"incr x 1"}}
+
+catch {unset x}
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/info.test b/vendor/x11iraf/obm/Tcl/tests/info.test
new file mode 100644
index 00000000..ecc7d940
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/info.test
@@ -0,0 +1,524 @@
+# Commands covered: info
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/info.test,v 1.17 93/10/13 13:02:02 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test info-1.1 {info args option} {
+ proc t1 {a bbb c} {return foo}
+ info args t1
+} {a bbb c}
+test info-1.2 {info args option} {
+ proc t1 {{a default1} {bbb default2} {c default3} args} {return foo}
+ info a t1
+} {a bbb c args}
+test info-1.3 {info args option} {
+ proc t1 "" {return foo}
+ info args t1
+} {}
+test info-1.4 {info args option} {
+ catch {rename t1 {}}
+ list [catch {info args t1} msg] $msg
+} {1 {"t1" isn't a procedure}}
+test info-1.5 {info args option} {
+ list [catch {info args set} msg] $msg
+} {1 {"set" isn't a procedure}}
+
+test info-2.1 {info body option} {
+ proc t1 {} {body of t1}
+ info body t1
+} {body of t1}
+test info-2.2 {info body option} {
+ list [catch {info body set} msg] $msg
+} {1 {"set" isn't a procedure}}
+test info-2.3 {info body option} {
+ list [catch {info args set 1} msg] $msg
+} {1 {wrong # args: should be "info args procname"}}
+
+test info-3.1 {info cmdcount option} {
+ set x [info cmdcount]
+ set y 12345
+ set z [info cm]
+ expr $z-$x
+} 3
+test info-3.2 {info body option} {
+ list [catch {info cmdcount 1} msg] $msg
+} {1 {wrong # args: should be "info cmdcount"}}
+
+test info-4.1 {info commands option} {
+ proc t1 {} {}
+ proc t2 {} {}
+ set x " [info commands] "
+ list [string match {* t1 *} $x] [string match {* t2 *} $x] \
+ [string match {* set *} $x] [string match {* list *} $x]
+} {1 1 1 1}
+test info-4.2 {info commands option} {
+ proc t1 {} {}
+ rename t1 {}
+ set x [info comm]
+ string match {* t1 *} $x
+} 0
+test info-4.3 {info commands option} {
+ proc _t1_ {} {}
+ proc _t2_ {} {}
+ info commands _t1_
+} _t1_
+test info-4.4 {info commands option} {
+ proc _t1_ {} {}
+ proc _t2_ {} {}
+ lsort [info commands _t*]
+} {_t1_ _t2_}
+catch {rename _t1_ {}}
+catch {rename _t2_ {}}
+test info-4.5 {info commands option} {
+ list [catch {info commands a b} msg] $msg
+} {1 {wrong # args: should be "info commands [pattern]"}}
+
+test info-5.1 {info complete option} {
+ info complete ""
+} 1
+test info-5.2 {info complete option} {
+ info complete " \n"
+} 1
+test info-5.3 {info complete option} {
+ info complete "abc def"
+} 1
+test info-5.4 {info complete option} {
+ info complete "a b c d e f \t\n"
+} 1
+test info-5.5 {info complete option} {
+ info complete {a b c"d}
+} 1
+test info-5.6 {info complete option} {
+ info complete {a b "c d" e}
+} 1
+test info-5.7 {info complete option} {
+ info complete {a b "c d"}
+} 1
+test info-5.8 {info complete option} {
+ info complete {a b "c d"}
+} 1
+test info-5.9 {info complete option} {
+ info complete {a b "c d}
+} 0
+test info-5.10 {info complete option} {
+ info complete {a b "}
+} 0
+test info-5.11 {info complete option} {
+ info complete {a b "cd"xyz}
+} 1
+test info-5.12 {info complete option} {
+ info complete {a b "c $d() d"}
+} 1
+test info-5.13 {info complete option} {
+ info complete {a b "c $dd("}
+} 0
+test info-5.14 {info complete option} {
+ info complete {a b "c \"}
+} 0
+test info-5.15 {info complete option} {
+ info complete {a b "c [d e f]"}
+} 1
+test info-5.16 {info complete option} {
+ info complete {a b "c [d e f] g"}
+} 1
+test info-5.17 {info complete option} {
+ info complete {a b "c [d e f"}
+} 0
+test info-5.18 {info complete option} {
+ info complete {a {b c d} e}
+} 1
+test info-5.19 {info complete option} {
+ info complete {a {b c d}}
+} 1
+test info-5.20 {info complete option} {
+ info complete "a b\{c d"
+} 1
+test info-5.21 {info complete option} {
+ info complete "a b \{c"
+} 0
+test info-5.22 {info complete option} {
+ info complete "a b \{c{ }"
+} 0
+test info-5.23 {info complete option} {
+ info complete "a b {c d e}xxx"
+} 1
+test info-5.24 {info complete option} {
+ info complete "a b {c \\\{d e}xxx"
+} 1
+test info-5.25 {info complete option} {
+ info complete {a b [ab cd ef]}
+} 1
+test info-5.26 {info complete option} {
+ info complete {a b x[ab][cd][ef] gh}
+} 1
+test info-5.27 {info complete option} {
+ info complete {a b x[ab][cd[ef] gh}
+} 0
+test info-5.28 {info complete option} {
+ info complete {a b x[ gh}
+} 0
+test info-5.29 {info complete option} {
+ info complete {[]]]}
+} 1
+test info-5.30 {info complete option} {
+ info complete {abc x$yyy}
+} 1
+test info-5.31 {info complete option} {
+ info complete "abc x\${abc\[\\d} xyz"
+} 1
+test info-5.32 {info complete option} {
+ info complete "abc x\$\{ xyz"
+} 0
+test info-5.33 {info complete option} {
+ info complete {word $a(xyz)}
+} 1
+test info-5.34 {info complete option} {
+ info complete {word $a(}
+} 0
+test info-5.35 {info complete option} {
+ info complete "set a \\\n"
+} 0
+test info-5.36 {info complete option} {
+ info complete "set a \\n "
+} 1
+test info-5.37 {info complete option} {
+ info complete "set a \\"
+} 1
+test info-5.38 {info complete option} {
+ info complete "foo \\\n\{"
+} 0
+test info-5.39 {info complete option} {
+ info complete " # \{"
+} 1
+test info-5.40 {info complete option} {
+ info complete "foo bar;# \{"
+} 1
+test info-5.41 {info complete option} {
+ info complete "a\nb\n# \{\n# \{\nc\n"
+} 1
+
+test info-6.1 {info default option} {
+ proc t1 {a b {c d} {e "long default value"}} {}
+ info default t1 a value
+} 0
+test info-6.2 {info default option} {
+ proc t1 {a b {c d} {e "long default value"}} {}
+ set value 12345
+ info d t1 a value
+ set value
+} {}
+test info-6.3 {info default option} {
+ proc t1 {a b {c d} {e "long default value"}} {}
+ info default t1 c value
+} 1
+test info-6.4 {info default option} {
+ proc t1 {a b {c d} {e "long default value"}} {}
+ set value 12345
+ info default t1 c value
+ set value
+} d
+test info-6.5 {info default option} {
+ proc t1 {a b {c d} {e "long default value"}} {}
+ set value 12345
+ set x [info default t1 e value]
+ list $x $value
+} {1 {long default value}}
+test info-6.6 {info default option} {
+ list [catch {info default a b} msg] $msg
+} {1 {wrong # args: should be "info default procname arg varname"}}
+test info-6.7 {info default option} {
+ list [catch {info default _nonexistent_ a b} msg] $msg
+} {1 {"_nonexistent_" isn't a procedure}}
+test info-6.8 {info default option} {
+ proc t1 {a b} {}
+ list [catch {info default t1 x value} msg] $msg
+} {1 {procedure "t1" doesn't have an argument "x"}}
+test info-6.9 {info default option} {
+ catch {unset a}
+ set a(0) 88
+ proc t1 {a b} {}
+ list [catch {info default t1 a a} msg] $msg
+} {1 {couldn't store default value in variable "a"}}
+test info-6.10 {info default option} {
+ catch {unset a}
+ set a(0) 88
+ proc t1 {{a 18} b} {}
+ list [catch {info default t1 a a} msg] $msg
+} {1 {couldn't store default value in variable "a"}}
+catch {unset a}
+
+test info-7.1 {info exists option} {
+ set value foo
+ info exists value
+} 1
+catch {unset _nonexistent_}
+test info-7.2 {info exists option} {
+ info exists _nonexistent_
+} 0
+test info-7.3 {info exists option} {
+ proc t1 {x} {return [info exists x]}
+ t1 2
+} 1
+test info-7.4 {info exists option} {
+ proc t1 {x} {
+ global _nonexistent_
+ return [info exists _nonexistent_]
+ }
+ t1 2
+} 0
+test info-7.5 {info exists option} {
+ proc t1 {x} {
+ set y 47
+ return [info exists y]
+ }
+ t1 2
+} 1
+test info-7.6 {info exists option} {
+ proc t1 {x} {return [info exists value]}
+ t1 2
+} 0
+test info-7.7 {info exists option} {
+ catch {unset x}
+ set x(2) 44
+ list [info exists x] [info exists x(1)] [info exists x(2)]
+} {1 0 1}
+catch {unset x}
+test info-7.8 {info exists option} {
+ list [catch {info exists} msg] $msg
+} {1 {wrong # args: should be "info exists varName"}}
+test info-7.9 {info exists option} {
+ list [catch {info exists 1 2} msg] $msg
+} {1 {wrong # args: should be "info exists varName"}}
+
+test info-8.1 {info globals option} {
+ set x 1
+ set y 2
+ set value 23
+ set a " [info globals] "
+ list [string match {* x *} $a] [string match {* y *} $a] \
+ [string match {* value *} $a] [string match {* _foobar_ *} $a]
+} {1 1 1 0}
+test info-8.2 {info globals option} {
+ set _xxx1 1
+ set _xxx2 2
+ lsort [info g _xxx*]
+} {_xxx1 _xxx2}
+test info-8.3 {info globals option} {
+ list [catch {info globals 1 2} msg] $msg
+} {1 {wrong # args: should be "info globals [pattern]"}}
+
+test info-9.1 {info level option} {
+ info level
+} 0
+test info-9.2 {info level option} {
+ proc t1 {a b} {
+ set x [info le]
+ set y [info level 1]
+ list $x $y
+ }
+ t1 146 testString
+} {1 {t1 146 testString}}
+test info-9.3 {info level option} {
+ proc t1 {a b} {
+ t2 [expr $a*2] $b
+ }
+ proc t2 {x y} {
+ list [info level] [info level 1] [info level 2] [info level -1] \
+ [info level 0]
+ }
+ t1 146 {a {b c} {{{c}}}}
+} {2 {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}} {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}}}
+test info-9.4 {info level option} {
+ proc t1 {} {
+ set x [info level]
+ set y [info level 1]
+ list $x $y
+ }
+ t1
+} {1 t1}
+test info-9.5 {info level option} {
+ list [catch {info level 1 2} msg] $msg
+} {1 {wrong # args: should be "info level [number]"}}
+test info-9.6 {info level option} {
+ list [catch {info level 123a} msg] $msg
+} {1 {expected integer but got "123a"}}
+test info-9.7 {info level option} {
+ list [catch {info level 0} msg] $msg
+} {1 {bad level "0"}}
+test info-9.8 {info level option} {
+ proc t1 {} {info level -1}
+ list [catch {t1} msg] $msg
+} {1 {bad level "-1"}}
+test info-9.9 {info level option} {
+ proc t1 {x} {info level $x}
+ list [catch {t1 -3} msg] $msg
+} {1 {bad level "-3"}}
+
+test info-10.1 {info library option} {
+ list [catch {info library x} msg] $msg
+} {1 {wrong # args: should be "info library"}}
+# The following check can only be done at Berkeley, where the exact
+# location of the library is known.
+
+if $atBerkeley {
+ test info-10.2 {info library option} {
+ info li
+ } /users/ouster/tcl/library
+ test info-10.3 {info library option} {
+ set env(TCL_LIBRARY) test_value
+ set result [info library]
+ unset env(TCL_LIBRARY)
+ list $result [info library]
+ } {test_value /users/ouster/tcl/library}
+}
+
+test info-11.1 {info locals option} {
+ set a 22
+ proc t1 {x y} {
+ set b 13
+ set c testing
+ global a
+ return [info locals]
+ }
+ lsort [t1 23 24]
+} {b c x y}
+test info-11.2 {info locals option} {
+ proc t1 {x y} {
+ set xx1 2
+ set xx2 3
+ set y 4
+ return [info lo x*]
+ }
+ lsort [t1 2 3]
+} {x xx1 xx2}
+test info-11.3 {info locals option} {
+ list [catch {info locals 1 2} msg] $msg
+} {1 {wrong # args: should be "info locals [pattern]"}}
+test info-11.4 {info locals option} {
+ info locals
+} {}
+test info-11.5 {info locals option} {
+ proc t1 {} {return [info locals]}
+ t1
+} {}
+
+test info-12.1 {info patchlevel option} {
+ set a [info patchlevel]
+ incr a 2
+ expr $a-[info patchlevel]
+} 2
+test info-12.2 {info patchlevel option} {
+ list [catch {info patchlevel a} msg] $msg
+} {1 {wrong # args: should be "info patchlevel"}}
+
+test info-13.1 {info procs option} {
+ proc t1 {} {}
+ proc t2 {} {}
+ set x " [info procs] "
+ list [string match {* t1 *} $x] [string match {* t2 *} $x] \
+ [string match {* _undefined_ *} $x]
+} {1 1 0}
+test info-13.2 {info procs option} {
+ proc _tt1 {} {}
+ proc _tt2 {} {}
+ lsort [info pr _tt*]
+} {_tt1 _tt2}
+catch {rename _tt1 {}}
+catch {rename _tt2 {}}
+test info-13.3 {info procs option} {
+ list [catch {info procs 2 3} msg] $msg
+} {1 {wrong # args: should be "info procs [pattern]"}}
+
+test info-14.1 {info script option} {
+ list [catch {info script x} msg] $msg
+} {1 {wrong # args: should be "info script"}}
+test info-14.2 {info script option} {
+ file tail [info s]
+} info.test
+catch {exec rm -f gorp.info}
+exec cat > gorp.info << "info script\n"
+test info-14.3 {info script option} {
+ list [source gorp.info] [file tail [info script]]
+} {gorp.info info.test}
+test info-14.4 {resetting "info script" after errors} {
+ catch {source ~_nobody_/foo}
+ file tail [info script]
+} {info.test}
+test info-14.5 {resetting "info script" after errors} {
+ catch {source _nonexistent_}
+ file tail [info script]
+} {info.test}
+exec rm -f gorp.info
+
+test info-15.1 {info tclversion option} {
+ set x [info tclversion]
+ scan $x "%d.%d%c" a b c
+} 2
+test info-15.2 {info tclversion option} {
+ list [catch {info t 2} msg] $msg
+} {1 {wrong # args: should be "info tclversion"}}
+
+test info-16.1 {info vars option} {
+ set a 1
+ set b 2
+ proc t1 {x y} {
+ global a b
+ set c 33
+ return [info vars]
+ }
+ lsort [t1 18 19]
+} {a b c x y}
+test info-16.2 {info vars option} {
+ set xxx1 1
+ set xxx2 2
+ proc t1 {xxa y} {
+ global xxx1 xxx2
+ set c 33
+ return [info vars x*]
+ }
+ lsort [t1 18 19]
+} {xxa xxx1 xxx2}
+test info-16.3 {info vars option} {
+ lsort [info vars]
+} [lsort [info globals]]
+test info-16.4 {info vars option} {
+ list [catch {info vars a b} msg] $msg
+} {1 {wrong # args: should be "info vars [pattern]"}}
+
+test info-17.1 {miscellaneous error conditions} {
+ list [catch {info} msg] $msg
+} {1 {wrong # args: should be "info option ?arg arg ...?"}}
+test info-17.2 {miscellaneous error conditions} {
+ list [catch {info gorp} msg] $msg
+} {1 {bad option "gorp": should be args, body, cmdcount, commands, complete, default, exists, globals, level, library, locals, patchlevel, procs, script, tclversion, or vars}}
+test info-17.3 {miscellaneous error conditions} {
+ list [catch {info c} msg] $msg
+} {1 {bad option "c": should be args, body, cmdcount, commands, complete, default, exists, globals, level, library, locals, patchlevel, procs, script, tclversion, or vars}}
+test info-17.4 {miscellaneous error conditions} {
+ list [catch {info l} msg] $msg
+} {1 {bad option "l": should be args, body, cmdcount, commands, complete, default, exists, globals, level, library, locals, patchlevel, procs, script, tclversion, or vars}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/join.test b/vendor/x11iraf/obm/Tcl/tests/join.test
new file mode 100644
index 00000000..0d01d4d9
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/join.test
@@ -0,0 +1,52 @@
+# Commands covered: join
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/join.test,v 1.4 93/02/06 16:01:33 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test join-1.1 {basic join commands} {
+ join {a b c} xyz
+} axyzbxyzc
+test join-1.2 {basic join commands} {
+ join {a b c} {}
+} abc
+test join-1.3 {basic join commands} {
+ join {} xyz
+} {}
+test join-1.4 {basic join commands} {
+ join {12 34 56}
+} {12 34 56}
+
+test join-2.1 {join errors} {
+ list [catch join msg] $msg $errorCode
+} {1 {wrong # args: should be "join list ?joinString?"} NONE}
+test join-2.2 {join errors} {
+ list [catch {join a b c} msg] $msg $errorCode
+} {1 {wrong # args: should be "join list ?joinString?"} NONE}
+test join-2.3 {join errors} {
+ list [catch {join "a \{ c" 111} msg] $msg $errorCode
+} {1 {unmatched open brace in list} NONE}
diff --git a/vendor/x11iraf/obm/Tcl/tests/lindex.test b/vendor/x11iraf/obm/Tcl/tests/lindex.test
new file mode 100644
index 00000000..f215a4ec
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/lindex.test
@@ -0,0 +1,73 @@
+# Commands covered: lindex
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/lindex.test,v 1.2 93/02/06 16:01:45 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test lindex-1.1 {basic tests} {
+ lindex {a b c} 0} a
+test lindex-1.2 {basic tests} {
+ lindex {a {b c d} x} 1} {b c d}
+test lindex-1.3 {basic tests} {
+ lindex {a b\ c\ d x} 1} {b c d}
+test lindex-1.4 {basic tests} {
+ lindex {a b c} 3} {}
+test lindex-1.5 {basic tests} {
+ list [catch {lindex {a b c} -1} msg] $msg
+} {0 {}}
+
+test lindex-2.1 {error conditions} {
+ list [catch {lindex msg} msg] $msg
+} {1 {wrong # args: should be "lindex list index"}}
+test lindex-2.2 {error conditions} {
+ list [catch {lindex 1 2 3 4} msg] $msg
+} {1 {wrong # args: should be "lindex list index"}}
+test lindex-2.3 {error conditions} {
+ list [catch {lindex 1 2a2} msg] $msg
+} {1 {expected integer but got "2a2"}}
+test lindex-2.4 {error conditions} {
+ list [catch {lindex "a \{" 2} msg] $msg
+} {1 {unmatched open brace in list}}
+test lindex-2.5 {error conditions} {
+ list [catch {lindex {a {b c}d e} 2} msg] $msg
+} {1 {list element in braces followed by "d" instead of space}}
+test lindex-2.6 {error conditions} {
+ list [catch {lindex {a "b c"def ghi} 2} msg] $msg
+} {1 {list element in quotes followed by "def" instead of space}}
+
+test lindex-3.1 {quoted elements} {
+ lindex {a "b c" d} 1
+} {b c}
+test lindex-3.2 {quoted elements} {
+ lindex {"{}" b c} 0
+} {{}}
+test lindex-3.3 {quoted elements} {
+ lindex {ab "c d \" x" y} 1
+} {c d " x}
+test lindex-3.4 {quoted elements} {
+ lindex {a b {c d "e} {f g"}} 2
+} {c d "e}
diff --git a/vendor/x11iraf/obm/Tcl/tests/link.test b/vendor/x11iraf/obm/Tcl/tests/link.test
new file mode 100644
index 00000000..11817145
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/link.test
@@ -0,0 +1,148 @@
+# Commands covered: none
+#
+# This file contains a collection of tests for Tcl_LinkVar and related
+# library procedures. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/link.test,v 1.5 93/07/28 15:05:32 ouster Exp $ (Berkeley)
+
+if {[info commands testlink] == {}} {
+ puts "This application hasn't been compiled with the \"testlink\""
+ puts "command, so I can't test Tcl_LinkVar et al."
+ return
+}
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+foreach i {int real bool string} {
+ catch {unset $i}
+}
+test link-1.1 {reading C variables from Tcl} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 1 1 1
+ list $int $real $bool $string
+} {43 1.23 1 NULL}
+test link-1.2 {reading C variables from Tcl} {
+ testlink delete
+ testlink create 1 1 1 1
+ testlink set -3 2 0 "A long string with spaces"
+ list $int $real $bool $string $int $real $bool $string
+} {-3 2.0 0 {A long string with spaces} -3 2.0 0 {A long string with spaces}}
+
+test link-2.1 {writing C variables from Tcl} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 1 1 1
+ set int "00721"
+ set real -8e13
+ set bool true
+ set string abcdef
+ concat [testlink get] $int $real $bool $string
+} {465 -8e+13 1 abcdef 00721 -8e13 true abcdef}
+test link-2.2 {writing bad values into variables} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 1 1 1
+ list [catch {set int 09a} msg] $msg $int
+} {1 {can't set "int": variable must have integer value} 43}
+test link-2.3 {writing bad values into variables} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 1 1 1
+ list [catch {set real 1.x3} msg] $msg $real
+} {1 {can't set "real": variable must have real value} 1.23}
+test link-2.4 {writing bad values into variables} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 1 1 1
+ list [catch {set bool gorp} msg] $msg $bool
+} {1 {can't set "bool": variable must have boolean value} 1}
+
+test link-3.1 {read-only variables} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 0 1 1 0
+ list [catch {set int 4} msg] $msg $int \
+ [catch {set real 10.6} msg] $msg $real \
+ [catch {set bool no} msg] $msg $bool \
+ [catch {set string "new value"} msg] $msg $string
+} {1 {can't set "int": linked variable is read-only} 43 0 10.6 10.6 0 no no 1 {can't set "string": linked variable is read-only} NULL}
+test link-3.2 {read-only variables} {
+ testlink delete
+ testlink set 43 1.23 4 -
+ testlink create 1 0 0 1
+ list [catch {set int 4} msg] $msg $int \
+ [catch {set real 10.6} msg] $msg $real \
+ [catch {set bool no} msg] $msg $bool \
+ [catch {set string "new value"} msg] $msg $string
+} {0 4 4 1 {can't set "real": linked variable is read-only} 1.23 1 {can't set "bool": linked variable is read-only} 1 0 {new value} {new value}}
+
+test link-4.1 {unsetting linked variables} {
+ testlink delete
+ testlink set -6 -2.1 0 stringValue
+ testlink create 1 1 1 1
+ unset int real bool string
+ list [catch {set int} msg] $msg [catch {set real} msg] $msg \
+ [catch {set bool} msg] $msg [catch {set string} msg] $msg
+} {0 -6 0 -2.1 0 0 0 stringValue}
+test link-4.2 {unsetting linked variables} {
+ testlink delete
+ testlink set -6 -2.1 0 stringValue
+ testlink create 1 1 1 1
+ unset int real bool string
+ set int 102
+ set real 16
+ set bool true
+ set string newValue
+ testlink get
+} {102 16.0 1 newValue}
+
+test link-5.1 {unlinking variables} {
+ testlink delete
+ testlink set -6 -2.1 0 stringValue
+ testlink delete
+ set int xx1
+ set real qrst
+ set bool bogus
+ set string 12345
+ testlink get
+} {-6 -2.1 0 stringValue}
+test link-5.2 {unlinking variables} {
+ testlink delete
+ testlink set -6 -2.1 0 stringValue
+ testlink create 1 1 1 1
+ testlink delete
+ testlink set 25 14.7 7 -
+ list $int $real $bool $string
+} {-6 -2.1 0 stringValue}
+
+test link-6.1 {errors in setting up link} {
+ testlink delete
+ catch {unset int}
+ set int(44) 1
+ list [catch {testlink create 1 1 1 1} msg] $msg
+} {1 {can't set "int": variable is array}}
+
+testlink delete
+unset int real bool string
diff --git a/vendor/x11iraf/obm/Tcl/tests/linsert.test b/vendor/x11iraf/obm/Tcl/tests/linsert.test
new file mode 100644
index 00000000..0201405b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/linsert.test
@@ -0,0 +1,91 @@
+# Commands covered: linsert
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/linsert.test,v 1.5 93/06/19 14:31:26 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test linsert-1.1 {linsert command} {
+ linsert {1 2 3 4 5} 0 a
+} {a 1 2 3 4 5}
+test linsert-1.2 {linsert command} {
+ linsert {1 2 3 4 5} 1 a
+} {1 a 2 3 4 5}
+test linsert-1.3 {linsert command} {
+ linsert {1 2 3 4 5} 2 a
+} {1 2 a 3 4 5}
+test linsert-1.4 {linsert command} {
+ linsert {1 2 3 4 5} 3 a
+} {1 2 3 a 4 5}
+test linsert-1.5 {linsert command} {
+ linsert {1 2 3 4 5} 4 a
+} {1 2 3 4 a 5}
+test linsert-1.6 {linsert command} {
+ linsert {1 2 3 4 5} 5 a
+} {1 2 3 4 5 a}
+test linsert-1.7 {linsert command} {
+ linsert {1 2 3 4 5} 2 one two \{three \$four
+} {1 2 one two \{three {$four} 3 4 5}
+test linsert-1.8 {linsert command} {
+ linsert {\{one \$two \{three \ four \ five} 2 a b c
+} {\{one \$two a b c \{three \ four \ five}
+test linsert-1.9 {linsert command} {
+ linsert {{1 2} {3 4} {5 6} {7 8}} 2 {x y} {a b}
+} {{1 2} {3 4} {x y} {a b} {5 6} {7 8}}
+test linsert-1.10 {linsert command} {
+ linsert {} 2 a b c
+} {a b c}
+test linsert-1.11 {linsert command} {
+ linsert {} 2 {}
+} {{}}
+test linsert-1.12 {linsert command} {
+ linsert {a b "c c" d e} 3 1
+} {a b "c c" 1 d e}
+test linsert-1.13 {linsert command} {
+ linsert { a b c d} 0 1 2
+} {1 2 a b c d}
+test linsert-1.14 {linsert command} {
+ linsert {a b c {d e f}} 4 1 2
+} {a b c {d e f} 1 2}
+test linsert-1.15 {linsert command} {
+ linsert {a b c \{\ abc} 4 q r
+} {a b c \{\ q r abc}
+test linsert-1.16 {linsert command} {
+ linsert {a b c \{ abc} 4 q r
+} {a b c \{ q r abc}
+
+test linsert-2.1 {linsert errors} {
+ list [catch linsert msg] $msg
+} {1 {wrong # args: should be "linsert list index element ?element ...?"}}
+test linsert-2.2 {linsert errors} {
+ list [catch {linsert a b} msg] $msg
+} {1 {wrong # args: should be "linsert list index element ?element ...?"}}
+test linsert-2.3 {linsert errors} {
+ list [catch {linsert a 12x 2} msg] $msg
+} {1 {expected integer but got "12x"}}
+test linsert-2.4 {linsert errors} {
+ list [catch {linsert \{ 12 2} msg] $msg
+} {1 {unmatched open brace in list}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/list.test b/vendor/x11iraf/obm/Tcl/tests/list.test
new file mode 100644
index 00000000..8bc07815
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/list.test
@@ -0,0 +1,87 @@
+# Commands covered: list
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/list.test,v 1.18 93/10/28 16:14:10 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+# First, a bunch of individual tests
+
+test list-1.1 {basic tests} {list a b c} {a b c}
+test list-1.2 {basic tests} {list {a b} c} {{a b} c}
+test list-1.3 {basic tests} {list \{a b c} {\{a b c}
+test list-1.4 {basic tests} "list a{}} b{} c}" "a\\{\\}\\} b{} c\\}"
+test list-1.5 {basic tests} {list a\[ b\] } "{a\[} b\\]"
+test list-1.6 {basic tests} {list c\ d\t } "{c } {d\t}"
+test list-1.7 {basic tests} {list e\n f\$ } "{e\n} {f\$}"
+test list-1.8 {basic tests} {list g\; h\\} {{g;} h\\}
+test list-1.9 {basic tests} "list a\\\[} b\\\]} " "a\\\[\\\} b\\\]\\\}"
+test list-1.10 {basic tests} "list c\\\} d\\t} " "c\\} d\\t\\}"
+test list-1.11 {basic tests} "list e\\n} f\\$} " "e\\n\\} f\\$\\}"
+test list-1.12 {basic tests} "list g\\;} h\\\\} " "g\\;\\} {h\\}}"
+test list-1.13 {basic tests} {list a {{}} b} {a {{}} b}
+test list-1.14 {basic tests} {list a b xy\\} "a b xy\\\\"
+test list-1.15 {basic tests} "list a b\} e\\" "a b\\} e\\\\"
+test list-1.16 {basic tests} "list a b\}\\\$ e\\\$\\" "a b\\}\\\$ e\\\$\\\\"
+test list-1.17 {basic tests} {list a\f \{\f} "{a\f} \\\{\\f"
+test list-1.18 {basic tests} {list a\r \{\r} "{a\r} \\\{\\r"
+test list-1.19 {basic tests} {list a\v \{\v} "{a\v} \\\{\\v"
+test list-1.20 {basic tests} {list \"\}\{} "\\\"\\}\\{"
+test list-1.21 {basic tests} {list a b c\\\nd} "a b c\\\\\\nd"
+test list-1.22 {basic tests} {list "{ab}\\"} \\{ab\\}\\\\
+test list-1.23 {basic tests} {list \{} "\\{"
+test list-1.24 {basic tests} {list} {}
+
+# For the next round of tests create a list and then pick it apart
+# with "index" to make sure that we get back exactly what went in.
+
+set num 1
+proc lcheck {a b c} {
+ global num d
+ set d [list $a $b $c]
+ test list-2.$num {what goes in must come out} {lindex $d 0} $a
+ set num [expr $num+1]
+ test list-2.$num {what goes in must come out} {lindex $d 1} $b
+ set num [expr $num+1]
+ test list-2.$num {what goes in must come out} {lindex $d 2} $c
+ set num [expr $num+1]
+}
+lcheck a b c
+lcheck "a b" c\td e\nf
+lcheck {{a b}} {} { }
+lcheck \$ \$ab ab\$
+lcheck \; \;ab ab\;
+lcheck \[ \[ab ab\[
+lcheck \\ \\ab ab\\
+lcheck {"} {"ab} {ab"}
+lcheck {a b} { ab} {ab }
+lcheck a{ a{b \{ab
+lcheck a} a}b }ab
+lcheck a\\} {a \}b} {a \{c}
+lcheck xyz \\ 1\\\n2
+lcheck "{ab}\\" "{ab}xy" abc
+
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/llength.test b/vendor/x11iraf/obm/Tcl/tests/llength.test
new file mode 100644
index 00000000..371e1657
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/llength.test
@@ -0,0 +1,49 @@
+# Commands covered: llength
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/llength.test,v 1.2 93/02/06 16:01:45 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test llength-1.1 {length of list} {
+ llength {a b c d}
+} 4
+test llength-1.2 {length of list} {
+ llength {a b c {a b {c d}} d}
+} 5
+test llength-1.3 {length of list} {
+ llength {}
+} 0
+
+test llength-2.1 {error conditions} {
+ list [catch {llength} msg] $msg
+} {1 {wrong # args: should be "llength list"}}
+test llength-2.2 {error conditions} {
+ list [catch {llength 123 2} msg] $msg
+} {1 {wrong # args: should be "llength list"}}
+test llength-2.3 {error conditions} {
+ list [catch {llength "a b c \{"} msg] $msg
+} {1 {unmatched open brace in list}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/lrange.test b/vendor/x11iraf/obm/Tcl/tests/lrange.test
new file mode 100644
index 00000000..b8aef6bf
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/lrange.test
@@ -0,0 +1,79 @@
+# Commands covered: lrange
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/lrange.test,v 1.2 93/02/06 16:01:44 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test lrange-1.1 {range of list elements} {
+ lrange {a b c d} 1 2
+} {b c}
+test lrange-1.2 {range of list elements} {
+ lrange {a {bcd e {f g {}}} l14 l15 d} 1 1
+} {{bcd e {f g {}}}}
+test lrange-1.3 {range of list elements} {
+ lrange {a {bcd e {f g {}}} l14 l15 d} 3 end
+} {l15 d}
+test lrange-1.4 {range of list elements} {
+ lrange {a {bcd e {f g {}}} l14 l15 d} 4 10000
+} {d}
+test lrange-1.5 {range of list elements} {
+ lrange {a {bcd e {f g {}}} l14 l15 d} 4 3
+} {}
+test lrange-1.6 {range of list elements} {
+ lrange {a {bcd e {f g {}}} l14 l15 d} 10 11
+} {}
+test lrange-1.7 {range of list elements} {
+ lrange {a b c d e} -1 2
+} {a b c}
+test lrange-1.8 {range of list elements} {
+ lrange {a b c d e} -2 -1
+} {}
+test lrange-1.9 {range of list elements} {
+ lrange {a b c d e} -2 e
+} {a b c d e}
+test lrange-1.10 {range of list elements} {
+ lrange "a b\{c d" 1 2
+} "b\{c d"
+
+test lrange-2.1 {error conditions} {
+ list [catch {lrange a b} msg] $msg
+} {1 {wrong # args: should be "lrange list first last"}}
+test lrange-2.2 {error conditions} {
+ list [catch {lrange a b 6 7} msg] $msg
+} {1 {wrong # args: should be "lrange list first last"}}
+test lrange-2.3 {error conditions} {
+ list [catch {lrange a b 6} msg] $msg
+} {1 {expected integer but got "b"}}
+test lrange-2.4 {error conditions} {
+ list [catch {lrange a 0 enigma} msg] $msg
+} {1 {expected integer or "end" but got "enigma"}}
+test lrange-2.5 {error conditions} {
+ list [catch {lrange "a \{b c" 3 4} msg] $msg
+} {1 {unmatched open brace in list}}
+test lrange-2.6 {error conditions} {
+ list [catch {lrange "a b c \{ d e" 1 4} msg] $msg
+} {1 {unmatched open brace in list}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/lreplace.test b/vendor/x11iraf/obm/Tcl/tests/lreplace.test
new file mode 100644
index 00000000..d3025288
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/lreplace.test
@@ -0,0 +1,106 @@
+# Commands covered: lreplace
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/lreplace.test,v 1.5 93/02/06 16:01:39 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test lreplace-1.1 {lreplace command} {
+ lreplace {1 2 3 4 5} 0 0 a
+} {a 2 3 4 5}
+test lreplace-1.2 {lreplace command} {
+ lreplace {1 2 3 4 5} 1 1 a
+} {1 a 3 4 5}
+test lreplace-1.3 {lreplace command} {
+ lreplace {1 2 3 4 5} 2 2 a
+} {1 2 a 4 5}
+test lreplace-1.4 {lreplace command} {
+ lreplace {1 2 3 4 5} 3 3 a
+} {1 2 3 a 5}
+test lreplace-1.5 {lreplace command} {
+ lreplace {1 2 3 4 5} 4 4 a
+} {1 2 3 4 a}
+test lreplace-1.6 {lreplace command} {
+ lreplace {1 2 3 4 5} 4 5 a
+} {1 2 3 4 a}
+test lreplace-1.7 {lreplace command} {
+ lreplace {1 2 3 4 5} -1 -1 a
+} {a 2 3 4 5}
+test lreplace-1.8 {lreplace command} {
+ lreplace {1 2 3 4 5} 2 end a b c d
+} {1 2 a b c d}
+test lreplace-1.9 {lreplace command} {
+ lreplace {1 2 3 4 5} 0 3
+} {5}
+test lreplace-1.10 {lreplace command} {
+ lreplace {1 2 3 4 5} 0 4
+} {}
+test lreplace-1.11 {lreplace command} {
+ lreplace {1 2 3 4 5} 0 1
+} {3 4 5}
+test lreplace-1.12 {lreplace command} {
+ lreplace {1 2 3 4 5} 2 3
+} {1 2 5}
+test lreplace-1.13 {lreplace command} {
+ lreplace {1 2 3 4 5} 3 end
+} {1 2 3}
+test lreplace-1.14 {lreplace command} {
+ lreplace {1 2 3 4 5} -1 4 a b c
+} {a b c}
+test lreplace-1.15 {lreplace command} {
+ lreplace {a b "c c" d e f} 3 3
+} {a b "c c" e f}
+test lreplace-1.16 {lreplace command} {
+ lreplace { 1 2 3 4 5} 0 0 a
+} {a 2 3 4 5}
+test lreplace-1.17 {lreplace command} {
+ lreplace {1 2 3 4 "5 6"} 4 4 a
+} {1 2 3 4 a}
+test lreplace-1.18 {lreplace command} {
+ lreplace {1 2 3 4 {5 6}} 4 4 a
+} {1 2 3 4 a}
+
+test lreplace-2.1 {lreplace errors} {
+ list [catch lreplace msg] $msg
+} {1 {wrong # args: should be "lreplace list first last ?element element ...?"}}
+test lreplace-2.2 {lreplace errors} {
+ list [catch {lreplace a b} msg] $msg
+} {1 {wrong # args: should be "lreplace list first last ?element element ...?"}}
+test lreplace-2.3 {lreplace errors} {
+ list [catch {lreplace x a 10} msg] $msg
+} {1 {expected integer but got "a"}}
+test lreplace-2.4 {lreplace errors} {
+ list [catch {lreplace x 10 x} msg] $msg
+} {1 {bad index "x": must be integer or "end"}}
+test lreplace-2.5 {lreplace errors} {
+ list [catch {lreplace x 10 1x} msg] $msg
+} {1 {expected integer but got "1x"}}
+test lreplace-2.6 {lreplace errors} {
+ list [catch {lreplace x 3 2} msg] $msg
+} {1 {first index must not be greater than second}}
+test lreplace-2.7 {lreplace errors} {
+ list [catch {lreplace x 1 1} msg] $msg
+} {1 {list doesn't contain element 1}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/lsearch.test b/vendor/x11iraf/obm/Tcl/tests/lsearch.test
new file mode 100644
index 00000000..73bbdaf2
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/lsearch.test
@@ -0,0 +1,81 @@
+# Commands covered: lsearch
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/lsearch.test,v 1.3 93/05/06 16:18:04 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+set x {abcd bbcd 123 234 345}
+test lsearch-1.1 {lsearch command} {
+ lsearch $x 123
+} 2
+test lsearch-1.2 {lsearch command} {
+ lsearch $x 3456
+} -1
+test lsearch-1.3 {lsearch command} {
+ lsearch $x *5
+} 4
+test lsearch-1.4 {lsearch command} {
+ lsearch $x *bc*
+} 0
+
+test lsearch-2.1 {search modes} {
+ lsearch -exact {xyz bbcc *bc*} *bc*
+} 2
+test lsearch-2.2 {search modes} {
+ lsearch -exact {b.x ^bc xy bcx} ^bc
+} 1
+test lsearch-2.3 {search modes} {
+ list [catch {lsearch -regexp {xyz bbcc *bc*} *bc*} msg] $msg
+} {1 {couldn't compile regular expression pattern: ?+* follows nothing}}
+test lsearch-2.4 {search modes} {
+ lsearch -regexp {b.x ^bc xy bcx} ^bc
+} 3
+test lsearch-2.5 {search modes} {
+ lsearch -glob {xyz bbcc *bc*} *bc*
+} 1
+test lsearch-2.6 {search modes} {
+ lsearch -glob {b.x ^bc xy bcx} ^bc
+} 1
+test lsearch-2.7 {search modes} {
+ list [catch {lsearch -glib {b.x bx xy bcx} b.x} msg] $msg
+} {1 {bad search mode "-glib": must be -exact, -glob, or -regexp}}
+
+test lsearch-3.1 {lsearch errors} {
+ list [catch lsearch msg] $msg
+} {1 {wrong # args: should be "lsearch ?mode? list pattern"}}
+test lsearch-3.2 {lsearch errors} {
+ list [catch {lsearch a} msg] $msg
+} {1 {wrong # args: should be "lsearch ?mode? list pattern"}}
+test lsearch-3.3 {lsearch errors} {
+ list [catch {lsearch a b c} msg] $msg
+} {1 {bad search mode "a": must be -exact, -glob, or -regexp}}
+test lsearch-3.4 {lsearch errors} {
+ list [catch {lsearch a b c d} msg] $msg
+} {1 {wrong # args: should be "lsearch ?mode? list pattern"}}
+test lsearch-3.5 {lsearch errors} {
+ list [catch {lsearch "\{" b} msg] $msg
+} {1 {unmatched open brace in list}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/lsort.test b/vendor/x11iraf/obm/Tcl/tests/lsort.test
new file mode 100644
index 00000000..0020eb5c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/lsort.test
@@ -0,0 +1,136 @@
+# Commands covered: lsort
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/lsort.test,v 1.4 93/10/22 14:25:01 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test lsort-1.1 {lsort command} {
+ lsort {abdeq ab 1 ac a}
+} {1 a ab abdeq ac}
+test lsort-1.2 {lsort command} {
+ lsort -decreasing {abdeq ab 1 ac a}
+} {ac abdeq ab a 1}
+test lsort-1.3 {lsort command} {
+ lsort -increasing {abdeq ab 1 ac a}
+} {1 a ab abdeq ac}
+test lsort-1.4 {lsort command} {
+ lsort {{one long element}}
+} {{one long element}}
+test lsort-1.5 {lsort command} {
+ lsort {}
+} {}
+test lsort-1.6 {lsort with characters needing backslashes} {
+ lsort {$ \\ [] \{}
+} {{$} {[]} \\ \{}
+
+test lsort-2.1 {lsort -integer} {
+ lsort -integer -inc {1 180 62 040 180 -42 33 0x40}
+} {-42 1 040 33 62 0x40 180 180}
+test lsort-2.2 {lsort -integer} {
+ lsort -int -dec {1 180 62 040 180 -42 33 0x40}
+} {180 180 0x40 62 33 040 1 -42}
+test lsort-2.3 {lsort -integer} {
+ list [catch {lsort -integer {xxx 180.2 62 040 180 -42 33 0x40}} msg] $msg $errorInfo
+} {1 {expected integer but got "xxx"} {expected integer but got "xxx"
+ (converting list element from string to integer)
+ invoked from within
+"lsort -integer {xxx 180.2 62 040 180 -42 33 0x40}"}}
+test lsort-2.4 {lsort -integer} {
+ list [catch {lsort -integer {1 180.2 62 040 180 -42 33 0x40}} msg] $msg $errorInfo
+} {1 {expected integer but got "180.2"} {expected integer but got "180.2"
+ (converting list element from string to integer)
+ invoked from within
+"lsort -integer {1 180.2 62 040 180 -42 33 0x40}"}}
+
+test lsort-3.1 {lsort -real} {
+ lsort -real {1 180.1 62 040 180 -42.7 33}
+} {-42.7 1 33 040 62 180 180.1}
+test lsort-3.2 {lsort -real} {
+ lsort -r -d {1 180.1 62 040 180 -42.7 33}
+} {180.1 180 62 040 33 1 -42.7}
+test lsort-3.3 {lsort -real} {
+ list [catch {lsort -real -inc {xxx 20 62 180 -42.7 33}} msg] $msg $errorInfo
+} {1 {expected floating-point number but got "xxx"} {expected floating-point number but got "xxx"
+ (converting list element from string to real)
+ invoked from within
+"lsort -real -inc {xxx 20 62 180 -42.7 33}"}}
+test lsort-3.4 {lsort -real} {
+ list [catch {lsort -real -inc {1 0x40 62 180 -42.7 33}} msg] $msg $errorInfo
+} {1 {expected floating-point number but got "0x40"} {expected floating-point number but got "0x40"
+ (converting list element from string to real)
+ invoked from within
+"lsort -real -inc {1 0x40 62 180 -42.7 33}"}}
+
+proc lsort1 {a b} {
+ expr {2*([string match x* $a] - [string match x* $b])
+ + [string match *y $a] - [string match *y $b]}
+}
+proc lsort2 {a b} {
+ error "comparison error"
+}
+proc lsort3 {a b} {
+ concat "foobar"
+}
+
+test lsort-4.1 {lsort -command} {
+ lsort -command lsort1 {xxx yyy abc {xx y}}
+} {abc yyy xxx {xx y}}
+test lsort-4.2 {lsort -command} {
+ lsort -command lsort1 -dec {xxx yyy abc {xx y}}
+} {{xx y} xxx yyy abc}
+test lsort-4.3 {lsort -command} {
+ list [catch {lsort -command lsort2 -dec {1 1 1 1}} msg] $msg $errorInfo
+} {1 {comparison error} {comparison error
+ while executing
+"error "comparison error""
+ (procedure "lsort2" line 2)
+ invoked from within
+"lsort2 1 1"
+ (user-defined comparison command)
+ invoked from within
+"lsort -command lsort2 -dec {1 1 1 1}"}}
+test lsort-4.4 {lsort -command} {
+ list [catch {lsort -command lsort3 -dec {1 2 3 4}} msg] $msg $errorInfo
+} {1 {comparison command returned non-numeric result} {comparison command returned non-numeric result
+ while executing
+"lsort -command lsort3 -dec {1 2 3 4}"}}
+test lsort-4.5 {lsort -command} {
+ list [catch {lsort -command {xxx yyy xxy abc}} msg] $msg
+} {1 {"-command" must be followed by comparison command}}
+
+test lsort-5.1 {lsort errors} {
+ list [catch lsort msg] $msg
+} {1 {wrong # args: should be "lsort ?-ascii? ?-integer? ?-real? ?-increasing? ?-decreasing? ?-command string? list"}}
+test lsort-5.2 {lsort errors} {
+ list [catch {lsort a b} msg] $msg
+} {1 {bad switch "a": must be -ascii, -integer, -real, -increasing -decreasing, or -command}}
+test lsort-5.3 {lsort errors} {
+ list [catch {lsort "\{"} msg] $msg
+} {1 {unmatched open brace in list}}
+test lsort-5.4 {lsort errors} {
+ list [catch {lsort -in {1 180.0 040 62 180 -42.7 33}} msg] $msg
+} {1 {bad switch "-in": must be -ascii, -integer, -real, -increasing -decreasing, or -command}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/misc.test b/vendor/x11iraf/obm/Tcl/tests/misc.test
new file mode 100644
index 00000000..d05a63f5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/misc.test
@@ -0,0 +1,84 @@
+# Commands covered: various
+#
+# This file contains a collection of miscellaneous Tcl tests that
+# don't fit naturally in any of the other test files. Many of these
+# tests are pathological cases that caused bugs in earlier Tcl
+# releases.
+#
+# Copyright (c) 1992-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/misc.test,v 1.3 93/10/07 11:41:23 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test misc-1.1 {error in variable ref. in command in array reference} {
+ proc tstProc {} {
+ global a
+
+ set tst $a([winfo name $zz])
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ }
+ set msg {}
+ list [catch tstProc msg] $msg
+} {1 {can't read "zz": no such variable}}
+test misc-1.2 {error in variable ref. in command in array reference} {
+ proc tstProc {} "
+ global a
+
+ set tst \$a(\[winfo name \$\{zz)
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ "
+ set msg {}
+ list [catch tstProc msg] $msg $errorInfo
+} [list 1 {missing close-brace for variable name} \
+[format {missing close-brace for variable name
+ while executing
+"winfo name $%szz)
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus commen ..."
+ (parsing index for array "a")
+ invoked from within
+"set tst $a([winfo name $%szz)
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a bogus comment
+ # this is a ..."
+ (procedure "tstProc" line 4)
+ invoked from within
+"tstProc"} \{ \{]]
diff --git a/vendor/x11iraf/obm/Tcl/tests/open.test b/vendor/x11iraf/obm/Tcl/tests/open.test
new file mode 100644
index 00000000..950873d5
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/open.test
@@ -0,0 +1,662 @@
+# Commands covered: open, close, gets, puts, read, seek, tell, eof, flush
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/open.test,v 1.19 93/10/18 08:52:24 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {exec rm -f test1 test2 test3}
+exec cat > test1 << "Two lines: this one\nand this one\n"
+exec cat > test2 << "line1\nline2\nline3\nline4\nline5\n"
+
+test open-1.1 {open command (files only)} {
+ set f [open test1]
+ set x [gets $f]
+ close $f
+ set x
+} {Two lines: this one}
+test open-1.2 {open command (files only)} {
+ set f [open test1]
+ set f2 [open test2]
+ set f3 [open test1]
+ set f4 [open test1]
+ set x [list [gets $f] [gets $f2] [gets $f3] [gets $f4] \
+ [gets $f] [gets $f2]]
+ close $f
+ close $f2
+ close $f3
+ close $f4
+ set x
+} {{Two lines: this one} line1 {Two lines: this one} {Two lines: this one} {and this one} line2}
+test open-1.3 {open command (files only)} {
+ set f [open test3 w]
+ puts $f xyz
+ close $f
+ exec cat test3
+} "xyz"
+test open-1.4 {open command (files only)} {
+ set f [open test3 w]
+ puts $f xyz
+ close $f
+ set f [open test3 a]
+ puts $f 123
+ close $f
+ exec cat test3
+} "xyz\n123"
+test open-1.5 {open command (files only)} {
+ set f [open test3 w]
+ puts $f xyz\n123
+ close $f
+ set f [open test3 r+]
+ set x [gets $f]
+ seek $f 0 current
+ puts $f 456
+ close $f
+ list $x [exec cat test3]
+} "xyz {xyz
+456}"
+test open-1.6 {open command (files only)} {
+ set f [open test3 w]
+ puts $f xyz\n123
+ close $f
+ set f [open test3 w+]
+ puts $f xyzzy
+ seek $f 2
+ set x [gets $f]
+ close $f
+ list $x [exec cat test3]
+} "zzy xyzzy"
+test open-1.7 {open command (files only)} {
+ set f [open test3 w]
+ puts $f xyz\n123
+ close $f
+ set f [open test3 a+]
+ puts $f xyzzy
+ flush $f
+ set x [tell $f]
+ seek $f -4 cur
+ set y [gets $f]
+ close $f
+ list $x [exec cat test3] $y
+} {14 {xyz
+123
+xyzzy} zzy}
+
+test open-2.1 {errors in open command} {
+ list [catch {open} msg] $msg
+} {1 {wrong # args: should be "open filename ?access? ?permissions?"}}
+test open-2.2 {errors in open command} {
+ list [catch {open a b c d} msg] $msg
+} {1 {wrong # args: should be "open filename ?access? ?permissions?"}}
+test open-2.3 {errors in open command} {
+ list [catch {open test1 x} msg] $msg
+} {1 {illegal access mode "x"}}
+test open-2.4 {errors in open command} {
+ list [catch {open test1 rw} msg] $msg
+} {1 {illegal access mode "rw"}}
+test open-2.5 {errors in open command} {
+ list [catch {open test1 r+1} msg] $msg
+} {1 {illegal access mode "r+1"}}
+test open-2.6 {errors in open command} {
+ string tolower [list [catch {open _non_existent_} msg] $msg $errorCode]
+} {1 {couldn't open "_non_existent_": no such file or directory} {posix enoent {no such file or directory}}}
+
+if {![file exists ~/_test_] && [file writable ~]} {
+ test open-3.1 {tilde substitution in open} {
+ set f [open ~/_test_ w]
+ puts $f "Some text"
+ close $f
+ set x [file exists $env(HOME)/_test_]
+ exec rm -f $env(HOME)/_test_
+ set x
+ } 1
+}
+test open-3.2 {tilde substitution in open} {
+ set home $env(HOME)
+ unset env(HOME)
+ set x [list [catch {open ~/foo} msg] $msg]
+ set env(HOME) $home
+ set x
+} {1 {couldn't find HOME environment variable to expand "~/foo"}}
+
+test open-4.1 {file id parsing errors} {
+ list [catch {eof gorp} msg] $msg $errorCode
+} {1 {bad file identifier "gorp"} NONE}
+test open-4.2 {file id parsing errors} {
+ list [catch {eof filex} msg] $msg
+} {1 {bad file identifier "filex"}}
+test open-4.3 {file id parsing errors} {
+ list [catch {eof file12a} msg] $msg
+} {1 {bad file identifier "file12a"}}
+test open-4.4 {file id parsing errors} {
+ list [catch {eof file123} msg] $msg
+} {1 {file "file123" isn't open}}
+test open-4.5 {file id parsing errors} {
+ list [catch {eof file1} msg] $msg
+} {0 0}
+test open-4.5 {file id parsing errors} {
+ list [catch {eof stdin} msg] $msg
+} {0 0}
+test open-4.6 {file id parsing errors} {
+ list [catch {eof stdout} msg] $msg
+} {0 0}
+test open-4.7 {file id parsing errors} {
+ list [catch {eof stderr} msg] $msg
+} {0 0}
+test open-4.8 {file id parsing errors} {
+ list [catch {eof stderr1} msg] $msg
+} {1 {bad file identifier "stderr1"}}
+set f [open test1]
+close $f
+set expect "1 {file \"$f\" isn't open}"
+test open-4.9 {file id parsing errors} {
+ list [catch {eof $f} msg] $msg
+} $expect
+
+test open-5.1 {close command (files only)} {
+ list [catch {close} msg] $msg $errorCode
+} {1 {wrong # args: should be "close fileId"} NONE}
+test open-5.2 {close command (files only)} {
+ list [catch {close a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "close fileId"} NONE}
+test open-5.3 {close command (files only)} {
+ list [catch {close gorp} msg] $msg $errorCode
+} {1 {bad file identifier "gorp"} NONE}
+test open-5.4 {close command (files only)} {
+ list [catch {close file4} msg] \
+ [string range $msg [string first {" } $msg] end] $errorCode
+} {1 {" isn't open} NONE}
+
+test open-6.1 {puts command} {
+ list [catch {puts} msg] $msg $errorCode
+} {1 {wrong # args: should be "puts" ?-nonewline? ?fileId? string} NONE}
+test open-6.2 {puts command} {
+ list [catch {puts a b c d} msg] $msg $errorCode
+} {1 {wrong # args: should be "puts" ?-nonewline? ?fileId? string} NONE}
+test open-6.3 {puts command} {
+ list [catch {puts a b nonewlinx} msg] $msg $errorCode
+} {1 {bad argument "nonewlinx": should be "nonewline"} NONE}
+test open-6.4 {puts command} {
+ list [catch {puts gorp "New text"} msg] $msg $errorCode
+} {1 {bad file identifier "gorp"} NONE}
+test open-6.5 {puts command} {
+ set f [open test3]
+ set x [list [catch {puts $f "New text"} msg] \
+ [string range $msg [string first " " $msg] end] $errorCode]
+ close $f
+ set x
+} {1 { wasn't opened for writing} NONE}
+test open-6.6 {puts command} {
+ set f [open test3 w]
+ puts -nonewline $f "Text1"
+ puts -nonewline $f " Text 2"
+ puts $f " Text 3"
+ close $f
+ exec cat test3
+} {Text1 Text 2 Text 3}
+
+test open-7.1 {gets command} {
+ list [catch {gets} msg] $msg $errorCode
+} {1 {wrong # args: should be "gets fileId ?varName?"} NONE}
+test open-7.2 {gets command} {
+ list [catch {gets a b c} msg] $msg $errorCode
+} {1 {wrong # args: should be "gets fileId ?varName?"} NONE}
+test open-7.3 {gets command} {
+ list [catch {gets a} msg] $msg $errorCode
+} {1 {bad file identifier "a"} NONE}
+test open-7.4 {gets command} {
+ set f [open test3 w]
+ set x [list [catch {gets $f} msg] \
+ [string range $msg [string first " " $msg] end] $errorCode]
+ close $f
+ set x
+} {1 { wasn't opened for reading} NONE}
+set f [open test3 w]
+puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+puts $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+close $f
+test open-7.5 {gets command with long line} {
+ set f [open test3]
+ set x [gets $f]
+ close $f
+ set x
+} {abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}
+test open-7.6 {gets command with long line} {
+ set f [open test3]
+ set x [gets $f y]
+ close $f
+ list $x $y
+} {260 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}
+test open-7.7 {gets command and end of file} {
+ set f [open test3 w]
+ puts -nonewline $f "Test1\nTest2"
+ close $f
+ set f [open test3]
+ set x {}
+ set y {}
+ lappend x [gets $f y] $y
+ set y {}
+ lappend x [gets $f y] $y
+ set y {}
+ lappend x [gets $f y] $y
+ close $f
+ set x
+} {5 Test1 5 Test2 -1 {}}
+set f [open test3 w]
+puts $f "Line 1"
+puts $f "Line 2"
+close $f
+test open-7.8 {gets command and bad variable} {
+ catch {unset x}
+ set x 24
+ set f [open test3 r]
+ set result [list [catch {gets $f x(0)} msg] $msg]
+ close $f
+ set result
+} {1 {can't set "x(0)": variable isn't array}}
+
+test open-8.1 {read command} {
+ list [catch {read} msg] $msg $errorCode
+} {1 {wrong # args: should be "read fileId ?numBytes?" or "read ?-nonewline? fileId"} NONE}
+test open-8.2 {read command} {
+ list [catch {read -nonewline} msg] $msg $errorCode
+} {1 {bad file identifier "-nonewline"} NONE}
+test open-8.3 {read command} {
+ list [catch {read a b c} msg] $msg $errorCode
+} {1 {wrong # args: should be "read fileId ?numBytes?" or "read ?-nonewline? fileId"} NONE}
+test open-8.4 {read command} {
+ list [catch {read -nonew file4} msg] $msg $errorCode
+} {1 {bad file identifier "-nonew"} NONE}
+test open-8.5 {read command} {
+ list [catch {read stdin foo} msg] $msg $errorCode
+} {1 {bad argument "foo": should be "nonewline"} NONE}
+test open-8.6 {read command} {
+ list [catch {read file10} msg] $msg $errorCode
+} {1 {file "file10" isn't open} NONE}
+test open-8.7 {read command} {
+ set f [open test3 w]
+ set x [list [catch {read $f} msg] \
+ [string range $msg [string first " " $msg] end] $errorCode]
+ close $f
+ set x
+} {1 { wasn't opened for reading} NONE}
+test open-8.8 {read command} {
+ set f [open test1]
+ set x [list [catch {read $f 12z} msg] $msg $errorCode]
+ close $f
+ set x
+} {1 {expected integer but got "12z"} NONE}
+test open-898 {read command} {
+ set f [open test1]
+ set x [list [catch {read $f z} msg] $msg $errorCode]
+ close $f
+ set x
+} {1 {bad argument "z": should be "nonewline"} NONE}
+test open-8.10 {read command} {
+ set f [open test1]
+ set x [list [read $f 1] [read $f 2] [read $f]]
+ close $f
+ set x
+} {T wo { lines: this one
+and this one
+}}
+test open-8.11 {read command, with over-large count} {
+ set f [open test1]
+ set x [read $f 100]
+ close $f
+ set x
+} {Two lines: this one
+and this one
+}
+test open-8.12 {read command, -nonewline switch} {
+ set f [open test1]
+ set x [read -nonewline $f]
+ close $f
+ set x
+} {Two lines: this one
+and this one}
+
+test open-9.1 {seek command} {
+ list [catch {seek foo} msg] $msg $errorCode
+} {1 {wrong # args: should be "seek fileId offset ?origin?"} NONE}
+test open-9.2 {seek command} {
+ list [catch {seek foo a b c} msg] $msg $errorCode
+} {1 {wrong # args: should be "seek fileId offset ?origin?"} NONE}
+test open-9.3 {seek command} {
+ list [catch {seek foo 0} msg] $msg $errorCode
+} {1 {bad file identifier "foo"} NONE}
+test open-9.4 {seek command} {
+ set f [open test2]
+ set x [list [catch {seek $f xyz} msg] $msg $errorCode]
+ close $f
+ set x
+} {1 {expected integer but got "xyz"} NONE}
+test open-9.5 {seek command} {
+ set f [open test2]
+ set x [list [catch {seek $f 100 gorp} msg] $msg $errorCode]
+ close $f
+ set x
+} {1 {bad origin "gorp": should be start, current, or end} NONE}
+set f [open test3 w]
+puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+close $f
+test open-9.6 {seek command} {
+ set f [open test3]
+ set x [read $f 1]
+ seek $f 3
+ lappend x [read $f 1]
+ seek $f 0 start
+ lappend x [read $f 1]
+ seek $f 10 current
+ lappend x [read $f 1]
+ seek $f -2 end
+ lappend x [read $f 1]
+ seek $f 50 end
+ lappend x [read $f 1]
+ seek $f 1
+ lappend x [read $f 1]
+ close $f
+ set x
+} {a d a l Y {} b}
+
+test open-10.1 {tell command} {
+ list [catch {tell} msg] $msg $errorCode
+} {1 {wrong # args: should be "tell fileId"} NONE}
+test open-10.2 {tell command} {
+ list [catch {tell a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "tell fileId"} NONE}
+test open-10.3 {tell command} {
+ list [catch {tell a} msg] $msg $errorCode
+} {1 {bad file identifier "a"} NONE}
+test open-10.4 {tell command} {
+ set f [open test2]
+ set x [tell $f]
+ read $f 3
+ lappend x [tell $f]
+ seek $f 2
+ lappend x [tell $f]
+ seek $f 10 current
+ lappend x [tell $f]
+ seek $f 0 end
+ lappend x [tell $f]
+ close $f
+ set x
+} {0 3 2 12 30}
+
+test open-11.1 {eof command} {
+ list [catch {eof} msg] $msg $errorCode
+} {1 {wrong # args: should be "eof fileId"} NONE}
+test open-11.2 {eof command} {
+ list [catch {eof a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "eof fileId"} NONE}
+test open-11.3 {eof command} {
+ list [catch {eof file100} msg] $msg $errorCode
+} {1 {file "file100" isn't open} NONE}
+test open-11.4 {eof command} {
+ set f [open test1]
+ set x [eof $f]
+ lappend x [eof $f]
+ gets $f
+ lappend x [eof $f]
+ gets $f
+ lappend x [eof $f]
+ gets $f
+ lappend x [eof $f]
+ lappend x [eof $f]
+ close $f
+ set x
+} {0 0 0 0 1 1}
+
+test open-12.1 {flush command} {
+ list [catch {flush} msg] $msg $errorCode
+} {1 {wrong # args: should be "flush fileId"} NONE}
+test open-12.2 {flush command} {
+ list [catch {flush a b} msg] $msg $errorCode
+} {1 {wrong # args: should be "flush fileId"} NONE}
+test open-12.3 {flush command} {
+ list [catch {flush a} msg] $msg $errorCode
+} {1 {bad file identifier "a"} NONE}
+test open-12.4 {flush command} {
+ set f [open test3]
+ set x [list [catch {flush $f} msg] \
+ [string range $msg [string first " " $msg] end] $errorCode]
+ close $f
+ set x
+} {1 { wasn't opened for writing} NONE}
+test open-12.5 {flush command} {
+ set f [open test3 w]
+ puts $f "Line 1"
+ puts $f "Line 2"
+ set f2 [open test3]
+ set x {}
+ lappend x [read -nonewline $f2]
+ close $f2
+ flush $f
+ set f2 [open test3]
+ lappend x [read -nonewline $f2]
+ close $f2
+ close $f
+ set x
+} {{} {Line 1
+Line 2}}
+
+test open-13.1 {I/O to command pipelines} {
+ list [catch {open "| cat < test1 > test3" w} msg] $msg $errorCode
+} {1 {can't write input to command: standard input was redirected} NONE}
+test open-13.2 {I/O to command pipelines} {
+ list [catch {open "| echo > test3" r} msg] $msg $errorCode
+} {1 {can't read output from command: standard output was redirected} NONE}
+test open-13.3 {I/O to command pipelines} {
+ list [catch {open "| echo > test3" r+} msg] $msg $errorCode
+} {1 {can't read output from command: standard output was redirected} NONE}
+test open-13.4 {writing to command pipelines} {
+ exec rm test3
+ set f [open "| cat | cat > test3" w]
+ puts $f "Line 1"
+ puts $f "Line 2"
+ close $f
+ exec cat test3
+} {Line 1
+Line 2}
+test open-13.5 {reading from command pipelines} {
+ set f [open "| cat test2" r]
+ set x [list [gets $f] [gets $f] [gets $f]]
+ close $f
+ set x
+} {line1 line2 line3}
+test open-13.6 {both reading and writing from/to command pipelines} {
+ set f [open "| cat -u" r+]
+ puts $f "Line1"
+ flush $f
+ set x [gets $f]
+ close $f
+ set x
+} {Line1}
+test open-13.7 {errors in command pipelines} {
+ set f [open "|gorp"]
+ list [catch {close $f} msg] $msg [lindex $errorCode 0] [lindex $errorCode 2]
+} {1 {couldn't find "gorp" to execute} CHILDSTATUS 1}
+test open-13.8 {errors in command pipelines} {
+ set f [open "|gorp" w]
+ exec sleep 1
+ puts $f output
+ set x [list [catch {flush $f} msg] [concat \
+ [string range $msg 0 [string first {"} $msg]] \
+ [string range $msg [string first : $msg] end]] $errorCode]
+ catch {close $f}
+ string tolower $x
+} {1 {error flushing " : broken pipe} {posix epipe {broken pipe}}}
+test open-13.9 {errors in command pipelines} {
+ set f [open "|gorp" w]
+ list [catch {close $f} msg] $msg \
+ [lindex $errorCode 0] [lindex $errorCode 2]
+} {1 {couldn't find "gorp" to execute} CHILDSTATUS 1}
+test open-13.10 {errors in command pipelines} {
+ set f [open "|gorp" w]
+ exec sleep 1
+ puts $f output
+ string tolower [list [catch {close $f} msg] [concat \
+ [string range $msg 0 [string first {"} $msg]] \
+ [string range $msg [string first : $msg] end]] \
+ [lindex $errorCode 0] [lindex $errorCode 2]]
+} {1 {error closing " : broken pipe
+couldn't find "gorp" to execute} childstatus 1}
+
+test open-14.1 {POSIX open access modes: RDONLY} {
+ set f [open test1 RDONLY]
+ set x [list [gets $f] [catch {puts $f Test} msg] $msg]
+ close $f
+
+ # The regsub is needed to avoid false errors if the file
+ # number varies from system to system.
+
+ regsub {"file."} $x {"file"} x
+ set x
+} {{Two lines: this one} 1 {"file" wasn't opened for writing}}
+test open-14.2 {POSIX open access modes: RDONLY} {
+ catch {exec rm -f test3}
+ string tolower [list [catch {open test3 RDONLY} msg] $msg]
+} {1 {couldn't open "test3": no such file or directory}}
+test open-14.3 {POSIX open access modes: WRONLY} {
+ catch {exec rm -f test3}
+ string tolower [list [catch {open test3 WRONLY} msg] $msg]
+} {1 {couldn't open "test3": no such file or directory}}
+test open-14.4 {POSIX open access modes: WRONLY} {
+ exec echo xyzzy > test3
+ set f [open test3 WRONLY]
+ puts -nonewline $f "ab"
+ seek $f 0 current
+ set x [list [catch {gets $f} msg] $msg]
+ close $f
+ lappend x [exec cat test3]
+
+ # The regsub is needed to avoid false errors if the file
+ # number varies from system to system.
+
+ regsub {"file."} $x {"file"} x
+ set x
+} {1 {"file" wasn't opened for reading} abzzy}
+test open-14.5 {POSIX open access modes: RDWR} {
+ catch {exec rm -f test3}
+ string tolower [list [catch {open test3 RDWR} msg] $msg]
+} {1 {couldn't open "test3": no such file or directory}}
+test open-14.6 {POSIX open access modes: RDWR} {
+ exec echo xyzzy > test3
+ set f [open test3 RDWR]
+ puts -nonewline $f "ab"
+ seek $f 0 current
+ set x [gets $f]
+ close $f
+ lappend x [exec cat test3]
+} {zzy abzzy}
+test open-14.7 {POSIX open access modes: CREAT} {
+ catch {exec rm -f test3}
+ set f [open test3 {WRONLY CREAT} 0600]
+ file stat test3 stats
+ set x [format "0%o" [expr $stats(mode)&0777]]
+ puts $f "line 1"
+ close $f
+ lappend x [exec cat test3]
+} {0600 {line 1}}
+if $atBerkeley {
+ test open-14.8 {POSIX open access modes: CREAT} {
+ catch {exec rm -f test3}
+ set f [open test3 {WRONLY CREAT}]
+ close $f
+ file stat test3 stats
+ format "0%o" [expr $stats(mode)&0777]
+ } 0664
+}
+test open-14.9 {POSIX open access modes: CREAT} {
+ exec echo xyzzy > test3
+ set f [open test3 {WRONLY CREAT}]
+ puts -nonewline $f "ab"
+ close $f
+ exec cat test3
+} abzzy
+test open-14.10 {POSIX open access modes: APPEND} {
+ exec echo xyzzy > test3
+ set f [open test3 {WRONLY APPEND}]
+ puts $f "new line"
+ seek $f 0
+ puts $f "abc"
+ close $f
+ exec cat test3
+} {xyzzy
+new line
+abc}
+test open-14.11 {POSIX open access modes: EXCL} {
+ exec echo xyzzy > test3
+ set msg [list [catch {open test3 {WRONLY CREAT EXCL}} msg] $msg]
+ regsub " already " $msg " " msg
+ string tolower $msg
+} {1 {couldn't open "test3": file exists}}
+test open-14.12 {POSIX open access modes: EXCL} {
+ catch {exec rm -f test3}
+ set x [catch {set f [open test3 {WRONLY CREAT EXCL}]}]
+ puts $f "A test line"
+ close $f
+ lappend x [exec cat test3]
+} {0 {A test line}}
+test open-14.13 {POSIX open access modes: TRUNC} {
+ exec echo xyzzy > test3
+ set f [open test3 {WRONLY TRUNC}]
+ puts $f abc
+ close $f
+ exec cat test3
+} {abc}
+if $atBerkeley {
+ test open-14.14 {POSIX open access modes: NOCTTY} {
+ catch {exec rm -f test3}
+ list [catch {open test3 {WRONLY NOCTTY CREAT}} msg] $msg
+ } {1 {access mode "NOCTTY" not supported by this system}}
+ test open-14.15 {POSIX open access modes: NONBLOCK} {
+ catch {exec rm -f test3}
+ set f [open test3 {WRONLY NONBLOCK CREAT}]
+ puts $f "NONBLOCK test"
+ close $f
+ exec cat test3
+ } {NONBLOCK test}
+}
+test open-14.16 {POSIX open access modes: errors} {
+ concat [catch {open test3 "FOO \{BAR BAZ"} msg] $msg\n$errorInfo
+} "1 unmatched open brace in list
+unmatched open brace in list
+ while processing open access modes \"FOO {BAR BAZ\"
+ invoked from within
+\"open test3 \"FOO \\{BAR BAZ\"\""
+test open-14.17 {POSIX open access modes: errors} {
+ list [catch {open test3 {FOO BAR BAZ}} msg] $msg
+} {1 {invalid access mode "FOO": must be RDONLY, WRONLY, RDWR, APPEND, CREAT EXCL, NOCTTY, NONBLOCK, or TRUNC}}
+test open-14.18 {POSIX open access modes: errors} {
+ list [catch {open test3 {TRUNC CREAT}} msg] $msg
+} {1 {access mode must include either RDONLY, WRONLY, or RDWR}}
+
+catch {exec rm -f test1 test2 test3}
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/parse.test b/vendor/x11iraf/obm/Tcl/tests/parse.test
new file mode 100644
index 00000000..fde51011
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/parse.test
@@ -0,0 +1,429 @@
+# Commands covered: set (plus basic command syntax)
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/parse.test,v 1.24 93/07/28 13:07:14 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc fourArgs {a b c d} {
+ global arg1 arg2 arg3 arg4
+ set arg1 $a
+ set arg2 $b
+ set arg3 $c
+ set arg4 $d
+}
+
+proc getArgs args {
+ global argv
+ set argv $args
+}
+
+# Basic argument parsing.
+
+test parse-1.1 {basic argument parsing} {
+ set arg1 {}
+ fourArgs a b c d
+ list $arg1 $arg2 $arg3 $arg4
+} {a b c d}
+test parse-1.2 {basic argument parsing} {
+ set arg1 {}
+ eval "fourArgs 123\v4\f56\r7890"
+ list $arg1 $arg2 $arg3 $arg4
+} {123 4 56 7890}
+
+# Quotes.
+
+test parse-2.1 {quotes and variable-substitution} {
+ getArgs "a b c" d
+ set argv
+} {{a b c} d}
+test parse-2.2 {quotes and variable-substitution} {
+ set a 101
+ getArgs "a$a b c"
+ set argv
+} {{a101 b c}}
+test parse-2.3 {quotes and variable-substitution} {
+ set argv "xy[format xabc]"
+ set argv
+} {xyxabc}
+test parse-2.4 {quotes and variable-substitution} {
+ set argv "xy\t"
+ set argv
+} xy\t
+test parse-2.5 {quotes and variable-substitution} {
+ set argv "a b c
+d e f"
+ set argv
+} a\ b\tc\nd\ e\ f
+test parse-2.6 {quotes and variable-substitution} {
+ set argv a"bcd"e
+ set argv
+} {a"bcd"e}
+
+# Braces.
+
+test parse-3.1 {braces} {
+ getArgs {a b c} d
+ set argv
+} "{a b c} d"
+test parse-3.2 {braces} {
+ set a 101
+ set argv {a$a b c}
+ set b [string index $argv 1]
+ set b
+} {$}
+test parse-3.3 {braces} {
+ set argv {a[format xyz] b}
+ string length $argv
+} 15
+test parse-3.4 {braces} {
+ set argv {a\nb\}}
+ string length $argv
+} 6
+test parse-3.5 {braces} {
+ set argv {{{{}}}}
+ set argv
+} "{{{}}}"
+test parse-3.6 {braces} {
+ set argv a{{}}b
+ set argv
+} "a{{}}b"
+test parse-3.7 {braces} {
+ set a [format "last]"]
+ set a
+} {last]}
+
+# Command substitution.
+
+test parse-4.1 {command substitution} {
+ set a [format xyz]
+ set a
+} xyz
+test parse-4.2 {command substitution} {
+ set a a[format xyz]b[format q]
+ set a
+} axyzbq
+test parse-4.3 {command substitution} {
+ set a a[
+set b 22;
+format %s $b
+
+]b
+ set a
+} a22b
+
+# Variable substitution.
+
+test parse-5.1 {variable substitution} {
+ set a 123
+ set b $a
+ set b
+} 123
+test parse-5.2 {variable substitution} {
+ set a 345
+ set b x$a.b
+ set b
+} x345.b
+test parse-5.3 {variable substitution} {
+ set _123z xx
+ set b $_123z^
+ set b
+} xx^
+test parse-5.4 {variable substitution} {
+ set a 78
+ set b a${a}b
+ set b
+} a78b
+test parse-5.5 {variable substitution} {catch {$_non_existent_} msg} 1
+test parse-5.6 {variable substitution} {
+ catch {$_non_existent_} msg
+ set msg
+} {can't read "_non_existent_": no such variable}
+test parse-5.7 {array variable substitution} {
+ catch {unset a}
+ set a(xyz) 123
+ set b $a(xyz)foo
+ set b
+} 123foo
+test parse-5.8 {array variable substitution} {
+ catch {unset a}
+ set "a(x y z)" 123
+ set b $a(x y z)foo
+ set b
+} 123foo
+test parse-5.9 {array variable substitution} {
+ catch {unset a}; catch {unset qqq}
+ set "a(x y z)" qqq
+ set $a([format x]\ y [format z]) foo
+ set qqq
+} foo
+test parse-5.10 {array variable substitution} {
+ catch {unset a}
+ list [catch {set b $a(22)} msg] $msg
+} {1 {can't read "a(22)": no such variable}}
+test parse-5.11 {array variable substitution} {
+ set b a$!
+ set b
+} {a$!}
+test parse-5.12 {array variable substitution} {
+ set b a$()
+ set b
+} {a$()}
+catch {unset a}
+test parse-5.13 {array variable substitution} {
+ catch {unset a}
+ set long {This is a very long variable, long enough to cause storage \
+ allocation to occur in Tcl_ParseVar. If that storage isn't getting \
+ freed up correctly, then a core leak will occur when this test is \
+ run. This text is probably beginning to sound like drivel, but I've \
+ run out of things to say and I need more characters still.}
+ set a($long) 777
+ set b $a($long)
+ list $b [array names a]
+} {777 {{This is a very long variable, long enough to cause storage \
+ allocation to occur in Tcl_ParseVar. If that storage isn't getting \
+ freed up correctly, then a core leak will occur when this test is \
+ run. This text is probably beginning to sound like drivel, but I've \
+ run out of things to say and I need more characters still.}}}
+test parse-5.14 {array variable substitution} {
+ catch {unset a}; catch {unset b}; catch {unset a1}
+ set a1(22) foo
+ set a(foo) bar
+ set b $a($a1(22))
+ set b
+} bar
+catch {unset a}; catch {unset a1}
+
+# Backslash substitution.
+
+set errNum 1
+proc bsCheck {char num} {
+ global errNum
+ test parse-6.$errNum {backslash substitution} {
+ scan $char %c value
+ set value
+ } $num
+ set errNum [expr $errNum+1]
+}
+
+bsCheck \b 8
+bsCheck \e 101
+bsCheck \f 12
+bsCheck \n 10
+bsCheck \r 13
+bsCheck \t 9
+bsCheck \v 11
+bsCheck \{ 123
+bsCheck \} 125
+bsCheck \[ 91
+bsCheck \] 93
+bsCheck \$ 36
+bsCheck \ 32
+bsCheck \; 59
+bsCheck \\ 92
+bsCheck \Ca 67
+bsCheck \Ma 77
+bsCheck \CMa 67
+bsCheck \8a 8
+bsCheck \14 12
+bsCheck \141 97
+bsCheck \340 224
+bsCheck b\0 98
+bsCheck \x 120
+bsCheck \xa 10
+bsCheck \x41 65
+bsCheck \x541 65
+
+test parse-7.1 {backslash substitution} {
+ set a "\a\c\n\]\}"
+ string length $a
+} 5
+test parse-7.2 {backslash substitution} {
+ set a {\a\c\n\]\}}
+ string length $a
+} 10
+test parse-7.3 {backslash substitution} {
+ set a "abc\
+def"
+ set a
+} {abc def}
+test parse-7.4 {backslash substitution} {
+ set a {abc\
+def}
+ set a
+} {abc def}
+test parse-7.5 {backslash substitution} {
+ set msg {}
+ set a xxx
+ set error [catch {if {24 < \
+ 35} {set a 22} {set \
+ a 33}} msg]
+ list $error $msg $a
+} {0 22 22}
+test parse-7.6 {backslash substitution} {
+ eval "concat abc\\"
+} "abc\\"
+test parse-7.7 {backslash substitution} {
+ eval "concat \\\na"
+} "a"
+test parse-7.8 {backslash substitution} {
+ eval "concat x\\\n \na"
+} "x a"
+test parse-7.9 {backslash substitution} {
+ eval "concat \\x"
+} "x"
+test parse-7.10 {backslash substitution} {
+ eval "list a b\\\nc d"
+} {a b c d}
+
+# Semi-colon.
+
+test parse-8.1 {semi-colons} {
+ set b 0
+ getArgs a;set b 2
+ set argv
+} a
+test parse-8.2 {semi-colons} {
+ set b 0
+ getArgs a;set b 2
+ set b
+} 2
+test parse-8.3 {semi-colons} {
+ getArgs a b ; set b 1
+ set argv
+} {a b}
+test parse-8.4 {semi-colons} {
+ getArgs a b ; set b 1
+ set b
+} 1
+
+# The following checks are to ensure that the interpreter's result
+# gets re-initialized by Tcl_Eval in all the right places.
+
+test parse-9.1 {result initialization} {concat abc} abc
+test parse-9.2 {result initialization} {concat abc; proc foo {} {}} {}
+test parse-9.3 {result initialization} {concat abc; proc foo {} $a} {}
+test parse-9.4 {result initialization} {proc foo {} [concat abc]} {}
+test parse-9.5 {result initialization} {concat abc; } abc
+test parse-9.6 {result initialization} {
+ eval {
+ concat abc
+}} abc
+test parse-9.7 {result initialization} {} {}
+test parse-9.8 {result initialization} {concat abc; ; ;} abc
+
+# Syntax errors.
+
+test parse-10.1 {syntax errors} {catch "set a \{bcd" msg} 1
+test parse-10.2 {syntax errors} {
+ catch "set a \{bcd" msg
+ set msg
+} {missing close-brace}
+test parse-10.3 {syntax errors} {catch {set a "bcd} msg} 1
+test parse-10.4 {syntax errors} {
+ catch {set a "bcd} msg
+ set msg
+} {missing "}
+test parse-10.5 {syntax errors} {catch {set a "bcd"xy} msg} 1
+test parse-10.6 {syntax errors} {
+ catch {set a "bcd"xy} msg
+ set msg
+} {extra characters after close-quote}
+test parse-10.7 {syntax errors} {catch "set a {bcd}xy" msg} 1
+test parse-10.8 {syntax errors} {
+ catch "set a {bcd}xy" msg
+ set msg
+} {extra characters after close-brace}
+test parse-10.9 {syntax errors} {catch {set a [format abc} msg} 1
+test parse-10.10 {syntax errors} {
+ catch {set a [format abc} msg
+ set msg
+} {missing close-bracket}
+test parse-10.11 {syntax errors} {catch gorp-a-lot msg} 1
+test parse-10.12 {syntax errors} {
+ catch gorp-a-lot msg
+ set msg
+} {invalid command name: "gorp-a-lot"}
+test parse-10.13 {syntax errors} {
+ set a [concat {a}\
+ {b}]
+ set a
+} {a b}
+test parse-10.14 {syntax errors} {catch "concat \{a\}\\\n{b}" msg} 1
+test parse-10.15 {syntax errors} {
+ catch "concat \{a\}\\\n{b}" msg
+ set msg
+} {extra characters after close-brace}
+
+# Long values (stressing storage management)
+
+set a {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH}
+
+test parse-11.1 {long values} {
+ string length $a
+} 214
+test parse-11.2 {long values} {
+ llength $a
+} 43
+test parse-1a1.3 {long values} {
+ set b "1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH"
+ set b
+} $a
+test parse-11.4 {long values} {
+ set b "$a"
+ set b
+} $a
+test parse-11.5 {long values} {
+ set b [set a]
+ set b
+} $a
+test parse-11.6 {long values} {
+ set b [concat 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH]
+ string length $b
+} 214
+test parse-11.7 {long values} {
+ set b [concat 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH]
+ llength $b
+} 43
+test parse-11.8 {long values} {
+ set b
+} $a
+test parse-11.9 {long values} {
+ set a [concat 0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN OOOO PPPP QQQQ RRRR SSSS TTTT UUUU VVVV WWWW XXXX YYYY ZZZZ]
+ llength $a
+} 62
+set i 0
+foreach j [concat 0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN OOOO PPPP QQQQ RRRR SSSS TTTT UUUU VVVV WWWW XXXX YYYY ZZZZ] {
+ set test [string index 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ $i]
+ set test $test$test$test$test
+ set i [expr $i+1]
+ test parse-11.10 {long values} {
+ set j
+ } $test
+}
+test parse-11.10 {test buffer overflow in backslashes in braces} {
+ expr {"a" == {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101}}
+} 0
diff --git a/vendor/x11iraf/obm/Tcl/tests/pid.test b/vendor/x11iraf/obm/Tcl/tests/pid.test
new file mode 100644
index 00000000..b6023870
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/pid.test
@@ -0,0 +1,58 @@
+# Commands covered: pid
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/pid.test,v 1.1 93/05/15 16:06:39 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {exec rm -f test1}
+
+test open-1.1 {pid command} {
+ regexp {^[0-9]+$} [pid]
+} 1
+test open-1.2 {pid command} {
+ set f [open {| echo foo | cat > /dev/null} w]
+ set pids [pid $f]
+ close $f
+ list [llength $pids] [regexp {^[0-9]+$} [lindex $pids 0]] \
+ [regexp {^[0-9]+$} [lindex $pids 1]] \
+ [expr {[lindex $pids 0] == [lindex $pids 1]}]
+} {2 1 1 0}
+test open-1.3 {pid command} {
+ set f [open test1 w]
+ set pids [pid $f]
+ close $f
+ set pids
+} {}
+test open-1.4 {pid command} {
+ list [catch {pid a b} msg] $msg
+} {1 {wrong # args: should be "pid ?fileId?"}}
+test open-1.5 {pid command} {
+ list [catch {pid gorp} msg] $msg
+} {1 {bad file identifier "gorp"}}
+
+catch {exec rm -f test1}
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/proc.test b/vendor/x11iraf/obm/Tcl/tests/proc.test
new file mode 100644
index 00000000..f321b761
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/proc.test
@@ -0,0 +1,450 @@
+# Commands covered: proc, return, global
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/proc.test,v 1.15 93/08/03 16:10:28 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc tproc {} {return a; return b}
+test proc-1.1 {simple procedure call and return} {tproc} a
+proc tproc x {
+ set x [expr $x+1]
+ return $x
+}
+test proc-1.2 {simple procedure call and return} {tproc 2} 3
+test proc-1.3 {simple procedure call and return} {
+ proc tproc {} {return foo}
+} {}
+test proc-1.4 {simple procedure call and return} {
+ proc tproc {} {return}
+ tproc
+} {}
+
+test proc-2.1 {local and global variables} {
+ proc tproc x {
+ set x [expr $x+1]
+ return $x
+ }
+ set x 42
+ list [tproc 6] $x
+} {7 42}
+test proc-2.2 {local and global variables} {
+ proc tproc x {
+ set y [expr $x+1]
+ return $y
+ }
+ set y 18
+ list [tproc 6] $y
+} {7 18}
+test proc-2.3 {local and global variables} {
+ proc tproc x {
+ global y
+ set y [expr $x+1]
+ return $y
+ }
+ set y 189
+ list [tproc 6] $y
+} {7 7}
+test proc-2.4 {local and global variables} {
+ proc tproc x {
+ global y
+ return [expr $x+$y]
+ }
+ set y 189
+ list [tproc 6] $y
+} {195 189}
+catch {unset _undefined_}
+test proc-2.5 {local and global variables} {
+ proc tproc x {
+ global _undefined_
+ return $_undefined_
+ }
+ list [catch {tproc xxx} msg] $msg
+} {1 {can't read "_undefined_": no such variable}}
+test proc-2.6 {local and global variables} {
+ set a 114
+ set b 115
+ global a b
+ list $a $b
+} {114 115}
+
+proc do {cmd} {eval $cmd}
+test proc-3.1 {local and global arrays} {
+ catch {unset a}
+ set a(0) 22
+ list [catch {do {global a; set a(0)}} msg] $msg
+} {0 22}
+test proc-3.2 {local and global arrays} {
+ catch {unset a}
+ set a(x) 22
+ list [catch {do {global a; set a(x) newValue}} msg] $msg $a(x)
+} {0 newValue newValue}
+test proc-3.3 {local and global arrays} {
+ catch {unset a}
+ set a(x) 22
+ set a(y) 33
+ list [catch {do {global a; unset a(y)}; array names a} msg] $msg
+} {0 x}
+test proc-3.4 {local and global arrays} {
+ catch {unset a}
+ set a(x) 22
+ set a(y) 33
+ list [catch {do {global a; unset a; info exists a}} msg] $msg \
+ [info exists a]
+} {0 0 0}
+test proc-3.5 {local and global arrays} {
+ catch {unset a}
+ set a(x) 22
+ set a(y) 33
+ list [catch {do {global a; unset a(y); array names a}} msg] $msg
+} {0 x}
+catch {unset a}
+test proc-3.6 {local and global arrays} {
+ catch {unset a}
+ set a(x) 22
+ set a(y) 33
+ do {global a; do {global a; unset a}; set a(z) 22}
+ list [catch {array names a} msg] $msg
+} {0 z}
+test proc-3.7 {local and global arrays} {
+ proc t1 {args} {global info; set info 1}
+ catch {unset a}
+ set info {}
+ do {global a; trace var a(1) w t1}
+ set a(1) 44
+ set info
+} 1
+test proc-3.8 {local and global arrays} {
+ proc t1 {args} {global info; set info 1}
+ catch {unset a}
+ trace var a(1) w t1
+ set info {}
+ do {global a; trace vdelete a(1) w t1}
+ set a(1) 44
+ set info
+} {}
+test proc-3.9 {local and global arrays} {
+ proc t1 {args} {global info; set info 1}
+ catch {unset a}
+ trace var a(1) w t1
+ do {global a; trace vinfo a(1)}
+} {{w t1}}
+catch {unset a}
+
+test proc-3.1 {arguments and defaults} {
+ proc tproc {x y z} {
+ return [list $x $y $z]
+ }
+ tproc 11 12 13
+} {11 12 13}
+test proc-3.2 {arguments and defaults} {
+ proc tproc {x y z} {
+ return [list $x $y $z]
+ }
+ list [catch {tproc 11 12} msg] $msg
+} {1 {no value given for parameter "z" to "tproc"}}
+test proc-3.3 {arguments and defaults} {
+ proc tproc {x y z} {
+ return [list $x $y $z]
+ }
+ list [catch {tproc 11 12 13 14} msg] $msg
+} {1 {called "tproc" with too many arguments}}
+test proc-3.4 {arguments and defaults} {
+ proc tproc {x {y y-default} {z z-default}} {
+ return [list $x $y $z]
+ }
+ tproc 11 12 13
+} {11 12 13}
+test proc-3.5 {arguments and defaults} {
+ proc tproc {x {y y-default} {z z-default}} {
+ return [list $x $y $z]
+ }
+ tproc 11 12
+} {11 12 z-default}
+test proc-3.6 {arguments and defaults} {
+ proc tproc {x {y y-default} {z z-default}} {
+ return [list $x $y $z]
+ }
+ tproc 11
+} {11 y-default z-default}
+test proc-3.7 {arguments and defaults} {
+ proc tproc {x {y y-default} {z z-default}} {
+ return [list $x $y $z]
+ }
+ list [catch {tproc} msg] $msg
+} {1 {no value given for parameter "x" to "tproc"}}
+test proc-3.8 {arguments and defaults} {
+ list [catch {
+ proc tproc {x {y y-default} z} {
+ return [list $x $y $z]
+ }
+ tproc 2 3
+ } msg] $msg
+} {1 {no value given for parameter "z" to "tproc"}}
+test proc-3.9 {arguments and defaults} {
+ proc tproc {x {y y-default} args} {
+ return [list $x $y $args]
+ }
+ tproc 2 3 4 5
+} {2 3 {4 5}}
+test proc-3.10 {arguments and defaults} {
+ proc tproc {x {y y-default} args} {
+ return [list $x $y $args]
+ }
+ tproc 2 3
+} {2 3 {}}
+test proc-3.11 {arguments and defaults} {
+ proc tproc {x {y y-default} args} {
+ return [list $x $y $args]
+ }
+ tproc 2
+} {2 y-default {}}
+test proc-3.12 {arguments and defaults} {
+ proc tproc {x {y y-default} args} {
+ return [list $x $y $args]
+ }
+ list [catch {tproc} msg] $msg
+} {1 {no value given for parameter "x" to "tproc"}}
+
+test proc-4.1 {variable numbers of arguments} {
+ proc tproc args {return $args}
+ tproc
+} {}
+test proc-4.2 {variable numbers of arguments} {
+ proc tproc args {return $args}
+ tproc 1 2 3 4 5 6 7 8
+} {1 2 3 4 5 6 7 8}
+test proc-4.3 {variable numbers of arguments} {
+ proc tproc args {return $args}
+ tproc 1 {2 3} {4 {5 6} {{{7}}}} 8
+} {1 {2 3} {4 {5 6} {{{7}}}} 8}
+test proc-4.4 {variable numbers of arguments} {
+ proc tproc {x y args} {return $args}
+ tproc 1 2 3 4 5 6 7
+} {3 4 5 6 7}
+test proc-4.5 {variable numbers of arguments} {
+ proc tproc {x y args} {return $args}
+ tproc 1 2
+} {}
+test proc-4.6 {variable numbers of arguments} {
+ proc tproc {x missing args} {return $args}
+ list [catch {tproc 1} msg] $msg
+} {1 {no value given for parameter "missing" to "tproc"}}
+
+test proc-5.1 {error conditions} {
+ list [catch {proc} msg] $msg
+} {1 {wrong # args: should be "proc name args body"}}
+test proc-5.2 {error conditions} {
+ list [catch {proc tproc b} msg] $msg
+} {1 {wrong # args: should be "proc name args body"}}
+test proc-5.3 {error conditions} {
+ list [catch {proc tproc b c d e} msg] $msg
+} {1 {wrong # args: should be "proc name args body"}}
+test proc-5.4 {error conditions} {
+ list [catch {proc tproc \{xyz {return foo}} msg] $msg
+} {1 {unmatched open brace in list}}
+test proc-5.5 {error conditions} {
+ list [catch {proc tproc {{} y} {return foo}} msg] $msg
+} {1 {procedure "tproc" has argument with no name}}
+test proc-5.6 {error conditions} {
+ list [catch {proc tproc {{} y} {return foo}} msg] $msg
+} {1 {procedure "tproc" has argument with no name}}
+test proc-5.7 {error conditions} {
+ list [catch {proc tproc {{x 1 2} y} {return foo}} msg] $msg
+} {1 {too many fields in argument specifier "x 1 2"}}
+test proc-5.8 {error conditions} {
+ catch {return}
+} 2
+test proc-5.9 {error conditions} {
+ list [catch {global} msg] $msg
+} {1 {wrong # args: should be "global varName ?varName ...?"}}
+proc tproc {} {
+ set a 22
+ global a
+}
+test proc-5.10 {error conditions} {
+ list [catch {tproc} msg] $msg
+} {1 {variable "a" already exists}}
+test proc-5.11 {error conditions} {
+ catch {rename tproc {}}
+ catch {
+ proc tproc {x {} z} {return foo}
+ }
+ list [catch {tproc 1} msg] $msg
+} {1 {invalid command name: "tproc"}}
+test proc-5.12 {error conditions} {
+ proc tproc {} {
+ set a 22
+ error "error in procedure"
+ return
+ }
+ list [catch tproc msg] $msg
+} {1 {error in procedure}}
+test proc-5.13 {error conditions} {
+ proc tproc {} {
+ set a 22
+ error "error in procedure"
+ return
+ }
+ catch tproc msg
+ set errorInfo
+} {error in procedure
+ while executing
+"error "error in procedure""
+ (procedure "tproc" line 3)
+ invoked from within
+"tproc"}
+test proc-5.14 {error conditions} {
+ proc tproc {} {
+ set a 22
+ break
+ return
+ }
+ catch tproc msg
+ set errorInfo
+} {invoked "break" outside of a loop
+ while executing
+"tproc"}
+test proc-5.15 {error conditions} {
+ proc tproc {} {
+ set a 22
+ continue
+ return
+ }
+ catch tproc msg
+ set errorInfo
+} {invoked "continue" outside of a loop
+ while executing
+"tproc"}
+
+# The tests below will really only be useful when run under Purify or
+# some other system that can detect accesses to freed memory...
+
+test proc-6.1 {procedure that redefines itself} {
+ proc tproc {} {
+ proc tproc {} {
+ return 44
+ }
+ return 45
+ }
+ tproc
+} 45
+test proc-6.2 {procedure that deletes itself} {
+ proc tproc {} {
+ rename tproc {}
+ return 45
+ }
+ tproc
+} 45
+
+proc tproc code {
+ return -code $code abc
+}
+test proc-7.1 {return with special completion code} {
+ list [catch {tproc ok} msg] $msg
+} {0 abc}
+test proc-7.2 {return with special completion code} {
+ list [catch {tproc error} msg] $msg $errorInfo $errorCode
+} {1 abc {abc
+ while executing
+"tproc error"} NONE}
+test proc-7.3 {return with special completion code} {
+ list [catch {tproc return} msg] $msg
+} {2 abc}
+test proc-7.4 {return with special completion code} {
+ list [catch {tproc break} msg] $msg
+} {3 abc}
+test proc-7.5 {return with special completion code} {
+ list [catch {tproc continue} msg] $msg
+} {4 abc}
+test proc-7.6 {return with special completion code} {
+ list [catch {tproc -14} msg] $msg
+} {-14 abc}
+test proc-7.7 {return with special completion code} {
+ list [catch {tproc gorp} msg] $msg
+} {1 {bad completion code "gorp": must be ok, error, return, break, continue, or an integer}}
+test proc-7.8 {return with special completion code} {
+ list [catch {tproc 10b} msg] $msg
+} {1 {bad completion code "10b": must be ok, error, return, break, continue, or an integer}}
+test proc-7.9 {return with special completion code} {
+ proc tproc2 {} {
+ tproc return
+ }
+ list [catch tproc2 msg] $msg
+} {0 abc}
+test proc-7.10 {return with special completion code} {
+ proc tproc2 {} {
+ return -code error
+ }
+ list [catch tproc2 msg] $msg
+} {1 {}}
+test proc-7.11 {return with special completion code} {
+ proc tproc2 {} {
+ global errorCode errorInfo
+ catch {open _bad_file_name r} msg
+ return -code error -errorinfo $errorInfo -errorcode $errorCode $msg
+ }
+ string tolower [list [catch tproc2 msg] $msg $errorInfo $errorCode]
+} {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory
+ while executing
+"open _bad_file_name r"
+ invoked from within
+"tproc2"} {posix enoent {no such file or directory}}}
+test proc-7.12 {return with special completion code} {
+ proc tproc2 {} {
+ global errorCode errorInfo
+ catch {open _bad_file_name r} msg
+ return -code error -errorcode $errorCode $msg
+ }
+ string tolower [list [catch tproc2 msg] $msg $errorInfo $errorCode]
+} {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory
+ while executing
+"tproc2"} {posix enoent {no such file or directory}}}
+test proc-7.13 {return with special completion code} {
+ proc tproc2 {} {
+ global errorCode errorInfo
+ catch {open _bad_file_name r} msg
+ return -code error -errorinfo $errorInfo $msg
+ }
+ string tolower [list [catch tproc2 msg] $msg $errorInfo $errorCode]
+} {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory
+ while executing
+"open _bad_file_name r"
+ invoked from within
+"tproc2"} none}
+test proc-7.14 {return with special completion code} {
+ proc tproc2 {} {
+ global errorCode errorInfo
+ catch {open _bad_file_name r} msg
+ return -code error $msg
+ }
+ string tolower [list [catch tproc2 msg] $msg $errorInfo $errorCode]
+} {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory
+ while executing
+"tproc2"} none}
+test proc-7.14 {return with special completion code} {
+ list [catch {return -badOption foo message} msg] $msg
+} {1 {bad option "-badOption: must be -code, -errorcode, or -errorinfo}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/regexp.test b/vendor/x11iraf/obm/Tcl/tests/regexp.test
new file mode 100644
index 00000000..5f0bc7ce
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/regexp.test
@@ -0,0 +1,324 @@
+# Commands covered: regexp, regsub
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/regexp.test,v 1.13 93/10/14 14:53:21 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {unset foo}
+test regexp-1.1 {basic regexp operation} {
+ regexp ab*c abbbc
+} 1
+test regexp-1.2 {basic regexp operation} {
+ regexp ab*c ac
+} 1
+test regexp-1.3 {basic regexp operation} {
+ regexp ab*c ab
+} 0
+test regexp-1.4 {basic regexp operation} {
+ regexp -- -gorp abc-gorpxxx
+} 1
+
+test regexp-2.1 {getting substrings back from regexp} {
+ set foo {}
+ list [regexp ab*c abbbbc foo] $foo
+} {1 abbbbc}
+test regexp-2.2 {getting substrings back from regexp} {
+ set foo {}
+ set f2 {}
+ list [regexp a(b*)c abbbbc foo f2] $foo $f2
+} {1 abbbbc bbbb}
+test regexp-2.3 {getting substrings back from regexp} {
+ set foo {}
+ set f2 {}
+ list [regexp a(b*)(c) abbbbc foo f2] $foo $f2
+} {1 abbbbc bbbb}
+test regexp-2.4 {getting substrings back from regexp} {
+ set foo {}
+ set f2 {}
+ set f3 {}
+ list [regexp a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3
+} {1 abbbbc bbbb c}
+test regexp-2.5 {getting substrings back from regexp} {
+ set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {};
+ set f6 {}; set f7 {}; set f8 {}; set f9 {}
+ list [regexp (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) 12223345556789999 \
+ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \
+ $f6 $f7 $f8 $f9
+} {1 12223345556789999 1 222 33 4 555 6 7 8 9999}
+test regexp-2.6 {getting substrings back from regexp} {
+ set foo 2; set f2 2; set f3 2; set f4 2
+ list [regexp (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4
+} {1 a a {} {}}
+test regexp-2.7 {getting substrings back from regexp} {
+ set foo 1; set f2 1; set f3 1; set f4 1
+ list [regexp (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4
+} {1 ac a {} c}
+
+test regexp-3.1 {-indices option to regexp} {
+ set foo {}
+ list [regexp -indices ab*c abbbbc foo] $foo
+} {1 {0 5}}
+test regexp-3.2 {-indices option to regexp} {
+ set foo {}
+ set f2 {}
+ list [regexp -indices a(b*)c abbbbc foo f2] $foo $f2
+} {1 {0 5} {1 4}}
+test regexp-3.3 {-indices option to regexp} {
+ set foo {}
+ set f2 {}
+ list [regexp -indices a(b*)(c) abbbbc foo f2] $foo $f2
+} {1 {0 5} {1 4}}
+test regexp-3.4 {-indices option to regexp} {
+ set foo {}
+ set f2 {}
+ set f3 {}
+ list [regexp -indices a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3
+} {1 {0 5} {1 4} {5 5}}
+test regexp-3.5 {-indices option to regexp} {
+ set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {};
+ set f6 {}; set f7 {}; set f8 {}; set f9 {}
+ list [regexp -indices (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) \
+ 12223345556789999 \
+ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \
+ $f6 $f7 $f8 $f9
+} {1 {0 16} {0 0} {1 3} {4 5} {6 6} {7 9} {10 10} {11 11} {12 12} {13 16}}
+test regexp-3.6 {getting substrings back from regexp} {
+ set foo 2; set f2 2; set f3 2; set f4 2
+ list [regexp -indices (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4
+} {1 {1 1} {1 1} {-1 -1} {-1 -1}}
+test regexp-3.7 {getting substrings back from regexp} {
+ set foo 1; set f2 1; set f3 1; set f4 1
+ list [regexp -indices (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4
+} {1 {1 2} {1 1} {-1 -1} {2 2}}
+
+test regexp-4.1 {-nocase option to regexp} {
+ regexp -nocase foo abcFOo
+} 1
+test regexp-4.2 {-nocase option to regexp} {
+ set f1 22
+ set f2 33
+ set f3 44
+ list [regexp -nocase {a(b*)([xy]*)z} aBbbxYXxxZ22 f1 f2 f3] $f1 $f2 $f3
+} {1 aBbbxYXxxZ Bbb xYXxx}
+test regexp-4.3 {-nocase option to regexp} {
+ regexp -nocase FOo abcFOo
+} 1
+set x abcdefghijklmnopqrstuvwxyz1234567890
+set x $x$x$x$x$x$x$x$x$x$x$x$x
+test regexp-4.4 {case conversion in regsub} {
+ list [regexp -nocase $x $x foo] $foo
+} "1 $x"
+unset x
+
+test regexp-5.1 {exercise cache of compiled expressions} {
+ regexp .*a b
+ regexp .*b c
+ regexp .*c d
+ regexp .*d e
+ regexp .*e f
+ regexp .*a bbba
+} 1
+test regexp-5.2 {exercise cache of compiled expressions} {
+ regexp .*a b
+ regexp .*b c
+ regexp .*c d
+ regexp .*d e
+ regexp .*e f
+ regexp .*b xxxb
+} 1
+test regexp-5.3 {exercise cache of compiled expressions} {
+ regexp .*a b
+ regexp .*b c
+ regexp .*c d
+ regexp .*d e
+ regexp .*e f
+ regexp .*c yyyc
+} 1
+test regexp-5.4 {exercise cache of compiled expressions} {
+ regexp .*a b
+ regexp .*b c
+ regexp .*c d
+ regexp .*d e
+ regexp .*e f
+ regexp .*d 1d
+} 1
+test regexp-5.5 {exercise cache of compiled expressions} {
+ regexp .*a b
+ regexp .*b c
+ regexp .*c d
+ regexp .*d e
+ regexp .*e f
+ regexp .*e xe
+} 1
+
+test regexp-6.1 {regexp errors} {
+ list [catch {regexp a} msg] $msg
+} {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}}
+test regexp-6.2 {regexp errors} {
+ list [catch {regexp -nocase a} msg] $msg
+} {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}}
+test regexp-6.3 {regexp errors} {
+ list [catch {regexp -gorp a} msg] $msg
+} {1 {bad switch "-gorp": must be -indices, -nocase, or --}}
+test regexp-6.4 {regexp errors} {
+ list [catch {regexp a( b} msg] $msg
+} {1 {couldn't compile regular expression pattern: unmatched ()}}
+test regexp-6.5 {regexp errors} {
+ list [catch {regexp a( b} msg] $msg
+} {1 {couldn't compile regular expression pattern: unmatched ()}}
+test regexp-6.6 {regexp errors} {
+ list [catch {regexp a a f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1} msg] $msg
+} {1 {too many substring variables}}
+test regexp-6.7 {regexp errors} {
+ set f1 44
+ list [catch {regexp abc abc f1(f2)} msg] $msg
+} {1 {couldn't set variable "f1(f2)"}}
+
+test regexp-7.1 {basic regsub operation} {
+ list [regsub aa+ xaxaaaxaa 111&222 foo] $foo
+} {1 xax111aaa222xaa}
+test regexp-7.2 {basic regsub operation} {
+ list [regsub aa+ aaaxaa &111 foo] $foo
+} {1 aaa111xaa}
+test regexp-7.3 {basic regsub operation} {
+ list [regsub aa+ xaxaaa 111& foo] $foo
+} {1 xax111aaa}
+test regexp-7.4 {basic regsub operation} {
+ list [regsub aa+ aaa 11&2&333 foo] $foo
+} {1 11aaa2aaa333}
+test regexp-7.5 {basic regsub operation} {
+ list [regsub aa+ xaxaaaxaa &2&333 foo] $foo
+} {1 xaxaaa2aaa333xaa}
+test regexp-7.6 {basic regsub operation} {
+ list [regsub aa+ xaxaaaxaa 1&22& foo] $foo
+} {1 xax1aaa22aaaxaa}
+test regexp-7.7 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {1\122\1} foo] $foo
+} {1 xax1aa22aaxaa}
+test regexp-7.8 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {1\\\122\1} foo] $foo
+} "1 {xax1\\aa22aaxaa}"
+test regexp-7.9 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {1\\122\1} foo] $foo
+} "1 {xax1\\122aaxaa}"
+test regexp-7.10 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {1\\&\1} foo] $foo
+} "1 {xax1\\aaaaaxaa}"
+test regexp-7.11 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {1\&\1} foo] $foo
+} {1 xax1&aaxaa}
+test regexp-7.12 {basic regsub operation} {
+ list [regsub a(a+) xaxaaaxaa {\1\1\1\1&&} foo] $foo
+} {1 xaxaaaaaaaaaaaaaaxaa}
+test regexp-7.13 {basic regsub operation} {
+ set foo xxx
+ list [regsub abc xyz 111 foo] $foo
+} {0 xyz}
+test regexp-7.14 {basic regsub operation} {
+ set foo xxx
+ list [regsub ^ xyz "111 " foo] $foo
+} {1 {111 xyz}}
+test regexp-7.15 {basic regsub operation} {
+ set foo xxx
+ list [regsub -- -foo abc-foodef "111 " foo] $foo
+} {1 {abc111 def}}
+test regexp-7.16 {basic regsub operation} {
+ set foo xxx
+ list [regsub x "" y foo] $foo
+} {0 {}}
+
+test regexp-8.1 {case conversion in regsub} {
+ list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
+} {1 xaAAaAAay}
+test regexp-8.2 {case conversion in regsub} {
+ list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
+} {1 xaAAaAAay}
+test regexp-8.3 {case conversion in regsub} {
+ set foo 123
+ list [regsub a(a+) xaAAaAAay & foo] $foo
+} {0 xaAAaAAay}
+test regexp-8.4 {case conversion in regsub} {
+ set foo 123
+ list [regsub -nocase a CaDE b foo] $foo
+} {1 CbDE}
+test regexp-8.5 {case conversion in regsub} {
+ set foo 123
+ list [regsub -nocase XYZ CxYzD b foo] $foo
+} {1 CbD}
+test regexp-8.6 {case conversion in regsub} {
+ set x abcdefghijklmnopqrstuvwxyz1234567890
+ set x $x$x$x$x$x$x$x$x$x$x$x$x
+ set foo 123
+ list [regsub -nocase $x $x b foo] $foo
+} {1 b}
+
+test regexp-9.1 {-all option to regsub} {
+ set foo 86
+ list [regsub -all x+ axxxbxxcxdx |&| foo] $foo
+} {1 a|xxx|b|xx|c|x|d|x|}
+test regexp-9.2 {-all option to regsub} {
+ set foo 86
+ list [regsub -nocase -all x+ aXxXbxxcXdx |&| foo] $foo
+} {1 a|XxX|b|xx|c|X|d|x|}
+test regexp-9.3 {-all option to regsub} {
+ set foo 86
+ list [regsub x+ axxxbxxcxdx |&| foo] $foo
+} {1 a|xxx|bxxcxdx}
+test regexp-9.4 {-all option to regsub} {
+ set foo 86
+ list [regsub -all bc axxxbxxcxdx |&| foo] $foo
+} {0 axxxbxxcxdx}
+test regexp-9.5 {-all option to regsub} {
+ set foo xxx
+ list [regsub -all node "node node more" yy foo] $foo
+} {1 {yy yy more}}
+test regexp-9.6 {-all option to regsub} {
+ set foo xxx
+ list [regsub -all ^ xxx 123 foo] $foo
+} {1 123xxx}
+
+test regexp-10.1 {regsub errors} {
+ list [catch {regsub a b c} msg] $msg
+} {1 {wrong # args: should be "regsub ?switches? exp string subSpec varName"}}
+test regexp-10.2 {regsub errors} {
+ list [catch {regsub -nocase a b c} msg] $msg
+} {1 {wrong # args: should be "regsub ?switches? exp string subSpec varName"}}
+test regexp-10.3 {regsub errors} {
+ list [catch {regsub -nocase -all a b c} msg] $msg
+} {1 {wrong # args: should be "regsub ?switches? exp string subSpec varName"}}
+test regexp-10.4 {regsub errors} {
+ list [catch {regsub a b c d e f} msg] $msg
+} {1 {wrong # args: should be "regsub ?switches? exp string subSpec varName"}}
+test regexp-10.5 {regsub errors} {
+ list [catch {regsub -gorp a b c} msg] $msg
+} {1 {bad switch "-gorp": must be -all, -nocase, or --}}
+test regexp-10.6 {regsub errors} {
+ list [catch {regsub -nocase a( b c d} msg] $msg
+} {1 {couldn't compile regular expression pattern: unmatched ()}}
+test regexp-10.7 {regsub errors} {
+ list [catch {regsub -nocase aaa aaa xxx f1(f2)} msg] $msg
+} {1 {couldn't set variable "f1(f2)"}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/rename.test b/vendor/x11iraf/obm/Tcl/tests/rename.test
new file mode 100644
index 00000000..c5c8d922
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/rename.test
@@ -0,0 +1,78 @@
+# Commands covered: rename
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/rename.test,v 1.5 93/02/06 15:54:23 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {rename r2 {}}
+proc r1 {} {return "procedure r1"}
+rename r1 r2
+test rename-1.1 {simple renaming} {
+ r2
+} {procedure r1}
+test rename-1.2 {simple renaming} {
+ list [catch r1 msg] $msg
+} {1 {invalid command name: "r1"}}
+rename r2 {}
+test rename-1.3 {simple renaming} {
+ list [catch r2 msg] $msg
+} {1 {invalid command name: "r2"}}
+
+# The test below is tricky because it renames a built-in command.
+# It's possible that the test procedure uses this command, so must
+# restore the command before calling test again.
+
+rename list l.new
+set a [catch list msg1]
+set b [l.new a b c]
+rename l.new list
+set c [catch l.new msg2]
+set d [list 111 222]
+test 2.1 {renaming built-in command} {
+ list $a $msg1 $b $c $msg2 $d
+} {1 {invalid command name: "list"} {a b c} 1 {invalid command name: "l.new"} {111 222}}
+
+test rename-3.1 {error conditions} {
+ list [catch {rename r1} msg] $msg $errorCode
+} {1 {wrong # args: should be "rename oldName newName"} NONE}
+test rename-3.2 {error conditions} {
+ list [catch {rename r1 r2 r3} msg] $msg $errorCode
+} {1 {wrong # args: should be "rename oldName newName"} NONE}
+test rename-3.3 {error conditions} {
+ proc r1 {} {}
+ proc r2 {} {}
+ list [catch {rename r1 r2} msg] $msg
+} {1 {can't rename to "r2": command already exists}}
+test rename-3.4 {error conditions} {
+ catch {rename r1 {}}
+ catch {rename r2 {}}
+ list [catch {rename r1 r2} msg] $msg
+} {1 {can't rename "r1": command doesn't exist}}
+test rename-3.5 {error conditions} {
+ catch {rename _non_existent_command {}}
+ list [catch {rename _non_existent_command {}} msg] $msg
+} {1 {can't delete "_non_existent_command": command doesn't exist}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/scan.test b/vendor/x11iraf/obm/Tcl/tests/scan.test
new file mode 100644
index 00000000..c0219d5f
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/scan.test
@@ -0,0 +1,276 @@
+# Commands covered: scan
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/scan.test,v 1.17 93/10/07 10:39:35 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test scan-1.1 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "-20 1476 \n33 0" "%d %d %d %d" a b c d] $a $b $c $d
+} {4 -20 1476 33 0}
+test scan-1.2 {integer scanning} {
+ set a {}; set b {}; set c {}
+ list [scan "-45 16 7890 +10" "%2d %*d %10d %d" a b c] $a $b $c
+} {3 -4 16 7890}
+test scan-1.3 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "-45 16 +10 987" "%ld %d %ld %d" a b c d] $a $b $c $d
+} {4 -45 16 10 987}
+test scan-1.4 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "14 1ab 62 10" "%d %x %lo %x" a b c d] $a $b $c $d
+} {4 14 427 50 16}
+test scan-1.5 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "12345670 1234567890ab cdefg" "%o %o %x %lx" a b c d] \
+ $a $b $c $d
+} {4 2739128 342391 561323 52719}
+test scan-1.6 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "ab123-24642" "%2x %3x %3o %2o" a b c d] $a $b $c $d
+} {4 171 291 -20 52}
+test scan-1.7 {integer scanning} {
+ set a {}; set b {}
+ list [scan "1234567 234 567 " "%*3x %x %*o %4o" a b] $a $b
+} {2 17767 375}
+test scan-1.8 {integer scanning} {
+ set a {}; set b {}
+ list [scan "a 1234" "%d %d" a b] $a $b
+} {0 {} {}}
+test scan-1.9 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {};
+ list [scan "12345678" "%2d %2d %2ld %2d" a b c d] $a $b $c $d
+} {4 12 34 56 78}
+test scan-1.10 {integer scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "1 2 " "%hd %d %d %d" a b c d] $a $b $c $d
+} {2 1 2 {} {}}
+if $atBerkeley {
+ test scan-1.11 {integer scanning} {
+ set a {}; set b {};
+ list [scan "4294967280 4294967280" "%u %d" a b] $a $b
+ } {2 4294967280 -16}
+}
+
+test scan-2.1 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "2.1 -3.0e8 .99962 a" "%f%g%e%f" a b c d] $a $b $c $d
+} {3 2.1 -3e+08 0.99962 {}}
+test scan-2.2 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "-1.2345 +8.2 9" "%3e %3lf %f %f" a b c d] $a $b $c $d
+} {4 -1.0 234.0 5.0 8.2}
+test scan-2.3 {floating-point scanning} {
+ set a {}; set b {}; set c {}
+ list [scan "1e00004 332E-4 3e+4" "%Lf %*2e %f %f" a b c] $a $c
+} {3 10000.0 30000.0}
+if $atBerkeley {
+ test scan-2.4 {floating-point scanning} {
+ set a {}; set b {}; set c {}
+ list [scan "1. 47.6 2.e2 3.e-" "%f %*f %f %f" a b c] $a $b $c
+ } {3 1.0 200.0 3.0}
+ test scan-2.5 {floating-point scanning} {
+ set a {}; set b {}
+ list [scan "1.eabc" "%f %x" a b] $a $b
+ } {2 1.0 2748}
+}
+test scan-2.6 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "4.6 99999.7 876.43e-1 118" "%f %f %f %e" a b c d] $a $b $c $d
+} {4 4.6 99999.7 87.643 118.0}
+test scan-2.7 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "1.2345 697.0e-3 124 .00005" "%f %e %f %e" a b c d] $a $b $c $d
+} {4 1.2345 0.697 124.0 5e-05}
+test scan-2.8 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "4.6abc" "%f %f %f %f" a b c d] $a $b $c $d
+} {1 4.6 {} {} {}}
+test scan-2.9 {floating-point scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "4.6 5.2" "%f %f %f %f" a b c d] $a $b $c $d
+} {2 4.6 5.2 {} {}}
+
+test scan-3.1 {string and character scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "abc defghijk dum " "%s %3s %20s %s" a b c d] $a $b $c $d
+} {4 abc def ghijk dum}
+test scan-3.2 {string and character scanning} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "a bcdef" "%c%c%1s %s" a b c d] $a $b $c $d
+} {4 97 32 b cdef}
+test scan-3.3 {string and character scanning} {
+ set a {}; set b {}; set c {}
+ list [scan "123456 test " "%*c%*s %s %s %s" a b c] $a $b $c
+} {1 test {} {}}
+test scan-3.4 {string and character scanning} {
+ set a {}; set b {}; set c {}; set d
+ list [scan "ababcd01234 f 123450" {%4[abcd] %4[abcd] %[^abcdef] %[^0]} a b c d] $a $b $c $d
+} {4 abab cd {01234 } {f 12345}}
+test scan-3.5 {string and character scanning} {
+ set a {}; set b {}; set c {}
+ list [scan "aaaaaabc aaabcdefg + + XYZQR" {%*4[a] %s %*4[a]%s%*4[ +]%c} a b c] $a $b $c
+} {3 aabc bcdefg 43}
+
+test scan-4.1 {error conditions} {
+ catch {scan a}
+} 1
+test scan-4.2 {error conditions} {
+ catch {scan a} msg
+ set msg
+} {wrong # args: should be "scan string format ?varName varName ...?"}
+test scan-4.3 {error conditions} {
+ catch {scan "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21}
+} 1
+test scan-4.4 {error conditions} {
+ catch {scan "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21} msg
+ set msg
+} {too many fields to scan}
+test scan-4.5 {error conditions} {
+ list [catch {scan a %D} msg] $msg
+} {1 {bad scan conversion character "D"}}
+test scan-4.6 {error conditions} {
+ list [catch {scan a %O} msg] $msg
+} {1 {bad scan conversion character "O"}}
+test scan-4.7 {error conditions} {
+ list [catch {scan a %X} msg] $msg
+} {1 {bad scan conversion character "X"}}
+test scan-4.8 {error conditions} {
+ list [catch {scan a %F} msg] $msg
+} {1 {bad scan conversion character "F"}}
+test scan-4.9 {error conditions} {
+ list [catch {scan a %E} msg] $msg
+} {1 {bad scan conversion character "E"}}
+test scan-4.10 {error conditions} {
+ list [catch {scan a "%d %d" a} msg] $msg
+} {1 {different numbers of variable names and field specifiers}}
+test scan-4.11 {error conditions} {
+ list [catch {scan a "%d %d" a b c} msg] $msg
+} {1 {different numbers of variable names and field specifiers}}
+test scan-4.12 {error conditions} {
+ set a {}; set b {}; set c {}; set d {}
+ list [expr {[scan " a" " a %d %d %d %d" a b c d] <= 0}] $a $b $c $d
+} {1 {} {} {} {}}
+test scan-4.13 {error conditions} {
+ set a {}; set b {}; set c {}; set d {}
+ list [scan "1 2" "%d %d %d %d" a b c d] $a $b $c $d
+} {2 1 2 {} {}}
+test scan-4.14 {error conditions} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {scan 44 %d a} msg] $msg
+} {1 {couldn't set variable "a"}}
+test scan-4.15 {error conditions} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {scan 44 %c a} msg] $msg
+} {1 {couldn't set variable "a"}}
+test scan-4.16 {error conditions} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {scan 44 %s a} msg] $msg
+} {1 {couldn't set variable "a"}}
+test scan-4.17 {error conditions} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {scan 44 %f a} msg] $msg
+} {1 {couldn't set variable "a"}}
+test scan-4.18 {error conditions} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {scan 44 %f a} msg] $msg
+} {1 {couldn't set variable "a"}}
+catch {unset a}
+test scan-4.19 {error conditions} {
+ list [catch {scan 44 %2c a} msg] $msg
+} {1 {field width may not be specified in %c conversion}}
+
+test scan-5.1 {lots of arguments} {
+ scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20
+} 20
+test scan-5.2 {lots of arguments} {
+ scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20
+ set a20
+} 200
+
+test scan-6.1 {miscellaneous tests} {
+ set a {}
+ list [scan ab16c ab%dc a] $a
+} {1 16}
+test scan-6.2 {miscellaneous tests} {
+ set a {}
+ list [scan ax16c ab%dc a] $a
+} {0 {}}
+test scan-6.3 {miscellaneous tests} {
+ set a {}
+ list [catch {scan ab%c114 ab%%c%d a} msg] $msg $a
+} {0 1 114}
+test scan-6.4 {miscellaneous tests} {
+ set a {}
+ list [catch {scan ab%c14 ab%%c%d a} msg] $msg $a
+} {0 1 14}
+test scan-6.5 {miscellaneous tests} {
+ catch {unset tcl_precision}
+ set a {}
+ scan 1.111122223333 %f a
+ set a
+} {1.11112}
+test scan-6.6 {miscellaneous tests} {
+ set tcl_precision 10
+ set a {}
+ scan 1.111122223333 %lf a
+ unset tcl_precision
+ set a
+} {1.111122223}
+test scan-6.7 {miscellaneous tests} {
+ set tcl_precision 10
+ set a {}
+ scan 1.111122223333 %f a
+ unset tcl_precision
+ set a
+} {1.111122223}
+
+test scan-7.1 {alignment in results array (TCL_ALIGN)} {
+ scan "123 13.6" "%s %f" a b
+ set b
+} 13.6
+test scan-7.2 {alignment in results array (TCL_ALIGN)} {
+ scan "1234567 13.6" "%s %f" a b
+ set b
+} 13.6
+test scan-7.3 {alignment in results array (TCL_ALIGN)} {
+ scan "12345678901 13.6" "%s %f" a b
+ set b
+} 13.6
+test scan-7.4 {alignment in results array (TCL_ALIGN)} {
+ scan "123456789012345 13.6" "%s %f" a b
+ set b
+} 13.6
+test scan-7.5 {alignment in results array (TCL_ALIGN)} {
+ scan "1234567890123456789 13.6" "%s %f" a b
+ set b
+} 13.6
diff --git a/vendor/x11iraf/obm/Tcl/tests/set.test b/vendor/x11iraf/obm/Tcl/tests/set.test
new file mode 100644
index 00000000..f8622e32
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/set.test
@@ -0,0 +1,584 @@
+# Commands covered: set, unset, array
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/set.test,v 1.12 93/07/21 09:18:48 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc ignore args {}
+
+# Simple variable operations.
+
+catch {unset a}
+test set-1.1 {basic variable setting and unsetting} {
+ set a 22
+} 22
+test set-1.2 {basic variable setting and unsetting} {
+ set a 123
+ set a
+} 123
+test set-1.3 {basic variable setting and unsetting} {
+ set a xxx
+ format %s $a
+} xxx
+test set-1.4 {basic variable setting and unsetting} {
+ set a 44
+ unset a
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+
+# Basic array operations.
+
+catch {unset a}
+set a(xyz) 2
+set a(44) 3
+set {a(a long name)} test
+test set-2.1 {basic array operations} {
+ lsort [array names a]
+} {44 {a long name} xyz}
+test set-2.2 {basic array operations} {
+ set a(44)
+} 3
+test set-2.3 {basic array operations} {
+ set a(xyz)
+} 2
+test set-2.4 {basic array operations} {
+ set "a(a long name)"
+} test
+test set-2.5 {basic array operations} {
+ list [catch {set a(other)} msg] $msg
+} {1 {can't read "a(other)": no such element in array}}
+test set-2.6 {basic array operations} {
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+test set-2.7 {basic array operations} {
+ format %s $a(44)
+} 3
+test set-2.8 {basic array operations} {
+ format %s $a(a long name)
+} test
+unset a(44)
+test set-2.9 {basic array operations} {
+ lsort [array names a]
+} {{a long name} xyz}
+test set-2.10 {basic array operations} {
+ catch {unset b}
+ list [catch {set b(123)} msg] $msg
+} {1 {can't read "b(123)": no such variable}}
+test set-2.11 {basic array operations} {
+ catch {unset b}
+ set b 44
+ list [catch {set b(123)} msg] $msg
+} {1 {can't read "b(123)": variable isn't array}}
+test set-2.12 {basic array operations} {
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+test set-2.13 {basic array operations} {
+ list [catch {set a 14} msg] $msg
+} {1 {can't set "a": variable is array}}
+unset a
+test set-2.14 {basic array operations} {
+ list [catch {set a(xyz)} msg] $msg
+} {1 {can't read "a(xyz)": no such variable}}
+
+# Test the set commands, and exercise the corner cases of the code
+# that parses array references into two parts.
+
+test set-3.1 {set command} {
+ list [catch {set} msg] $msg
+} {1 {wrong # args: should be "set varName ?newValue?"}}
+test set-3.2 {set command} {
+ list [catch {set x y z} msg] $msg
+} {1 {wrong # args: should be "set varName ?newValue?"}}
+test set-3.3 {set command} {
+ catch {unset a}
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+test set-3.4 {set command} {
+ catch {unset a}
+ set a(14) 83
+ list [catch {set a 22} msg] $msg
+} {1 {can't set "a": variable is array}}
+
+# Test the corner-cases of parsing array names, using set and unset.
+
+test set-4.1 {parsing array names} {
+ catch {unset a}
+ set a(()) 44
+ list [catch {array names a} msg] $msg
+} {0 ()}
+test set-4.2 {parsing array names} {
+ catch {unset a a(abcd}
+ set a(abcd 33
+ info exists a(abcd
+} 1
+test set-4.3 {parsing array names} {
+ catch {unset a a(abcd}
+ set a(abcd 33
+ list [catch {array names a} msg] $msg
+} {1 {"a" isn't an array}}
+test set-4.4 {parsing array names} {
+ catch {unset a abcd)}
+ set abcd) 33
+ info exists abcd)
+} 1
+test set-4.5 {parsing array names} {
+ set a(bcd yyy
+ catch {unset a}
+ list [catch {set a(bcd} msg] $msg
+} {0 yyy}
+test set-4.6 {parsing array names} {
+ catch {unset a}
+ set a 44
+ list [catch {set a(bcd test} msg] $msg
+} {0 test}
+
+# Errors in reading variables
+
+test set-5.1 {errors in reading variables} {
+ catch {unset a}
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+test set-5.2 {errors in reading variables} {
+ catch {unset a}
+ set a 44
+ list [catch {set a(18)} msg] $msg
+} {1 {can't read "a(18)": variable isn't array}}
+test set-5.3 {errors in reading variables} {
+ catch {unset a}
+ set a(6) 44
+ list [catch {set a(18)} msg] $msg
+} {1 {can't read "a(18)": no such element in array}}
+test set-5.4 {errors in reading variables} {
+ catch {unset a}
+ set a(6) 44
+ list [catch {set a} msg] $msg
+} {1 {can't read "a": no such variable}}
+
+# Errors and other special cases in writing variables
+
+test set-6.1 {creating array during write} {
+ catch {unset a}
+ trace var a rwu ignore
+ list [catch {set a(14) 186} msg] $msg [array names a]
+} {0 186 14}
+test set-6.2 {errors in writing variables} {
+ catch {unset a}
+ set a xxx
+ list [catch {set a(14) 186} msg] $msg
+} {1 {can't set "a(14)": variable isn't array}}
+test set-6.3 {errors in writing variables} {
+ catch {unset a}
+ set a(100) yyy
+ list [catch {set a 2} msg] $msg
+} {1 {can't set "a": variable is array}}
+test set-6.4 {expanding variable size} {
+ catch {unset a}
+ list [set a short] [set a "longer name"] [set a "even longer name"] \
+ [set a "a much much truly longer name"]
+} {short {longer name} {even longer name} {a much much truly longer name}}
+
+# Unset command, Tcl_UnsetVar procedures
+
+test set-7.1 {unset command} {
+ catch {unset a}; catch {unset b}; catch {unset c}; catch {unset d}
+ set a 44
+ set b 55
+ set c 66
+ set d 77
+ unset a b c
+ list [catch {set a(0) 0}] [catch {set b(0) 0}] [catch {set c(0) 0}] \
+ [catch {set d(0) 0}]
+} {0 0 0 1}
+test set-7.2 {unset command} {
+ list [catch {unset} msg] $msg
+} {1 {wrong # args: should be "unset varName ?varName ...?"}}
+test set-7.3 {unset command} {
+ catch {unset a}
+ list [catch {unset a} msg] $msg
+} {1 {can't unset "a": no such variable}}
+test set-7.4 {unset command} {
+ catch {unset a}
+ set a 44
+ list [catch {unset a(14)} msg] $msg
+} {1 {can't unset "a(14)": variable isn't array}}
+test set-7.5 {unset command} {
+ catch {unset a}
+ set a(0) xx
+ list [catch {unset a(14)} msg] $msg
+} {1 {can't unset "a(14)": no such element in array}}
+test set-7.6 {unset command} {
+ catch {unset a}; catch {unset b}; catch {unset c}
+ set a foo
+ set c gorp
+ list [catch {unset a a a(14)} msg] $msg [info exists c]
+} {1 {can't unset "a": no such variable} 1}
+test set-7.7 {unsetting globals from within procedures} {
+ set y 0
+ proc p1 {} {
+ global y
+ set z [p2]
+ return [list $z [catch {set y} msg] $msg]
+ }
+ proc p2 {} {global y; unset y; list [catch {set y} msg] $msg}
+ p1
+} {{1 {can't read "y": no such variable}} 1 {can't read "y": no such variable}}
+test set-7.8 {unsetting globals from within procedures} {
+ set y 0
+ proc p1 {} {
+ global y
+ p2
+ return [list [catch {set y 44} msg] $msg]
+ }
+ proc p2 {} {global y; unset y}
+ concat [p1] [list [catch {set y} msg] $msg]
+} {0 44 0 44}
+test set-7.9 {unsetting globals from within procedures} {
+ set y 0
+ proc p1 {} {
+ global y
+ unset y
+ return [list [catch {set y 55} msg] $msg]
+ }
+ concat [p1] [list [catch {set y} msg] $msg]
+} {0 55 0 55}
+test set-7.10 {unset command} {
+ catch {unset a}
+ set a(14) 22
+ unset a(14)
+ list [catch {set a(14)} msg] $msg [catch {array names a} msg2] $msg2
+} {1 {can't read "a(14)": no such element in array} 0 {}}
+test set-7.11 {unset command} {
+ catch {unset a}
+ set a(14) 22
+ unset a
+ list [catch {set a(14)} msg] $msg [catch {array names a} msg2] $msg2
+} {1 {can't read "a(14)": no such variable} 1 {"a" isn't an array}}
+
+# Array command.
+
+test set-8.1 {array command} {
+ list [catch {array} msg] $msg
+} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
+test set-8.2 {array command} {
+ catch {unset a}
+ list [catch {array names a} msg] $msg
+} {1 {"a" isn't an array}}
+test set-8.3 {array command} {
+ catch {unset a}
+ set a 44
+ list [catch {array names a} msg] $msg
+} {1 {"a" isn't an array}}
+test set-8.4 {array command} {
+ catch {unset a}
+ set a(22) 3
+ list [catch {array gorp a} msg] $msg
+} {1 {bad option "gorp": should be anymore, donesearch, names, nextelement, size, or startsearch}}
+test set-8.5 {array command, names option} {
+ catch {unset a}
+ set a(22) 3
+ list [catch {array names a 4} msg] $msg
+} {1 {wrong # args: should be "array names arrayName"}}
+test set-8.6 {array command, names option} {
+ catch {unset a}
+ set a(22) 3; set a(Textual_name) 44; set "a(name with spaces)" xxx
+ list [catch {lsort [array names a]} msg] $msg
+} {0 {22 Textual_name {name with spaces}}}
+test set-8.7 {array command, names option} {
+ catch {unset a}
+ set a(22) 3; set a(33) 44;
+ trace var a(xxx) w ignore
+ list [catch {lsort [array names a]} msg] $msg
+} {0 {22 33}}
+test set-8.8 {array command, names option} {
+ catch {unset a}
+ set a(22) 3; set a(33) 44;
+ trace var a(xxx) w ignore
+ set a(xxx) value
+ list [catch {lsort [array names a]} msg] $msg
+} {0 {22 33 xxx}}
+test set-8.9 {array command, size option} {
+ catch {unset a}
+ set a(22) 3
+ list [catch {array size a 4} msg] $msg
+} {1 {wrong # args: should be "array size arrayName"}}
+test set-8.10 {array command, size option} {
+ catch {unset a}
+ set a(22) 3; set a(Textual_name) 44; set "a(name with spaces)" xxx
+ list [catch {array size a} msg] $msg
+} {0 3}
+test set-8.10 {array command, size option} {
+ catch {unset a}
+ set a(22) 3; set a(xx) 44; set a(y) xxx
+ unset a(22) a(y) a(xx)
+ list [catch {array size a} msg] $msg
+} {0 0}
+test set-8.11 {array command, size option} {
+ catch {unset a}
+ set a(22) 3;
+ trace var a(33) rwu ignore
+ list [catch {array size a} msg] $msg
+} {0 1}
+
+test set-9.1 {ids for array enumeration} {
+ catch {unset a}
+ set a(a) 1
+ list [array st a] [array st a] [array done a s-1-a; array st a] \
+ [array done a s-2-a; array d a s-3-a; array start a]
+} {s-1-a s-2-a s-3-a s-1-a}
+test set-9.2 {array enumeration} {
+ catch {unset a}
+ set a(a) 1
+ set a(b) 1
+ set a(c) 1
+ set x [array startsearch a]
+ list [array nextelement a $x] [array ne a $x] [array next a $x] \
+ [array next a $x] [array next a $x]
+} {a b c {} {}}
+test set-9.3 {array enumeration} {
+ catch {unset a}
+ set a(a) 1
+ set a(b) 1
+ set a(c) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ set z [array startsearch a]
+ list [array nextelement a $x] [array ne a $x] \
+ [array next a $y] [array next a $z] [array next a $y] \
+ [array next a $z] [array next a $y] [array next a $z] \
+ [array next a $y] [array next a $z] [array next a $x] \
+ [array next a $x]
+} {a b a a b b c c {} {} c {}}
+test set-9.4 {array enumeration: stopping searches} {
+ catch {unset a}
+ set a(a) 1
+ set a(b) 1
+ set a(c) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ set z [array startsearch a]
+ list [array next a $x] [array next a $x] [array next a $y] \
+ [array done a $z; array next a $x] \
+ [array done a $x; array next a $y] [array next a $y]
+} {a b a c b c}
+test set-9.5 {array enumeration: stopping searches} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ array done a $x
+ list [catch {array next a $x} msg] $msg
+} {1 {couldn't find search "s-1-a"}}
+test set-9.6 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ set a(b) 1
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}}
+test set-9.7 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ set a(a) 2
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {0 a 0 a}
+test set-9.8 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set a(c) 2
+ set x [array startsearch a]
+ set y [array startsearch a]
+ catch {unset a(c)}
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}}
+test set-9.9 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ catch {unset a(c)}
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {0 a 0 a}
+test set-9.10 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ trace var a(b) r {}
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}}
+test set-9.11 {array enumeration: searches automatically stopped} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ set y [array startsearch a]
+ trace var a(a) r {}
+ list [catch {array next a $x} msg] $msg \
+ [catch {array next a $y} msg2] $msg2
+} {0 a 0 a}
+test set-9.12 {array enumeration with traced undefined elements} {
+ catch {unset a}
+ set a(a) 1
+ trace var a(b) r {}
+ set x [array startsearch a]
+ list [array next a $x] [array next a $x]
+} {a {}}
+
+test set-10.1 {array enumeration errors} {
+ list [catch {array start} msg] $msg
+} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
+test set-10.2 {array enumeration errors} {
+ list [catch {array start a b} msg] $msg
+} {1 {wrong # args: should be "array startsearch arrayName"}}
+test set-10.3 {array enumeration errors} {
+ catch {unset a}
+ list [catch {array start a} msg] $msg
+} {1 {"a" isn't an array}}
+test set-10.4 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a} msg] $msg
+} {1 {wrong # args: should be "array nextelement arrayName searchId"}}
+test set-10.5 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a b c} msg] $msg
+} {1 {wrong # args: should be "array nextelement arrayName searchId"}}
+test set-10.6 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a a-1-a} msg] $msg
+} {1 {illegal search identifier "a-1-a"}}
+test set-10.7 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a sx1-a} msg] $msg
+} {1 {illegal search identifier "sx1-a"}}
+test set-10.8 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a s--a} msg] $msg
+} {1 {illegal search identifier "s--a"}}
+test set-10.9 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a s-1-b} msg] $msg
+} {1 {search identifier "s-1-b" isn't for variable "a"}}
+test set-10.10 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a s-1ba} msg] $msg
+} {1 {illegal search identifier "s-1ba"}}
+test set-10.11 {array enumeration errors} {
+ catch {unset a}
+ set a(a) 1
+ set x [array startsearch a]
+ list [catch {array next a s-2-a} msg] $msg
+} {1 {couldn't find search "s-2-a"}}
+test set-10.12 {array enumeration errors} {
+ list [catch {array done a} msg] $msg
+} {1 {wrong # args: should be "array donesearch arrayName searchId"}}
+test set-10.13 {array enumeration errors} {
+ list [catch {array done a b c} msg] $msg
+} {1 {wrong # args: should be "array donesearch arrayName searchId"}}
+test set-10.14 {array enumeration errors} {
+ list [catch {array done a b} msg] $msg
+} {1 {illegal search identifier "b"}}
+test set-10.15 {array enumeration errors} {
+ list [catch {array anymore a} msg] $msg
+} {1 {wrong # args: should be "array anymore arrayName searchId"}}
+test set-10.16 {array enumeration errors} {
+ list [catch {array any a b c} msg] $msg
+} {1 {wrong # args: should be "array anymore arrayName searchId"}}
+test set-10.17 {array enumeration errors} {
+ catch {unset a}
+ set a(0) 44
+ list [catch {array any a bogus} msg] $msg
+} {1 {illegal search identifier "bogus"}}
+
+# Array enumeration with "anymore" option
+
+test set-11.1 {array anymore option} {
+ catch {unset a}
+ set a(a) 1
+ set a(b) 2
+ set a(c) 3
+ array startsearch a
+ list [array anymore a s-1-a] [array next a s-1-a] \
+ [array anymore a s-1-a] [array next a s-1-a] \
+ [array anymore a s-1-a] [array next a s-1-a] \
+ [array anymore a s-1-a] [array next a s-1-a]
+} {1 a 1 b 1 c 0 {}}
+test set-11.2 {array anymore option} {
+ catch {unset a}
+ set a(a) 1
+ set a(b) 2
+ set a(c) 3
+ array startsearch a
+ list [array next a s-1-a] [array next a s-1-a] \
+ [array anymore a s-1-a] [array next a s-1-a] \
+ [array next a s-1-a] [array anymore a s-1-a]
+} {a b 1 c {} 0}
+
+# Special check to see that the value of a variable is handled correctly
+# if it is returned as the result of a procedure (must not free the variable
+# string while deleting the call frame). Errors will only be detected if
+# a memory consistency checker such as Purify is being used.
+
+test set-12.1 {cleanup on procedure return} {
+ proc foo {} {
+ set x 12345
+ }
+ foo
+} 12345
+test set-12.2 {cleanup on procedure return} {
+ proc foo {} {
+ set x(1) 23456
+ }
+ foo
+} 23456
+
+# Must delete variables when done, since these arrays get used as
+# scalars by other tests.
+
+catch {unset a}
+catch {unset b}
+catch {unset c}
+return ""
diff --git a/vendor/x11iraf/obm/Tcl/tests/source.test b/vendor/x11iraf/obm/Tcl/tests/source.test
new file mode 100644
index 00000000..4ad049a0
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/source.test
@@ -0,0 +1,95 @@
+# Commands covered: source
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/source.test,v 1.8 93/02/17 13:22:56 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test source-1.1 {source command} {
+ set x "old x value"
+ set y "old y value"
+ set z "old z value"
+ exec cat << {
+ set x 22
+ set y 33
+ set z 44
+ } > source.file
+ source source.file
+ list $x $y $z
+} {22 33 44}
+test source-1.2 {source command} {
+ exec cat << {list result} > source.file
+ source source.file
+} result
+
+test source-2.1 {source error conditions} {
+ list [catch {source} msg] $msg
+} {1 {wrong # args: should be "source fileName"}}
+test source-2.2 {source error conditions} {
+ list [catch {source a b} msg] $msg
+} {1 {wrong # args: should be "source fileName"}}
+test source-2.3 {source error conditions} {
+ exec cat << {
+ set x 146
+ error "error in sourced file"
+ set y $x
+ } > source.file
+ list [catch {source source.file} msg] $msg $errorInfo
+} {1 {error in sourced file} {error in sourced file
+ while executing
+"error "error in sourced file""
+ (file "source.file" line 3)
+ invoked from within
+"source source.file"}}
+test source-2.4 {source error conditions} {
+ exec cat << {break} > source.file
+ catch {source source.file}
+} 3
+test source-2.5 {source error conditions} {
+ exec cat << {continue} > source.file
+ catch {source source.file}
+} 4
+test source-2.6 {source error conditions} {
+ string tolower [list [catch {source _non_existent_} msg] $msg $errorCode]
+} {1 {couldn't read file "_non_existent_": no such file or directory} {posix enoent {no such file or directory}}}
+
+test source-3.1 {return in middle of source file} {
+ exec cat << {
+ set x new-x
+ return allDone
+ set y new-y
+ } > source.file
+ set x old-x
+ set y old-y
+ set z [source source.file]
+ list $x $y $z
+} {new-x old-y allDone}
+
+catch {exec rm source.file}
+
+# Generate null final value
+
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/split.test b/vendor/x11iraf/obm/Tcl/tests/split.test
new file mode 100644
index 00000000..1e2a3d8b
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/split.test
@@ -0,0 +1,58 @@
+# Commands covered: split
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/split.test,v 1.6 93/10/11 09:05:58 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test split-1.1 {basic split commands} {
+ split "a\n b\t\r c\n "
+} {a {} b {} {} c {} {}}
+test split-1.2 {basic split commands} {
+ split "word 1xyzword 2zword 3" xyz
+} {{word 1} {} {} {word 2} {word 3}}
+test split-1.3 {basic split commands} {
+ split "12345" {}
+} {1 2 3 4 5}
+test split-1.4 {basic split commands} {
+ split "a\}b\[c\{\]\$"
+} "a\\}b\\\[c\\{\\\]\\\$"
+test split-1.5 {basic split commands} {
+ split {} {}
+} {}
+test split-1.6 {basic split commands} {
+ split {}
+} {}
+test split-1.7 {basic split commands} {
+ split { }
+} {{} {} {} {}}
+
+test split-2.1 {split errors} {
+ list [catch split msg] $msg $errorCode
+} {1 {wrong # args: should be "split string ?splitChars?"} NONE}
+test split-2.2 {split errors} {
+ list [catch {split a b c} msg] $msg $errorCode
+} {1 {wrong # args: should be "split string ?splitChars?"} NONE}
diff --git a/vendor/x11iraf/obm/Tcl/tests/string.test b/vendor/x11iraf/obm/Tcl/tests/string.test
new file mode 100644
index 00000000..e0bc44a6
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/string.test
@@ -0,0 +1,333 @@
+# Commands covered: string
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/string.test,v 1.7 93/02/06 15:54:24 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test string-1.1 {string compare} {
+ string compare abcde abdef
+} -1
+test string-1.2 {string compare} {
+ string c abcde ABCDE
+} 1
+test string-1.3 {string compare} {
+ string compare abcde abcde
+} 0
+test string-1.4 {string compare} {
+ list [catch {string compare a} msg] $msg
+} {1 {wrong # args: should be "string compare string1 string2"}}
+test string-1.5 {string compare} {
+ list [catch {string compare a b c} msg] $msg
+} {1 {wrong # args: should be "string compare string1 string2"}}
+
+test string-2.1 {string first} {
+ string first bq abcdefgbcefgbqrs
+} 12
+test string-2.2 {string first} {
+ string fir bcd abcdefgbcefgbqrs
+} 1
+test string-2.3 {string first} {
+ string f b abcdefgbcefgbqrs
+} 1
+test string-2.4 {string first} {
+ string first xxx x123xx345xxx789xxx012
+} 9
+test string-2.5 {string first} {
+ list [catch {string first a} msg] $msg
+} {1 {wrong # args: should be "string first string1 string2"}}
+test string-2.6 {string first} {
+ list [catch {string first a b c} msg] $msg
+} {1 {wrong # args: should be "string first string1 string2"}}
+
+test string-3.1 {string index} {
+ string index abcde 0
+} a
+test string-3.2 {string index} {
+ string i abcde 4
+} e
+test string-3.3 {string index} {
+ string index abcde 5
+} {}
+test string-3.4 {string index} {
+ list [catch {string index abcde -10} msg] $msg
+} {0 {}}
+test string-3.5 {string index} {
+ list [catch {string index} msg] $msg
+} {1 {wrong # args: should be "string index string charIndex"}}
+test string-3.6 {string index} {
+ list [catch {string index a b c} msg] $msg
+} {1 {wrong # args: should be "string index string charIndex"}}
+test string-3.7 {string index} {
+ list [catch {string index a xyz} msg] $msg
+} {1 {expected integer but got "xyz"}}
+
+test string-4.1 {string last} {
+ string la xxx xxxx123xx345x678
+} 1
+test string-4.2 {string last} {
+ string last xx xxxx123xx345x678
+} 7
+test string-4.3 {string last} {
+ string las x xxxx123xx345x678
+} 12
+test string-4.4 {string last} {
+ list [catch {string last a} msg] $msg
+} {1 {wrong # args: should be "string last string1 string2"}}
+test string-4.5 {string last} {
+ list [catch {string last a b c} msg] $msg
+} {1 {wrong # args: should be "string last string1 string2"}}
+
+test string-5.1 {string length} {
+ string length "a little string"
+} 15
+test string-5.2 {string length} {
+ string le ""
+} 0
+test string-5.3 {string length} {
+ list [catch {string length} msg] $msg
+} {1 {wrong # args: should be "string length string"}}
+test string-5.4 {string length} {
+ list [catch {string length a b} msg] $msg
+} {1 {wrong # args: should be "string length string"}}
+
+test string-6.1 {string match} {
+ string match abc abc
+} 1
+test string-6.2 {string match} {
+ string m abc abd
+} 0
+test string-6.3 {string match} {
+ string match ab*c abc
+} 1
+test string-6.4 {string match} {
+ string match ab**c abc
+} 1
+test string-6.5 {string match} {
+ string match ab* abcdef
+} 1
+test string-6.6 {string match} {
+ string match *c abc
+} 1
+test string-6.7 {string match} {
+ string match *3*6*9 0123456789
+} 1
+test string-6.8 {string match} {
+ string match *3*6*9 01234567890
+} 0
+test string-6.9 {string match} {
+ string match a?c abc
+} 1
+test string-6.10 {string match} {
+ string match a??c abc
+} 0
+test string-6.11 {string match} {
+ string match ?1??4???8? 0123456789
+} 1
+test string-6.12 {string match} {
+ string match {[abc]bc} abc
+} 1
+test string-6.13 {string match} {
+ string match {a[abc]c} abc
+} 1
+test string-6.14 {string match} {
+ string match {a[xyz]c} abc
+} 0
+test string-6.15 {string match} {
+ string match {12[2-7]45} 12345
+} 1
+test string-6.16 {string match} {
+ string match {12[ab2-4cd]45} 12345
+} 1
+test string-6.17 {string match} {
+ string match {12[ab2-4cd]45} 12b45
+} 1
+test string-6.18 {string match} {
+ string match {12[ab2-4cd]45} 12d45
+} 1
+test string-6.19 {string match} {
+ string match {12[ab2-4cd]45} 12145
+} 0
+test string-6.20 {string match} {
+ string match {12[ab2-4cd]45} 12545
+} 0
+test string-6.21 {string match} {
+ string match {a\*b} a*b
+} 1
+test string-6.22 {string match} {
+ string match {a\*b} ab
+} 0
+test string-6.23 {string match} {
+ string match {a\*\?\[\]\\\x} "a*?\[\]\\x"
+} 1
+test string-6.24 {string match} {
+ string match ** ""
+} 1
+test string-6.25 {string match} {
+ string match *. ""
+} 0
+test string-6.26 {string match} {
+ string match "" ""
+} 1
+test string-6.27 {string match} {
+ list [catch {string match a} msg] $msg
+} {1 {wrong # args: should be "string match pattern string"}}
+test string-6.28 {string match} {
+ list [catch {string match a b c} msg] $msg
+} {1 {wrong # args: should be "string match pattern string"}}
+
+test string-7.1 {string range} {
+ string range abcdefghijklmnop 2 14
+} {cdefghijklmno}
+test string-7.2 {string range} {
+ string range abcdefghijklmnop 7 1000
+} {hijklmnop}
+test string-7.3 {string range} {
+ string range abcdefghijklmnop 10 e
+} {klmnop}
+test string-7.4 {string range} {
+ string range abcdefghijklmnop 10 9
+} {}
+test string-7.5 {string range} {
+ string range abcdefghijklmnop -3 2
+} {abc}
+test string-7.6 {string range} {
+ string range abcdefghijklmnop -3 -2
+} {}
+test string-7.7 {string range} {
+ string range abcdefghijklmnop 1000 1010
+} {}
+test string-7.8 {string range} {
+ string range abcdefghijklmnop -100 end
+} {abcdefghijklmnop}
+test string-7.9 {string range} {
+ list [catch {string range} msg] $msg
+} {1 {wrong # args: should be "string range string first last"}}
+test string-7.10 {string range} {
+ list [catch {string range a 1} msg] $msg
+} {1 {wrong # args: should be "string range string first last"}}
+test string-7.11 {string range} {
+ list [catch {string range a 1 2 3} msg] $msg
+} {1 {wrong # args: should be "string range string first last"}}
+test string-7.12 {string range} {
+ list [catch {string range abc abc 1} msg] $msg
+} {1 {expected integer but got "abc"}}
+test string-7.13 {string range} {
+ list [catch {string range abc 1 eof} msg] $msg
+} {1 {expected integer or "end" but got "eof"}}
+
+test string-8.1 {string trim} {
+ string trim " XYZ "
+} {XYZ}
+test string-8.2 {string trim} {
+ string trim "\t\nXYZ\t\n\r\n"
+} {XYZ}
+test string-8.3 {string trim} {
+ string trim " A XYZ A "
+} {A XYZ A}
+test string-8.4 {string trim} {
+ string trim "XXYYZZABC XXYYZZ" ZYX
+} {ABC }
+test string-8.5 {string trim} {
+ string trim " \t\r "
+} {}
+test string-8.6 {string trim} {
+ string trim {abcdefg} {}
+} {abcdefg}
+test string-8.7 {string trim} {
+ string trim {}
+} {}
+test string-8.8 {string trim} {
+ string trim ABC DEF
+} {ABC}
+test string-8.9 {string trim} {
+ list [catch {string trim} msg] $msg
+} {1 {wrong # args: should be "string trim string ?chars?"}}
+test string-8.10 {string trim} {
+ list [catch {string trim a b c} msg] $msg
+} {1 {wrong # args: should be "string trim string ?chars?"}}
+
+test string-9.1 {string trimleft} {
+ string trimleft " XYZ "
+} {XYZ }
+test string-9.2 {string trimleft} {
+ list [catch {string triml} msg] $msg
+} {1 {wrong # args: should be "string trimleft string ?chars?"}}
+
+test string-10.1 {string trimright} {
+ string trimright " XYZ "
+} { XYZ}
+test string-10.2 {string trimright} {
+ string trimright " "
+} {}
+test string-10.3 {string trimright} {
+ string trimright ""
+} {}
+test string-10.4 {string trimright errors} {
+ list [catch {string trimr} msg] $msg
+} {1 {wrong # args: should be "string trimright string ?chars?"}}
+test string-10.5 {string trimright errors} {
+ list [catch {string trimg a} msg] $msg
+} {1 {bad option "trimg": should be compare, first, index, last, length, match, range, tolower, toupper, trim, trimleft, or trimright}}
+
+test string-11.1 {string tolower} {
+ string tolower ABCDeF
+} {abcdef}
+test string-11.2 {string tolower} {
+ string tolower "ABC XyZ"
+} {abc xyz}
+test string-11.3 {string tolower} {
+ string tolower {123#$&*()}
+} {123#$&*()}
+test string-11.4 {string tolower} {
+ list [catch {string tolower} msg] $msg
+} {1 {wrong # args: should be "string tolower string"}}
+test string-11.5 {string tolower} {
+ list [catch {string tolower a b} msg] $msg
+} {1 {wrong # args: should be "string tolower string"}}
+
+test string-12.1 {string toupper} {
+ string toupper abCDEf
+} {ABCDEF}
+test string-12.2 {string toupper} {
+ string toupper "abc xYz"
+} {ABC XYZ}
+test string-12.3 {string toupper} {
+ string toupper {123#$&*()}
+} {123#$&*()}
+test string-12.4 {string toupper} {
+ list [catch {string toupper} msg] $msg
+} {1 {wrong # args: should be "string toupper string"}}
+test string-12.5 {string toupper} {
+ list [catch {string toupper a b} msg] $msg
+} {1 {wrong # args: should be "string toupper string"}}
+
+test string-13.1 {error conditions} {
+ list [catch {string gorp a b} msg] $msg
+} {1 {bad option "gorp": should be compare, first, index, last, length, match, range, tolower, toupper, trim, trimleft, or trimright}}
+test string-13.2 {error conditions} {
+ list [catch {string} msg] $msg
+} {1 {wrong # args: should be "string option arg ?arg ...?"}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/switch.test b/vendor/x11iraf/obm/Tcl/tests/switch.test
new file mode 100644
index 00000000..dd2baa27
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/switch.test
@@ -0,0 +1,184 @@
+# Commands covered: switch
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/switch.test,v 1.2 93/06/17 11:53:58 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test switch-1.1 {simple patterns} {
+ switch a a {format 1} b {format 2} c {format 3} default {format 4}
+} 1
+test switch-1.2 {simple patterns} {
+ switch b a {format 1} b {format 2} c {format 3} default {format 4}
+} 2
+test switch-1.3 {simple patterns} {
+ switch x a {format 1} b {format 2} c {format 3} default {format 4}
+} 4
+test switch-1.4 {simple patterns} {
+ switch x a {format 1} b {format 2} c {format 3}
+} {}
+test switch-1.5 {simple pattern matches many times} {
+ switch b a {format 1} b {format 2} b {format 3} b {format 4}
+} 2
+test switch-1.6 {simple patterns} {
+ switch default a {format 1} default {format 2} c {format 3} default {format 4}
+} 2
+test switch-1.7 {simple patterns} {
+ switch x a {format 1} default {format 2} c {format 3} default {format 4}
+} 4
+
+test switch-2.1 {single-argument form for pattern/command pairs} {
+ switch b {
+ a {format 1}
+ b {format 2}
+ default {format 6}
+ }
+} {2}
+test switch-2.2 {single-argument form for pattern/command pairs} {
+ list [catch {switch z {a 2 b}} msg] $msg
+} {1 {extra switch pattern with no body}}
+
+test switch-3.1 {-exact vs. -glob vs. -regexp} {
+ switch -exact aaaab {
+ ^a*b$ {concat regexp}
+ *b {concat glob}
+ aaaab {concat exact}
+ default {concat none}
+ }
+} exact
+test switch-3.2 {-exact vs. -glob vs. -regexp} {
+ switch -exact -regexp aaaab {
+ ^a*b$ {concat regexp}
+ *b {concat glob}
+ aaaab {concat exact}
+ default {concat none}
+ }
+} regexp
+test switch-3.3 {-exact vs. -glob vs. -regexp} {
+ switch -glob aaaab {
+ ^a*b$ {concat regexp}
+ *b {concat glob}
+ aaaab {concat exact}
+ default {concat none}
+ }
+} glob
+test switch-3.4 {-exact vs. -glob vs. -regexp} {
+ switch aaaab {^a*b$} {concat regexp} *b {concat glob} \
+ aaaab {concat exact} default {concat none}
+} exact
+test switch-3.5 {-exact vs. -glob vs. -regexp} {
+ switch -- -glob {
+ ^g.*b$ {concat regexp}
+ -* {concat glob}
+ -glob {concat exact}
+ default {concat none}
+ }
+} exact
+test switch-3.6 {-exact vs. -glob vs. -regexp} {
+ list [catch {switch -foo a b c} msg] $msg
+} {1 {bad option "-foo": should be -exact, -glob, -regexp, or --}}
+
+test switch-4.1 {error in executed command} {
+ list [catch {switch a a {error "Just a test"} default {format 1}} msg] \
+ $msg $errorInfo
+} {1 {Just a test} {Just a test
+ while executing
+"error "Just a test""
+ ("a" arm line 1)
+ invoked from within
+"switch a a {error "Just a test"} default {format 1}"}}
+test switch-4.2 {error: not enough args} {
+ list [catch {switch} msg] $msg
+} {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}}
+test switch-4.3 {error: pattern with no body} {
+ list [catch {switch a b} msg] $msg
+} {1 {extra switch pattern with no body}}
+test switch-4.4 {error: pattern with no body} {
+ list [catch {switch a b {format 1} c} msg] $msg
+} {1 {extra switch pattern with no body}}
+test switch-4.5 {error in default command} {
+ list [catch {switch foo a {error switch1} b {error switch 3} \
+ default {error switch2}} msg] $msg $errorInfo
+} {1 switch2 {switch2
+ while executing
+"error switch2"
+ ("default" arm line 1)
+ invoked from within
+"switch foo a {error switch1} b {error switch 3} default {error switch2}"}}
+
+test switch-5.1 {errors in -regexp matching} {
+ list [catch {switch -regexp aaaab {
+ *b {concat glob}
+ aaaab {concat exact}
+ default {concat none}
+ }} msg] $msg
+} {1 {couldn't compile regular expression pattern: ?+* follows nothing}}
+
+test switch-6.1 {backslashes in patterns} {
+ switch -exact {\a\$\.\[} {
+ \a\$\.\[ {concat first}
+ \a\\$\.\\[ {concat second}
+ \\a\\$\\.\\[ {concat third}
+ {\a\\$\.\\[} {concat fourth}
+ {\\a\\$\\.\\[} {concat fifth}
+ default {concat none}
+ }
+} third
+test switch-6.2 {backslashes in patterns} {
+ switch -exact {\a\$\.\[} {
+ \a\$\.\[ {concat first}
+ {\a\$\.\[} {concat second}
+ {{\a\$\.\[}} {concat third}
+ default {concat none}
+ }
+} second
+
+test switch-7.1 {"-" bodies} {
+ switch a {
+ a -
+ b -
+ c {concat 1}
+ default {concat 2}
+ }
+} 1
+test switch-7.2 {"-" bodies} {
+ list [catch {
+ switch a {
+ a -
+ b -
+ c -
+ }
+ } msg] $msg
+} {1 {no body specified for pattern "a"}}
+test switch-7.3 {"-" bodies} {
+ list [catch {
+ switch a {
+ a -
+ b -foo
+ c -
+ }
+ } msg] $msg
+} {1 {invalid command name: "-foo"}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/trace.test b/vendor/x11iraf/obm/Tcl/tests/trace.test
new file mode 100644
index 00000000..02fc051c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/trace.test
@@ -0,0 +1,914 @@
+# Commands covered: trace
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/trace.test,v 1.20 93/10/11 09:05:38 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc traceScalar {name1 name2 op} {
+ global info
+ set info [list $name1 $name2 $op [catch {uplevel set $name1} msg] $msg]
+}
+proc traceArray {name1 name2 op} {
+ global info
+ set info [list $name1 $name2 $op [catch {uplevel set [set name1]($name2)} msg] $msg]
+}
+proc traceProc {name1 name2 op} {
+ global info
+ set info [concat $info [list $name1 $name2 $op]]
+}
+proc traceTag {tag args} {
+ global info
+ set info [concat $info $tag]
+}
+proc traceError {args} {
+ error "trace returned error"
+}
+proc traceCheck {cmd args} {
+ global info
+ set info [list [catch $cmd msg] $msg]
+}
+proc traceCrtElement {value name1 name2 op} {
+ uplevel set ${name1}($name2) $value
+}
+
+# Read-tracing on variables
+
+test trace-1.1 {trace variable reads} {
+ catch {unset x}
+ set info {}
+ trace var x r traceScalar
+ list [catch {set x} msg] $msg $info
+} {1 {can't read "x": no such variable} {x {} r 1 {can't read "x": no such variable}}}
+test trace-1.2 {trace variable reads} {
+ catch {unset x}
+ set x 123
+ set info {}
+ trace var x r traceScalar
+ list [catch {set x} msg] $msg $info
+} {0 123 {x {} r 0 123}}
+test trace-1.3 {trace variable reads} {
+ catch {unset x}
+ set info {}
+ trace var x r traceScalar
+ set x 123
+ set info
+} {}
+test trace-1.4 {trace array element reads} {
+ catch {unset x}
+ set info {}
+ trace var x(2) r traceArray
+ list [catch {set x(2)} msg] $msg $info
+} {1 {can't read "x(2)": no such element in array} {x 2 r 1 {can't read "x(2)": no such element in array}}}
+test trace-1.5 {trace array element reads} {
+ catch {unset x}
+ set x(2) zzz
+ set info {}
+ trace var x(2) r traceArray
+ list [catch {set x(2)} msg] $msg $info
+} {0 zzz {x 2 r 0 zzz}}
+test trace-1.6 {trace reads on whole arrays} {
+ catch {unset x}
+ set info {}
+ trace var x r traceArray
+ list [catch {set x(2)} msg] $msg $info
+} {1 {can't read "x(2)": no such variable} {}}
+test trace-1.7 {trace reads on whole arrays} {
+ catch {unset x}
+ set x(2) zzz
+ set info {}
+ trace var x r traceArray
+ list [catch {set x(2)} msg] $msg $info
+} {0 zzz {x 2 r 0 zzz}}
+test trace-1.8 {trace variable reads} {
+ catch {unset x}
+ set x 444
+ set info {}
+ trace var x r traceScalar
+ unset x
+ set info
+} {}
+
+# Basic write-tracing on variables
+
+test trace-2.1 {trace variable writes} {
+ catch {unset x}
+ set info {}
+ trace var x w traceScalar
+ set x 123
+ set info
+} {x {} w 0 123}
+test trace-2.2 {trace writes to array elements} {
+ catch {unset x}
+ set info {}
+ trace var x(33) w traceArray
+ set x(33) 444
+ set info
+} {x 33 w 0 444}
+test trace-2.3 {trace writes on whole arrays} {
+ catch {unset x}
+ set info {}
+ trace var x w traceArray
+ set x(abc) qq
+ set info
+} {x abc w 0 qq}
+test trace-2.4 {trace variable writes} {
+ catch {unset x}
+ set x 1234
+ set info {}
+ trace var x w traceScalar
+ set x
+ set info
+} {}
+test trace-2.5 {trace variable writes} {
+ catch {unset x}
+ set x 1234
+ set info {}
+ trace var x w traceScalar
+ unset x
+ set info
+} {}
+
+# Basic unset-tracing on variables
+
+test trace-3.1 {trace variable unsets} {
+ catch {unset x}
+ set info {}
+ trace var x u traceScalar
+ catch {unset x}
+ set info
+} {x {} u 1 {can't read "x": no such variable}}
+test trace-3.2 {variable mustn't exist during unset trace} {
+ catch {unset x}
+ set x 1234
+ set info {}
+ trace var x u traceScalar
+ unset x
+ set info
+} {x {} u 1 {can't read "x": no such variable}}
+test trace-3.3 {unset traces mustn't be called during reads and writes} {
+ catch {unset x}
+ set info {}
+ trace var x u traceScalar
+ set x 44
+ set x
+ set info
+} {}
+test trace-3.4 {trace unsets on array elements} {
+ catch {unset x}
+ set x(0) 18
+ set info {}
+ trace var x(1) u traceArray
+ catch {unset x(1)}
+ set info
+} {x 1 u 1 {can't read "x(1)": no such element in array}}
+test trace-3.5 {trace unsets on array elements} {
+ catch {unset x}
+ set x(1) 18
+ set info {}
+ trace var x(1) u traceArray
+ unset x(1)
+ set info
+} {x 1 u 1 {can't read "x(1)": no such element in array}}
+test trace-3.6 {trace unsets on array elements} {
+ catch {unset x}
+ set x(1) 18
+ set info {}
+ trace var x(1) u traceArray
+ unset x
+ set info
+} {x 1 u 1 {can't read "x(1)": no such variable}}
+test trace-3.7 {trace unsets on whole arrays} {
+ catch {unset x}
+ set x(1) 18
+ set info {}
+ trace var x u traceProc
+ catch {unset x(0)}
+ set info
+} {}
+test trace-3.8 {trace unsets on whole arrays} {
+ catch {unset x}
+ set x(1) 18
+ set x(2) 144
+ set x(3) 14
+ set info {}
+ trace var x u traceProc
+ unset x(1)
+ set info
+} {x 1 u}
+test trace-3.9 {trace unsets on whole arrays} {
+ catch {unset x}
+ set x(1) 18
+ set x(2) 144
+ set x(3) 14
+ set info {}
+ trace var x u traceProc
+ unset x
+ set info
+} {x {} u}
+
+# Trace multiple trace types at once.
+
+test trace-4.1 {multiple ops traced at once} {
+ catch {unset x}
+ set info {}
+ trace var x rwu traceProc
+ catch {set x}
+ set x 22
+ set x
+ set x 33
+ unset x
+ set info
+} {x {} r x {} w x {} r x {} w x {} u}
+test trace-4.2 {multiple ops traced on array element} {
+ catch {unset x}
+ set info {}
+ trace var x(0) rwu traceProc
+ catch {set x(0)}
+ set x(0) 22
+ set x(0)
+ set x(0) 33
+ unset x(0)
+ unset x
+ set info
+} {x 0 r x 0 w x 0 r x 0 w x 0 u}
+test trace-4.3 {multiple ops traced on whole array} {
+ catch {unset x}
+ set info {}
+ trace var x rwu traceProc
+ catch {set x(0)}
+ set x(0) 22
+ set x(0)
+ set x(0) 33
+ unset x(0)
+ unset x
+ set info
+} {x 0 w x 0 r x 0 w x 0 u x {} u}
+
+# Check order of invocation of traces
+
+test trace-5.1 {order of invocation of traces} {
+ catch {unset x}
+ set info {}
+ trace var x r "traceTag 1"
+ trace var x r "traceTag 2"
+ trace var x r "traceTag 3"
+ catch {set x}
+ set x 22
+ set x
+ set info
+} {3 2 1 3 2 1}
+test trace-5.2 {order of invocation of traces} {
+ catch {unset x}
+ set x(0) 44
+ set info {}
+ trace var x(0) r "traceTag 1"
+ trace var x(0) r "traceTag 2"
+ trace var x(0) r "traceTag 3"
+ set x(0)
+ set info
+} {3 2 1}
+test trace-5.3 {order of invocation of traces} {
+ catch {unset x}
+ set x(0) 44
+ set info {}
+ trace var x(0) r "traceTag 1"
+ trace var x r "traceTag A1"
+ trace var x(0) r "traceTag 2"
+ trace var x r "traceTag A2"
+ trace var x(0) r "traceTag 3"
+ trace var x r "traceTag A3"
+ set x(0)
+ set info
+} {A3 A2 A1 3 2 1}
+
+# Check effects of errors in trace procedures
+
+test trace-6.1 {error returns from traces} {
+ catch {unset x}
+ set x 123
+ set info {}
+ trace var x r "traceTag 1"
+ trace var x r traceError
+ list [catch {set x} msg] $msg $info
+} {1 {can't read "x": trace returned error} {}}
+test trace-6.2 {error returns from traces} {
+ catch {unset x}
+ set x 123
+ set info {}
+ trace var x w "traceTag 1"
+ trace var x w traceError
+ list [catch {set x 44} msg] $msg $info
+} {1 {can't set "x": trace returned error} {}}
+test trace-6.3 {error returns from traces} {
+ catch {unset x}
+ set x 123
+ set info {}
+ trace var x u "traceTag 1"
+ trace var x u traceError
+ list [catch {unset x} msg] $msg $info
+} {0 {} 1}
+test trace-6.4 {error returns from traces} {
+ catch {unset x}
+ set x(0) 123
+ set info {}
+ trace var x(0) r "traceTag 1"
+ trace var x r "traceTag 2"
+ trace var x r traceError
+ trace var x r "traceTag 3"
+ list [catch {set x(0)} msg] $msg $info
+} {1 {can't read "x(0)": trace returned error} 3}
+test trace-6.5 {error returns from traces} {
+ catch {unset x}
+ set x 123
+ trace var x u traceError
+ list [catch {unset x} msg] $msg
+} {0 {}}
+test trace-6.6 {error returns from traces} {
+ # This test just makes sure that the memory for the error message
+ # gets deallocated correctly when the trace is invoked again or
+ # when the trace is deleted.
+ catch {unset x}
+ set x 123
+ trace var x r traceError
+ catch {set x}
+ catch {set x}
+ trace vdelete x r traceError
+} {}
+
+# Check to see that variables are expunged before trace
+# procedures are invoked, so trace procedure can even manipulate
+# a new copy of the variables.
+
+test trace-7.1 {be sure variable is unset before trace is called} {
+ catch {unset x}
+ set x 33
+ set info {}
+ trace var x u {traceCheck {uplevel set x}}
+ unset x
+ set info
+} {1 {can't read "x": no such variable}}
+test trace-7.2 {be sure variable is unset before trace is called} {
+ catch {unset x}
+ set x 33
+ set info {}
+ trace var x u {traceCheck {uplevel set x 22}}
+ unset x
+ concat $info [list [catch {set x} msg] $msg]
+} {0 22 0 22}
+test trace-7.3 {be sure traces are cleared before unset trace called} {
+ catch {unset x}
+ set x 33
+ set info {}
+ trace var x u {traceCheck {uplevel trace vinfo x}}
+ unset x
+ set info
+} {0 {}}
+test trace-7.4 {set new trace during unset trace} {
+ catch {unset x}
+ set x 33
+ set info {}
+ trace var x u {traceCheck {global x; trace var x u traceProc}}
+ unset x
+ concat $info [trace vinfo x]
+} {0 {} {u traceProc}}
+
+test trace-8.1 {make sure array elements are unset before traces are called} {
+ catch {unset x}
+ set x(0) 33
+ set info {}
+ trace var x(0) u {traceCheck {uplevel set x(0)}}
+ unset x(0)
+ set info
+} {1 {can't read "x(0)": no such element in array}}
+test trace-8.2 {make sure array elements are unset before traces are called} {
+ catch {unset x}
+ set x(0) 33
+ set info {}
+ trace var x(0) u {traceCheck {uplevel set x(0) zzz}}
+ unset x(0)
+ concat $info [list [catch {set x(0)} msg] $msg]
+} {0 zzz 0 zzz}
+test trace-8.3 {array elements are unset before traces are called} {
+ catch {unset x}
+ set x(0) 33
+ set info {}
+ trace var x(0) u {traceCheck {global x; trace vinfo x(0)}}
+ unset x(0)
+ set info
+} {0 {}}
+test trace-8.4 {set new array element trace during unset trace} {
+ catch {unset x}
+ set x(0) 33
+ set info {}
+ trace var x(0) u {traceCheck {uplevel {trace variable x(0) r {}}}}
+ catch {unset x(0)}
+ concat $info [trace vinfo x(0)]
+} {0 {} {r {}}}
+
+test trace-9.1 {make sure arrays are unset before traces are called} {
+ catch {unset x}
+ set x(0) 33
+ set info {}
+ trace var x u {traceCheck {uplevel set x(0)}}
+ unset x
+ set info
+} {1 {can't read "x(0)": no such variable}}
+test trace-9.2 {make sure arrays are unset before traces are called} {
+ catch {unset x}
+ set x(y) 33
+ set info {}
+ trace var x u {traceCheck {uplevel set x(y) 22}}
+ unset x
+ concat $info [list [catch {set x(y)} msg] $msg]
+} {0 22 0 22}
+test trace-9.3 {make sure arrays are unset before traces are called} {
+ catch {unset x}
+ set x(y) 33
+ set info {}
+ trace var x u {traceCheck {uplevel array names x}}
+ unset x
+ set info
+} {1 {"x" isn't an array}}
+test trace-9.4 {make sure arrays are unset before traces are called} {
+ catch {unset x}
+ set x(y) 33
+ set info {}
+ set cmd {traceCheck {uplevel {trace vinfo x}}}
+ trace var x u $cmd
+ unset x
+ set info
+} {0 {}}
+test trace-9.5 {set new array trace during unset trace} {
+ catch {unset x}
+ set x(y) 33
+ set info {}
+ trace var x u {traceCheck {global x; trace var x r {}}}
+ unset x
+ concat $info [trace vinfo x]
+} {0 {} {r {}}}
+test trace-9.6 {create scalar during array unset trace} {
+ catch {unset x}
+ set x(y) 33
+ set info {}
+ trace var x u {traceCheck {global x; set x 44}}
+ unset x
+ concat $info [list [catch {set x} msg] $msg]
+} {0 44 0 44}
+
+# Check special conditions (e.g. errors) in Tcl_TraceVar2.
+
+test trace-10.1 {creating array when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x(0) w traceProc
+ list [catch {set x 22} msg] $msg
+} {1 {can't set "x": variable is array}}
+test trace-10.2 {creating array when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x(0) w traceProc
+ list [catch {set x(0)} msg] $msg
+} {1 {can't read "x(0)": no such element in array}}
+test trace-10.3 {creating array when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x(0) w traceProc
+ set x(0) 22
+ set info
+} {x 0 w}
+test trace-10.4 {creating variable when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x w traceProc
+ list [catch {set x} msg] $msg
+} {1 {can't read "x": no such variable}}
+test trace-10.5 {creating variable when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x w traceProc
+ set x 22
+ set info
+} {x {} w}
+test trace-10.6 {creating variable when setting variable traces} {
+ catch {unset x}
+ set info {}
+ trace var x w traceProc
+ set x(0) 22
+ set info
+} {x 0 w}
+test trace-10.7 {create array element during read trace} {
+ catch {unset x}
+ set x(2) zzz
+ trace var x r {traceCrtElement xyzzy}
+ list [catch {set x(3)} msg] $msg
+} {0 xyzzy}
+test trace-10.8 {errors when setting variable traces} {
+ catch {unset x}
+ set x 44
+ list [catch {trace var x(0) w traceProc} msg] $msg
+} {1 {can't trace "x(0)": variable isn't array}}
+
+# Check deleting one trace from another.
+
+test trace-11.1 {delete one trace from another} {
+ proc delTraces {args} {
+ global x
+ trace vdel x r {traceTag 2}
+ trace vdel x r {traceTag 3}
+ trace vdel x r {traceTag 4}
+ }
+ catch {unset x}
+ set x 44
+ set info {}
+ trace var x r {traceTag 1}
+ trace var x r {traceTag 2}
+ trace var x r {traceTag 3}
+ trace var x r {traceTag 4}
+ trace var x r delTraces
+ trace var x r {traceTag 5}
+ set x
+ set info
+} {5 1}
+
+# Check operation and syntax of "trace" command.
+
+test trace-12.1 {trace command (overall)} {
+ list [catch {trace} msg] $msg
+} {1 {too few args: should be "trace option [arg arg ...]"}}
+test trace-12.2 {trace command (overall)} {
+ list [catch {trace gorp} msg] $msg
+} {1 {bad option "gorp": should be variable, vdelete, or vinfo}}
+test trace-12.3 {trace command ("variable" option)} {
+ list [catch {trace variable x y} msg] $msg
+} {1 {wrong # args: should be "trace variable name ops command"}}
+test trace-12.4 {trace command ("variable" option)} {
+ list [catch {trace var x y z z2} msg] $msg
+} {1 {wrong # args: should be "trace variable name ops command"}}
+test trace-12.5 {trace command ("variable" option)} {
+ list [catch {trace var x y z} msg] $msg
+} {1 {bad operations "y": should be one or more of rwu}}
+test trace-12.6 {trace command ("vdelete" option)} {
+ list [catch {trace vdelete x y} msg] $msg
+} {1 {wrong # args: should be "trace vdelete name ops command"}}
+test trace-12.7 {trace command ("vdelete" option)} {
+ list [catch {trace vdelete x y z foo} msg] $msg
+} {1 {wrong # args: should be "trace vdelete name ops command"}}
+test trace-12.8 {trace command ("vdelete" option)} {
+ list [catch {trace vdelete x y z} msg] $msg
+} {1 {bad operations "y": should be one or more of rwu}}
+test trace-12.9 {trace command ("vdelete" option)} {
+ catch {unset x}
+ set info {}
+ trace var x w traceProc
+ trace vdelete x w traceProc
+} {}
+test trace-12.10 {trace command ("vdelete" option)} {
+ catch {unset x}
+ set info {}
+ trace var x w traceProc
+ trace vdelete x w traceProc
+ set x 12345
+ set info
+} {}
+test trace-12.11 {trace command ("vdelete" option)} {
+ catch {unset x}
+ set info {}
+ trace var x w {traceTag 1}
+ trace var x w traceProc
+ trace var x w {traceTag 2}
+ set x yy
+ trace vdelete x w traceProc
+ set x 12345
+ trace vdelete x w {traceTag 1}
+ set x foo
+ trace vdelete x w {traceTag 2}
+ set x gorp
+ set info
+} {2 x {} w 1 2 1 2}
+test trace-12.12 {trace command ("vdelete" option)} {
+ catch {unset x}
+ set info {}
+ trace var x w {traceTag 1}
+ trace vdelete x w non_existent
+ set x 12345
+ set info
+} {1}
+test trace-12.13 {trace command ("vinfo" option)} {
+ list [catch {trace vinfo} msg] $msg]
+} {1 {wrong # args: should be "trace vinfo name"]}}
+test trace-12.14 {trace command ("vinfo" option)} {
+ list [catch {trace vinfo x y} msg] $msg]
+} {1 {wrong # args: should be "trace vinfo name"]}}
+test trace-12.15 {trace command ("vinfo" option)} {
+ catch {unset x}
+ trace var x w {traceTag 1}
+ trace var x w traceProc
+ trace var x w {traceTag 2}
+ trace vinfo x
+} {{w {traceTag 2}} {w traceProc} {w {traceTag 1}}}
+test trace-12.16 {trace command ("vinfo" option)} {
+ catch {unset x}
+ trace vinfo x
+} {}
+test trace-12.17 {trace command ("vinfo" option)} {
+ catch {unset x}
+ trace vinfo x(0)
+} {}
+test trace-12.18 {trace command ("vinfo" option)} {
+ catch {unset x}
+ set x 44
+ trace vinfo x(0)
+} {}
+test trace-12.19 {trace command ("vinfo" option)} {
+ catch {unset x}
+ set x 44
+ trace var x w {traceTag 1}
+ proc check {} {global x; trace vinfo x}
+ check
+} {{w {traceTag 1}}}
+
+# Check fancy trace commands (long ones, weird arguments, etc.)
+
+test trace-13.1 {long trace command} {
+ catch {unset x}
+ set info {}
+ trace var x w {traceTag {This is a very very long argument. It's \
+ designed to test out the facilities of TraceVarProc for dealing \
+ with such long arguments by malloc-ing space. One possibility \
+ is that space doesn't get freed properly. If this happens, then \
+ invoking this test over and over again will eventually leak memory.}}
+ set x 44
+ set info
+} {This is a very very long argument. It's \
+ designed to test out the facilities of TraceVarProc for dealing \
+ with such long arguments by malloc-ing space. One possibility \
+ is that space doesn't get freed properly. If this happens, then \
+ invoking this test over and over again will eventually leak memory.}
+test trace-13.2 {long trace command result to ignore} {
+ proc longResult {args} {return "quite a bit of text, designed to
+ generate a core leak if this command file is invoked over and over again
+ and memory isn't being recycled correctly"}
+ catch {unset x}
+ trace var x w longResult
+ set x 44
+ set x 5
+ set x abcde
+} abcde
+test trace-13.3 {special list-handling in trace commands} {
+ catch {unset "x y z"}
+ set "x y z(a\n\{)" 44
+ set info {}
+ trace var "x y z(a\n\{)" w traceProc
+ set "x y z(a\n\{)" 33
+ set info
+} "{x y z} a\\n\\{ w"
+
+# Check for proper handling of unsets during traces.
+
+proc traceUnset {unsetName args} {
+ global info
+ upvar $unsetName x
+ lappend info [catch {unset x} msg] $msg [catch {set x} msg] $msg
+}
+proc traceReset {unsetName resetName args} {
+ global info
+ upvar $unsetName x $resetName y
+ lappend info [catch {unset x} msg] $msg [catch {set y xyzzy} msg] $msg
+}
+proc traceReset2 {unsetName resetName args} {
+ global info
+ lappend info [catch {uplevel unset $unsetName} msg] $msg \
+ [catch {uplevel set $resetName xyzzy} msg] $msg
+}
+proc traceAppend {string name1 name2 op} {
+ global info
+ lappend info $string
+}
+
+test trace-14.1 {unsets during read traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y r {traceUnset y}
+ trace var y u {traceAppend unset}
+ lappend info [catch {set y} msg] $msg
+} {unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}}
+test trace-14.2 {unsets during read traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceUnset y(0)}
+ lappend info [catch {set y(0)} msg] $msg
+} {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such element in array}}
+test trace-14.3 {unsets during read traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceUnset y}
+ lappend info [catch {set y(0)} msg] $msg
+} {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}}
+test trace-14.4 {unsets during read traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y r {traceReset y y}
+ lappend info [catch {set y} msg] $msg
+} {0 {} 0 xyzzy 0 xyzzy}
+test trace-14.5 {unsets during read traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceReset y(0) y(0)}
+ lappend info [catch {set y(0)} msg] $msg
+} {0 {} 0 xyzzy 0 xyzzy}
+test trace-14.6 {unsets during read traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceReset y y(0)}
+ lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 1 {can't set "y": upvar refers to element in deleted array} 1 {can't read "y(0)": no such variable} 1 {can't read "y(0)": no such variable}}
+test trace-14.7 {unsets during read traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceReset2 y y(0)}
+ lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 0 xyzzy 1 {can't read "y(0)": no such element in array} 0 xyzzy}
+test trace-14.8 {unsets during write traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y w {traceUnset y}
+ trace var y u {traceAppend unset}
+ lappend info [catch {set y xxx} msg] $msg
+} {unset 0 {} 1 {can't read "x": no such variable} 0 {}}
+test trace-14.9 {unsets during write traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) w {traceUnset y(0)}
+ lappend info [catch {set y(0) xxx} msg] $msg
+} {0 {} 1 {can't read "x": no such variable} 0 {}}
+test trace-14.10 {unsets during write traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) w {traceUnset y}
+ lappend info [catch {set y(0) xxx} msg] $msg
+} {0 {} 1 {can't read "x": no such variable} 0 {}}
+test trace-14.11 {unsets during write traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y w {traceReset y y}
+ lappend info [catch {set y xxx} msg] $msg
+} {0 {} 0 xyzzy 0 xyzzy}
+test trace-14.12 {unsets during write traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) w {traceReset y(0) y(0)}
+ lappend info [catch {set y(0) xxx} msg] $msg
+} {0 {} 0 xyzzy 0 xyzzy}
+test trace-14.13 {unsets during write traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) w {traceReset y y(0)}
+ lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 1 {can't set "y": upvar refers to element in deleted array} 0 {} 1 {can't read "y(0)": no such variable}}
+test trace-14.14 {unsets during write traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) w {traceReset2 y y(0)}
+ lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 0 xyzzy 0 {} 0 xyzzy}
+test trace-14.15 {unsets during unset traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y u {traceUnset y}
+ lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg
+} {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y": no such variable}}
+test trace-14.16 {unsets during unset traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) u {traceUnset y(0)}
+ lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such element in array}}
+test trace-14.17 {unsets during unset traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) u {traceUnset y}
+ lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such variable}}
+test trace-14.18 {unsets during unset traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y u {traceReset2 y y}
+ lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg
+} {1 {can't unset "y": no such variable} 0 xyzzy 0 {} 0 xyzzy}
+test trace-14.19 {unsets during unset traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) u {traceReset2 y(0) y(0)}
+ lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {1 {can't unset "y(0)": no such element in array} 0 xyzzy 0 {} 0 xyzzy}
+test trace-14.20 {unsets during unset traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) u {traceReset2 y y(0)}
+ lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
+} {0 {} 0 xyzzy 0 {} 0 xyzzy}
+test trace-14.21 {unsets cancelling traces} {
+ catch {unset y}
+ set y 1234
+ set info {}
+ trace var y r {traceAppend first}
+ trace var y r {traceUnset y}
+ trace var y r {traceAppend third}
+ trace var y u {traceAppend unset}
+ lappend info [catch {set y} msg] $msg
+} {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}}
+test trace-14.22 {unsets cancelling traces} {
+ catch {unset y}
+ set y(0) 1234
+ set info {}
+ trace var y(0) r {traceAppend first}
+ trace var y(0) r {traceUnset y}
+ trace var y(0) r {traceAppend third}
+ trace var y(0) u {traceAppend unset}
+ lappend info [catch {set y(0)} msg] $msg
+} {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}}
+
+# Check various non-interference between traces and other things.
+
+test trace-15.1 {trace doesn't prevent unset errors} {
+ catch {unset x}
+ set info {}
+ trace var x u {traceProc}
+ list [catch {unset x} msg] $msg $info
+} {1 {can't unset "x": no such variable} {x {} u}}
+test trace-15.2 {traced variables must survive procedure exits} {
+ catch {unset x}
+ proc p1 {} {global x; trace var x w traceProc}
+ p1
+ trace vinfo x
+} {{w traceProc}}
+test trace-15.3 {traced variables must survive procedure exits} {
+ catch {unset x}
+ set info {}
+ proc p1 {} {global x; trace var x w traceProc}
+ p1
+ set x 44
+ set info
+} {x {} w}
+
+# Be sure that procedure frames are released before unset traces
+# are invoked.
+
+test trace-16.1 {unset traces on procedure returns} {
+ proc p1 {x y} {set a 44; p2 14}
+ proc p2 {z} {trace var z u {traceCheck {lsort [uplevel {info vars}]}}}
+ set info {}
+ p1 foo bar
+ set info
+} {0 {a x y}}
+
+# Delete arrays when done, so they can be re-used as scalars
+# elsewhere.
+
+catch {unset x}
+catch {unset y}
+concat {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/unknown.test b/vendor/x11iraf/obm/Tcl/tests/unknown.test
new file mode 100644
index 00000000..e80258af
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/unknown.test
@@ -0,0 +1,73 @@
+# Commands covered: unknown
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/unknown.test,v 1.7 93/10/11 09:06:00 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+catch {rename unknown {}}
+
+test unknown-1.1 {non-existent "unknown" command} {
+ list [catch {_non-existent_ foo bar} msg] $msg
+} {1 {invalid command name: "_non-existent_"}}
+
+proc unknown {args} {
+ global x
+ set x $args
+}
+
+test unknown-2.1 {calling "unknown" command} {
+ foobar x y z
+ set x
+} {foobar x y z}
+test unknown-2.2 {calling "unknown" command with lots of args} {
+ foobar 1 2 3 4 5 6 7
+ set x
+} {foobar 1 2 3 4 5 6 7}
+test unknown-2.3 {calling "unknown" command with lots of args} {
+ foobar 1 2 3 4 5 6 7 8
+ set x
+} {foobar 1 2 3 4 5 6 7 8}
+test unknown-2.4 {calling "unknown" command with lots of args} {
+ foobar 1 2 3 4 5 6 7 8 9
+ set x
+} {foobar 1 2 3 4 5 6 7 8 9}
+
+test unknown-3.1 {argument quoting in calls to "unknown"} {
+ foobar \{ \} a\{b \; "\\" \$a a\[b \]
+ set x
+} "foobar \\{ \\} a\\{b {;} \\\\ {\$a} {a\[b} \\]"
+
+proc unknown args {
+ error "unknown failed"
+}
+
+test unknown-4.1 {errors in "unknown" procedure} {
+ list [catch {non-existent a b} msg] $msg $errorCode
+} {1 {unknown failed} NONE}
+
+catch {rename unknown {}}
+return {}
diff --git a/vendor/x11iraf/obm/Tcl/tests/uplevel.test b/vendor/x11iraf/obm/Tcl/tests/uplevel.test
new file mode 100644
index 00000000..675cb335
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/uplevel.test
@@ -0,0 +1,123 @@
+# Commands covered: uplevel
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/uplevel.test,v 1.11 93/07/17 14:38:22 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+proc a {x y} {
+ newset z [expr $x+$y]
+ return $z
+}
+proc newset {name value} {
+ uplevel set $name $value
+ uplevel 1 {uplevel 1 {set xyz 22}}
+}
+
+test uplevel-1.1 {simple operation} {
+ set xyz 0
+ a 22 33
+} 55
+test uplevel-1.2 {command is another uplevel command} {
+ set xyz 0
+ a 22 33
+ set xyz
+} 22
+
+proc a1 {} {
+ b1
+ global a a1
+ set a $x
+ set a1 $y
+}
+proc b1 {} {
+ c1
+ global b b1
+ set b $x
+ set b1 $y
+}
+proc c1 {} {
+ uplevel 1 set x 111
+ uplevel #2 set y 222
+ uplevel 2 set x 333
+ uplevel #1 set y 444
+ uplevel 3 set x 555
+ uplevel #0 set y 666
+}
+a1
+test uplevel-2.1 {relative and absolute uplevel} {set a} 333
+test uplevel-2.2 {relative and absolute uplevel} {set a1} 444
+test uplevel-2.3 {relative and absolute uplevel} {set b} 111
+test uplevel-2.4 {relative and absolute uplevel} {set b1} 222
+test uplevel-2.5 {relative and absolute uplevel} {set x} 555
+test uplevel-2.6 {relative and absolute uplevel} {set y} 666
+
+test uplevel-3.1 {uplevel to same level} {
+ set x 33
+ uplevel #0 set x 44
+ set x
+} 44
+test uplevel-3.2 {uplevel to same level} {
+ set x 33
+ uplevel 0 set x
+} 33
+test uplevel-3.3 {uplevel to same level} {
+ set y xxx
+ proc a1 {} {set y 55; uplevel 0 set y 66; return $y}
+ a1
+} 66
+test uplevel-3.4 {uplevel to same level} {
+ set y zzz
+ proc a1 {} {set y 55; uplevel #1 set y}
+ a1
+} 55
+
+test uplevel-4.1 {error: non-existent level} {
+ list [catch c1 msg] $msg
+} {1 {bad level "#2"}}
+test uplevel-4.2 {error: non-existent level} {
+ proc c2 {} {uplevel 3 {set a b}}
+ list [catch c2 msg] $msg
+} {1 {bad level "3"}}
+test uplevel-4.3 {error: not enough args} {
+ list [catch uplevel msg] $msg
+} {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}}
+test uplevel-4.4 {error: not enough args} {
+ proc upBug {} {uplevel 1}
+ list [catch upBug msg] $msg
+} {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}}
+
+proc a2 {} {
+ uplevel a3
+}
+proc a3 {} {
+ global x y
+ set x [info level]
+ set y [info level 1]
+}
+a2
+test uplevel-5.1 {info level} {set x} 1
+test uplevel-5.2 {info level} {set y} a3
diff --git a/vendor/x11iraf/obm/Tcl/tests/upvar.test b/vendor/x11iraf/obm/Tcl/tests/upvar.test
new file mode 100644
index 00000000..bfef720c
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/upvar.test
@@ -0,0 +1,303 @@
+# Commands covered: upvar
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/upvar.test,v 1.4 93/07/17 14:38:10 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test upvar-1.1 {reading variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2}
+ proc p2 {} {upvar a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a}
+ p1 foo bar
+} {foo bar 22 33 abc}
+test upvar-1.2 {reading variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2}
+ proc p2 {} {p3}
+ proc p3 {} {upvar 2 a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a}
+ p1 foo bar
+} {foo bar 22 33 abc}
+test upvar-1.3 {reading variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2}
+ proc p2 {} {p3}
+ proc p3 {} {
+ upvar #1 a x1 b x2 c x3 d x4
+ set a abc
+ list $x1 $x2 $x3 $x4 $a
+ }
+ p1 foo bar
+} {foo bar 22 33 abc}
+test upvar-1.4 {reading variables with upvar} {
+ set x1 44
+ set x2 55
+ proc p1 {} {p2}
+ proc p2 {} {
+ upvar 2 x1 x1 x2 a
+ upvar #0 x1 b
+ set c $b
+ incr b 3
+ list $x1 $a $b
+ }
+ p1
+} {47 55 47}
+test upvar-1.4 {reading array elements with upvar} {
+ proc p1 {} {set a(0) zeroth; set a(1) first; p2}
+ proc p2 {} {upvar a(0) x; set x}
+ p1
+} {zeroth}
+
+test upvar-2.1 {writing variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d}
+ proc p2 {} {
+ upvar a x1 b x2 c x3 d x4
+ set x1 14
+ set x4 88
+ }
+ p1 foo bar
+} {14 bar 22 88}
+test upvar-2.2 {writing variables with upvar} {
+ set x1 44
+ set x2 55
+ proc p1 {x1 x2} {
+ upvar #0 x1 a
+ upvar x2 b
+ set a $x1
+ set b $x2
+ }
+ p1 newbits morebits
+ list $x1 $x2
+} {newbits morebits}
+test upvar-2.3 {writing variables with upvar} {
+ catch {unset x1}
+ catch {unset x2}
+ proc p1 {x1 x2} {
+ upvar #0 x1 a
+ upvar x2 b
+ set a $x1
+ set b $x2
+ }
+ p1 newbits morebits
+ list [catch {set x1} msg] $msg [catch {set x2} msg] $msg
+} {0 newbits 0 morebits}
+test upvar-2.4 {writing array elements with upvar} {
+ proc p1 {} {set a(0) zeroth; set a(1) first; list [p2] $a(0)}
+ proc p2 {} {upvar a(0) x; set x xyzzy}
+ p1
+} {xyzzy xyzzy}
+
+test upvar-3.1 {unsetting variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]}
+ proc p2 {} {
+ upvar 1 a x1 d x2
+ unset x1 x2
+ }
+ p1 foo bar
+} {b c}
+test upvar-3.2 {unsetting variables with upvar} {
+ proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]}
+ proc p2 {} {
+ upvar 1 a x1 d x2
+ unset x1 x2
+ set x2 28
+ }
+ p1 foo bar
+} {b c d}
+test upvar-3.3 {unsetting variables with upvar} {
+ set x1 44
+ set x2 55
+ proc p1 {} {p2}
+ proc p2 {} {
+ upvar 2 x1 a
+ upvar #0 x2 b
+ unset a b
+ }
+ p1
+ list [info exists x1] [info exists x2]
+} {0 0}
+test upvar-3.4 {unsetting variables with upvar} {
+ set x1 44
+ set x2 55
+ proc p1 {} {
+ upvar x1 a x2 b
+ unset a b
+ set b 118
+ }
+ p1
+ list [info exists x1] [catch {set x2} msg] $msg
+} {0 0 118}
+test upvar-3.5 {unsetting array elements with upvar} {
+ proc p1 {} {
+ set a(0) zeroth
+ set a(1) first
+ set a(2) second
+ p2
+ array names a
+ }
+ proc p2 {} {upvar a(0) x; unset x}
+ p1
+} {1 2}
+test upvar-3.6 {unsetting then resetting array elements with upvar} {
+ proc p1 {} {
+ set a(0) zeroth
+ set a(1) first
+ set a(2) second
+ p2
+ list [array names a] [catch {set a(0)} msg] $msg
+ }
+ proc p2 {} {upvar a(0) x; unset x; set x 12345}
+ p1
+} {{0 1 2} 0 12345}
+
+test upvar-4.1 {nested upvars} {
+ set x1 88
+ proc p1 {a b} {set c 22; set d 33; p2}
+ proc p2 {} {global x1; upvar c x2; p3}
+ proc p3 {} {
+ upvar x1 a x2 b
+ list $a $b
+ }
+ p1 14 15
+} {88 22}
+test upvar-4.2 {nested upvars} {
+ set x1 88
+ proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d}
+ proc p2 {} {global x1; upvar c x2; p3}
+ proc p3 {} {
+ upvar x1 a x2 b
+ set a foo
+ set b bar
+ }
+ list [p1 14 15] $x1
+} {{14 15 bar 33} foo}
+
+proc tproc {args} {global x; set x [list $args [uplevel info vars]]}
+test upvar-5.1 {traces involving upvars} {
+ proc p1 {a b} {set c 22; set d 33; trace var c rw tproc; p2}
+ proc p2 {} {upvar c x1; set x1 22}
+ set x ---
+ p1 foo bar
+ set x
+} {{x1 {} w} x1}
+test upvar-5.2 {traces involving upvars} {
+ proc p1 {a b} {set c 22; set d 33; trace var c rw tproc; p2}
+ proc p2 {} {upvar c x1; set x1}
+ set x ---
+ p1 foo bar
+ set x
+} {{x1 {} r} x1}
+test upvar-5.3 {traces involving upvars} {
+ proc p1 {a b} {set c 22; set d 33; trace var c rwu tproc; p2}
+ proc p2 {} {upvar c x1; unset x1}
+ set x ---
+ p1 foo bar
+ set x
+} {{x1 {} u} x1}
+
+test upvar-6.1 {retargeting an upvar} {
+ proc p1 {} {
+ set a(0) zeroth
+ set a(1) first
+ set a(2) second
+ p2
+ }
+ proc p2 {} {
+ upvar a x
+ set result {}
+ foreach i [array names x] {
+ upvar a($i) x
+ lappend result $x
+ }
+ lsort $result
+ }
+ p1
+} {first second zeroth}
+test upvar-6.2 {retargeting an upvar} {
+ set x 44
+ set y abcde
+ proc p1 {} {
+ global x
+ set result $x
+ upvar y x
+ lappend result $x
+ }
+ p1
+} {44 abcde}
+test upvar-6.3 {retargeting an upvar} {
+ set x 44
+ set y abcde
+ proc p1 {} {
+ upvar y x
+ lappend result $x
+ global x
+ lappend result $x
+ }
+ p1
+} {abcde 44}
+
+test upvar-7.1 {upvar to same level} {
+ set x 44
+ set y 55
+ catch {unset uv}
+ upvar #0 x uv
+ set uv abc
+ upvar 0 y uv
+ set uv xyzzy
+ list $x $y
+} {abc xyzzy}
+test upvar-7.2 {upvar to same level} {
+ set x 1234
+ set y 4567
+ proc p1 {x y} {
+ upvar 0 x uv
+ set uv $y
+ return "$x $y"
+ }
+ p1 44 89
+} {89 89}
+test upvar-7.3 {upvar to same level} {
+ set x 1234
+ set y 4567
+ proc p1 {x y} {
+ upvar #1 x uv
+ set uv $y
+ return "$x $y"
+ }
+ p1 xyz abc
+} {abc abc}
+
+test upvar-8.1 {errors in upvar command} {
+ list [catch upvar msg] $msg
+} {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}}
+test upvar-8.2 {errors in upvar command} {
+ list [catch {upvar 1} msg] $msg
+} {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}}
+test upvar-8.3 {errors in upvar command} {
+ proc p1 {} {upvar a b c}
+ list [catch p1 msg] $msg
+} {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}}
+test upvar-8.4 {errors in upvar command} {
+ proc p1 {} {set a 33; upvar b a}
+ list [catch p1 msg] $msg
+} {1 {variable "a" already exists}}
diff --git a/vendor/x11iraf/obm/Tcl/tests/while.test b/vendor/x11iraf/obm/Tcl/tests/while.test
new file mode 100644
index 00000000..48a08e19
--- /dev/null
+++ b/vendor/x11iraf/obm/Tcl/tests/while.test
@@ -0,0 +1,113 @@
+# Commands covered: while
+#
+# This file contains a collection of tests for one or more of the Tcl
+# built-in commands. Sourcing this file into Tcl runs the tests and
+# generates output for errors. No output means no errors were found.
+#
+# Copyright (c) 1991-1993 The Regents of the University of California.
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+#
+# $Header: /user6/ouster/tcl/tests/RCS/while.test,v 1.7 93/04/21 11:18:58 ouster Exp $ (Berkeley)
+
+if {[string compare test [info procs test]] == 1} then {source defs}
+
+test while-1.1 {basic while loops} {
+ set count 0
+ while {$count < 10} {set count [expr $count+1]}
+ set count
+} 10
+test while-1.2 {basic while loops} {
+ set value xxx
+ while {2 > 3} {set value yyy}
+ set value
+} xxx
+test while-1.3 {basic while loops} {
+ set value 1
+ while {"true"} {
+ incr value;
+ if {$value > 5} {
+ break;
+ }
+ }
+ set value
+} 6
+
+test while-2.1 {continue in while loop} {
+ set list {1 2 3 4 5}
+ set index 0
+ set result {}
+ while {$index < 5} {
+ if {$index == 2} {set index [expr $index+1]; continue}
+ set result [concat $result [lindex $list $index]]
+ set index [expr $index+1]
+ }
+ set result
+} {1 2 4 5}
+
+test while-3.1 {break in while loop} {
+ set list {1 2 3 4 5}
+ set index 0
+ set result {}
+ while {$index < 5} {
+ if {$index == 3} break
+ set result [concat $result [lindex $list $index]]
+ set index [expr $index+1]
+ }
+ set result
+} {1 2 3}
+
+test while-4.1 {errors in while loops} {
+ set err [catch {while} msg]
+ list $err $msg
+} {1 {wrong # args: should be "while test command"}}
+test while-4.2 {errors in while loops} {
+ set err [catch {while 1} msg]
+ list $err $msg
+} {1 {wrong # args: should be "while test command"}}
+test while-4.3 {errors in while loops} {
+ set err [catch {while 1 2 3} msg]
+ list $err $msg
+} {1 {wrong # args: should be "while test command"}}
+test while-4.4 {errors in while loops} {
+ set err [catch {while {"a"+"b"} {error "loop aborted"}} msg]
+ list $err $msg
+} {1 {can't use non-numeric string as operand of "+"}}
+test while-4.5 {errors in while loops} {
+ set x 1
+ set err [catch {while {$x} {set x foo}} msg]
+ list $err $msg
+} {1 {expected boolean value but got "foo"}}
+test while-4.6 {errors in while loops} {
+ set err [catch {while {1} {error "loop aborted"}} msg]
+ list $err $msg $errorInfo
+} {1 {loop aborted} {loop aborted
+ while executing
+"error "loop aborted""
+ ("while" body line 1)
+ invoked from within
+"while {1} {error "loop aborted"}"}}
+
+test while-5.1 {while return result} {
+ while {0} {set a 400}
+} {}
+test while-5.2 {while return result} {
+ set x 1
+ while {$x} {set x 0}
+} {}
diff --git a/vendor/x11iraf/obm/client.c b/vendor/x11iraf/obm/client.c
new file mode 100644
index 00000000..32277572
--- /dev/null
+++ b/vendor/x11iraf/obm/client.c
@@ -0,0 +1,253 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+
+
+/*
+ * CLIENT class.
+ * --------------------------
+ * The client is the client application, which provides the functionality
+ * underlying the UI. When a message is sent to the client object it usually
+ * results in a message being sent to the client *application*, usually an
+ * external program communicating via IPC, which has little or no knowledge
+ * of the UI. The client application receives and executes commands delivered
+ * by the UI via the client object. Output from the client may or may not
+ * come back to the object manager. That portion of the output which comes
+ * back to the object manager is in the form of assignments of string values
+ * to UI parameter-class objects (another way of thinking of this is that
+ * messages or events are sent to and acted upon by the parameter objects).
+ * Hence, the client object is output only so far as the client application
+ * is concerned.
+ *
+ * The Client-class commands are used to send a message to the client.
+ *
+ * gkey <key>
+ * gcmd <command-string>
+ * literal <command>
+ *
+ * or just <command>, e.g., "send client <command>" will work in most cases.
+ *
+ * GKEY sends and IRAF graphics keystroke. GCMD sends and IRAF graphics
+ * colon command. LITERAL sends a literal command string to the client.
+ * The keyword "literal" may optionally be omitted, i.e., "send client foo"
+ * and "send client literal foo" are the same. The keyword "literal" may
+ * be used to ensure that the client command string which follows will not
+ * be interpreted as a Client-class command (such as gkey, gcmd, or literal).
+ */
+
+struct clientPrivate {
+ ObmContext obm;
+ Tcl_Interp *tcl;
+};
+
+typedef struct clientPrivate *ClientPrivate;
+
+struct clientObject {
+ struct obmObjectCore core;
+ struct clientPrivate client;
+};
+
+typedef struct clientObject *ClientObject;
+
+static void ClientDestroy();
+static int ClientEvaluate();
+static ObmObject ClientCreate();
+static int clientGcmd(), clientGkey(), clientLiteral();
+static int client_output();
+
+
+/* ClientClassInit -- Initialize the class record for the client class.
+ */
+void
+ClientClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ classrec->ClassDestroy = obmGenericClassDestroy;
+ classrec->Create = (ObmFunc) ClientCreate;
+ classrec->Destroy = ClientDestroy;
+ classrec->Evaluate = ClientEvaluate;
+}
+
+
+/* ClientCreate -- Create an instance of a client object.
+ */
+static ObmObject
+ClientCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register ClientObject obj;
+ register Tcl_Interp *tcl;
+
+ obj = (ClientObject) XtCalloc (1, sizeof (struct clientObject));
+ obj->client.tcl = tcl = Tcl_CreateInterp();
+ obj->client.obm = obm;
+
+ /* Register client-object actions. */
+ Tcl_CreateCommand (tcl,
+ "gcmd", clientGcmd, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "gkey", clientGkey, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "literal", clientLiteral, (ClientData)obj, NULL);
+
+ return ((ObmObject) obj);
+}
+
+
+/* ClientDestroy -- Destroy an instance of a client object.
+ */
+static void
+ClientDestroy (object)
+ObmObject object;
+{
+ register ClientObject obj = (ClientObject) object;
+
+ if (obj->core.being_destroyed++)
+ Tcl_DeleteInterp (obj->client.tcl);
+}
+
+
+/* ClientEvaluate -- Evaluate a client command or message.
+ */
+static int
+ClientEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register ClientObject obj = (ClientObject) object;
+ register Tcl_Interp *tcl = obj->client.tcl;
+ int status, argc, i;
+ char *argv[MAX_ARGS];
+ char **argvp;
+
+ if (!obmClientCommand (tcl, command))
+ goto literal;
+
+ /* If the command is unrecognized pass it on to the client as a
+ * literal to be processed by the client.
+ */
+ if ((status = Tcl_Eval (tcl, command)) != TCL_OK) {
+literal: if (Tcl_SplitList (tcl, command, &argc, &argvp) == TCL_OK) {
+ argv[0] = "literal";
+ if (argc > MAX_ARGS)
+ argc = MAX_ARGS;
+ for (i=0; i <= argc; i++)
+ argv[i+1] = argvp[i];
+
+ status = clientLiteral (object, tcl, argc + 1, argv);
+ free ((char *) argvp);
+ }
+ }
+
+ return (status);
+}
+
+
+/* clientGcmd -- Send a graphics command string to the client application.
+ * A graphics command string is a graphics cursor value with the key set
+ * to `:' and the command string given as the string part of the cursor
+ * value. The protocol module which posted the client output procedure is
+ * responsible for encoding and sending the cursor command.
+ *
+ * Usage: gcmd <command-string>
+ */
+static int
+clientGcmd (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ClientObject obj = (ClientObject) object;
+ register ObmContext obm = obj->client.obm;
+ int stat;
+
+ if (argc >= 2) {
+ char *message = Tcl_Concat (argc-1, &argv[1]);
+ stat = client_output (obm, obj->core.name, ':', message);
+ free ((char *)message);
+ } else
+ stat = -1;
+
+ return (stat < 0 ? TCL_ERROR : TCL_OK);
+}
+
+
+/* clientGkey -- Send a graphics key event to the client application.
+ * A graphics key event is a graphics cursor value with the key set to some
+ * integer value and a null string part.
+ *
+ * Usage: gkey <key>
+ */
+static int
+clientGkey (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ClientObject obj = (ClientObject) object;
+ register ObmContext obm = obj->client.obm;
+ int stat;
+
+ if (argc >= 2)
+ stat = client_output (obm, obj->core.name, *argv[1], "");
+ else
+ stat = -1;
+
+ return (stat < 0 ? TCL_ERROR : TCL_OK);
+}
+
+
+/* clientLiteral -- Send a literal command to the client application.
+ *
+ * Usage: literal <command>
+ */
+static int
+clientLiteral (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ClientObject obj = (ClientObject) object;
+ register ObmContext obm = obj->client.obm;
+ int stat;
+
+ if (argc >= 2) {
+ char *message = Tcl_Concat (argc-1, &argv[1]);
+ stat = client_output (obm, obj->core.name, 0, message);
+ free ((char *)message);
+ } else
+ stat = -1;
+
+ return (stat < 0 ? TCL_ERROR : TCL_OK);
+}
+
+
+/* client_output -- Call the client output callbacks if any.
+ */
+static int
+client_output (obm, objname, key, strval)
+register ObmContext obm;
+char *objname;
+int key;
+char *strval;
+{
+ register ObmCallback cb;
+ register int stat = 0;
+
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & OBMCB_clientOutput) && cb->u.fcn)
+ stat |= ((*cb->u.fcn) (cb->client_data, obm->tcl,
+ objname, key, strval));
+
+ return (stat != 0);
+}
diff --git a/vendor/x11iraf/obm/docs/gui.doc/TclQuickRef.html b/vendor/x11iraf/obm/docs/gui.doc/TclQuickRef.html
new file mode 100644
index 00000000..3f41eb29
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/TclQuickRef.html
@@ -0,0 +1,208 @@
+<title>Tcl Quick Reference</title>
+
+
+<H1><pre>TCL Quick Reference
+Based on TCL version 6.4
+Jeff Tranter 12-Aug-1992</pre><h1>
+
+
+<pre>
+Basic Language Features
+
+# comment (continues to end of line)
+" " allows embedding whitespace in arguments; substitutions made
+{ } group arguments; substitutions not made
+[ ] command substitution; replace with result of command
+$var variable substitution
+; command separator
+
+
+Backslash Substitution
+
+\b backspace
+\[ open bracket
+\f form feed
+\] close bracket
+\n newline
+\$ dollar sign
+\r carriage return
+\<space> space
+\t tab
+\; semi-colon
+\v vertical tab
+\" double-quote
+\{ left brace
+\<newln> newline
+\} right brace
+\\ backslash
+\ddd octal digits
+
+
+Built-in Variables
+
+env
+errorCode
+errorInfo
+
+
+Operators (in decreasing order of precedence)
+
+- ~ ! unary minus, bit-wise NOT, logical NOT
+* / % multiply, divide, remainder
++ - add, subtract
+<< >> left and right shift
+< > <= >= boolean comparisons
+== != boolean equal, not equa
+& bit-wise AND
+^ bit-wise exclusive OR
+| bit-wise inclusive OR
+&& logical AND
+|| logical OR
+x?y:z conditional operator
+
+All operators support integers.
+All support floating point except ~, %, <<, >>, &, ^, and |
+Boolean operators can also be used on strings.
+
+
+Regular Expressions
+regex | regex match either expression
+regex* match zero or more of regex
+regex+ match one or more of regex
+regex? match zero or one of regex
+. any single character (except newline)
+^ match beginning of line
+$ match end of line
+\c match character c
+c match character c
+[] match set of characters
+[a-z] match range of characters
+[^] match characters not in range or set
+() group expressions
+
+
+Keywords
+
+append varName value [value value ...]
+array anymore arrayName searchId
+array donesearch arrayName searchId
+array names arrayName
+array nextelement arrayName searchId
+array size arrayName
+array startsearch arrayName
+break
+case string [in] patList body [patList body ...]
+case string [in] {patList body [patList body ...]
+catch command [varName]
+cd [dirName]
+close fileId
+concat arg [arg ...]
+continue
+error message [info] [code]
+eof fileId
+error $errMsg $savedInfo
+eval arg [arg ...]
+exec arg [arg ...]
+exit [returnCode]
+expr arg
+file atime name
+file dirname name
+file executable name
+file exists name
+file extension name
+file isdirectory name
+file isfile name
+file lstat name varName
+file mtime name
+file owned name
+file readable name
+file readlink name
+file rootname name
+file size name
+file stat name varName
+file tail name
+file type name
+file writable name
+flush fileId
+for start test next body
+foreach varname list body
+format formatString [arg arg ...]
+gets fileId [varName]
+glob [-nocomplain] filename [filename ...]
+global varname [varname ...]
+history
+history add command [exec]
+history change newValue [event]
+history event [event]
+history info [count]
+history keep count
+history nextid
+history redo [event]
+history substitute old new [event]
+history words selector [event]
+if test [then] trueBody [else] [falseBody]
+incr varName [increment]
+info args procname
+info body procname
+info cmdcount
+info commands [pattern]
+info default procname arg varname
+into variable varname
+info exists varName
+info globals [pattern]
+info level [number]
+info library
+info locals [pattern]
+info procs [pattern]
+info script
+info tclversion
+info vars [pattern]
+join list [joinString]
+lappend varName value [value value ...]
+lindex list index
+linsert list index element [element element ...]
+list arg [arg ...]
+llength list
+lrange list first last
+lreplace list first last [element element ...]
+lsearch list pattern
+lsort list
+open fileName [access]
+proc name args body
+puts fileId string [nonewline]
+pwd
+read fileId
+read fileId nonewline
+read fileId numBytes
+regexp [-indices] [-nocase] exp string [matchVar] [subMatchVar subMatchVar ...]
+regsub [-all] [-nocase] exp string subSpec varName
+rename oldName newName
+return [value]
+scan string format varname1 [varname2 ...]
+seek fileId offset [origin]
+set varname [value]
+source fileName
+split string [splitChars]
+string compare string1 string2
+string first string1 string2
+string index string charIndex
+string last string1 string2
+string length string
+string match pattern string
+string range string first last
+string tolower string
+string toupper string
+string trim string [chars]
+string trimleft string [chars]
+string trimright string [chars]
+tell fileId
+time command [count]
+trace variable name ops command
+trace vdelete name ops command
+trace vinfo name
+unknown cmdName [arg arg ...]
+unset name [name name ...]
+uplevel [level] command [command ...]
+upvar [level] otherVar myVar [otherVar myVar ...]
+while test body
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/alphabetic.html b/vendor/x11iraf/obm/docs/gui.doc/alphabetic.html
new file mode 100644
index 00000000..0c141617
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/alphabetic.html
@@ -0,0 +1,39 @@
+<title>Alphabetized list of GUI commands</title>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<pre>
+<a href="gtermclass.html#activate">activate</a> <a href="servercom.html#activate">activate</a> <a href="notyet.html">activeMapping</a> <a href="gmc.html#addCallback">addCallback</a> <a href="gtermclass.html#addCallback">addCallback</a>
+<a href="uiparameterclass.html#addCallback">addCallback</a> <a href="widgetclass.html#addCallback">addCallback</a> <a href="widgetclass.html#addEventHandler">addEventHandler</a> <a href="widgetclass.html#append">append</a> <a href="servercom.html#appInitialize">appInitialize</a>
+<a href="notyet.html">assignRaster</a> <a href="gtermclass.html#bell">bell</a> <a href="widgetclass.html#do_userproc">call</a> <a href="gtermclass.html#clearScreen">clearScreen</a> <a href="widgetclass.html#configure">configure</a>
+<a href="notyet.html">copyPixmap</a> <a href="notyet.html">copyRaster</a> <a href="servercom.html#createBitmap">createBitmap</a> <a href="servercom.html#createCursor">createCursor</a> <a href="gtermclass.html#createMarker">createMarker</a>
+<a href="servercom.html#createMenu">createMenu</a> <a href="servercom.html#createObjects">createObjects</a> <a href="notyet.html">createPixmap</a> <a href="servercom.html#createPixmap">createPixmap</a> <a href="notyet.html">createRaster</a>
+<a href="gtermclass.html#deactivate">deactivate</a> <a href="servercom.html#deactivate">deactivate</a> <a href="uiparameterclass.html#deleteCallback">deleteCallback</a> <a href="widgetclass.html#deleteCallback">deleteCallback</a> <a href="servercom.html#deleteTimedCallback">deleteTimedCallback</a>
+<a href="servercom.html#deleteWorkCallback">deleteWorkCallback</a> <a href="gmc.html#destroy">destroy</a> <a href="servercom.html#destroyMenu">destroyMenu</a> <a href="servercom.html#destroyObject">destroyObject</a>
+<a href="notyet.html">destroyRaster</a> <a href="notyet.html">disableMapping</a> <a href="notyet.html">drawAlphaText</a> <a href="notyet.html">drawDialogText</a> <a href="notyet.html">drawMarker</a>
+<a href="notyet.html">drawPolygon</a> <a href="notyet.html">drawPolyline</a> <a href="notyet.html">drawPolymarker</a> <a href="servercom.html#createMenu">editMenu</a> <a href="notyet.html">enableMapping</a>
+<a href="ximclient.html#encodewcs">encodewcs</a> <a href="notyet.html">endDialog</a> <a href="notyet.html">eraseDialog</a> <a href="ximclient.html#fitFrame">fitFrame</a> <a href="gtermclass.html#flip">flip</a>
+<a href="ximclient.html#flip">flip</a> <a href="gtermclass.html#flush">flush</a> <a href="notyet.html">freeColormap</a> <a href="notyet.html">freeMapping</a> <a href="clientclass.html#gcmd">gcmd</a>
+<a href="gmc.html#getAttribute">get</a> <a href="widgetclass.html#get">get</a> <a href="notyet.html">getAlphaTextSize</a> <a href="gmc.html#getAttribute">getAttribute</a>
+<a href="gmc.html#getAttributes">getAttributes</a> <a href="gtermclass.html#getCursorPos">getCursorPos</a> <a href="notyet.html">getDialogTextSize</a> <a href="ximclient.html#getFrame">getFrame</a>
+<a href="widgetclass.html#getItem">getItem</a> <a href="notyet.html">getLogRes</a> <a href="gtermclass.html#getMapping">getMapping</a> <a href="notyet.html">getPhysRes</a> <a href="gtermclass.html#getPixel">getPixel</a>
+<a href="gtermclass.html#getRaster">getRaster</a> <a href="gmc.html#getRect">getRect</a> <a href="gmc.html#getRegion">getRegion</a> <a href="servercom.html#getResource">getResource</a> <a href="servercom.html#getResources">getResources</a>
+<a href="uiparameterclass.html#getValue">getValue</a> <a href="gmc.html#getVertices">getVertices</a> <a href="clientclass.html#gkey">gkey</a> <a href="widgetclass.html#highlight">highlight</a> <a href="notyet.html">initMappings</a>
+<a href="widgetclass.html#isRealized">isRealized</a> <a href="widgetclass.html#isSensitive">isSensitive</a> <a href="clientclass.html#literal">literal</a> <a href="gtermclass.html#loadColormap">loadColormap</a> <a href="gmc.html#lower">lower</a>
+<a href="gmc.html#makeCopy">makeCopy</a> <a href="widgetclass.html#manage">manage</a> <a href="widgetclass.html#map">map</a> <a href="gtermclass.html#markerInit">markerInit</a> <a href="gmc.html#markpos">markpos</a>
+<a href="ximclient.html#matchFrames">matchFrames</a> <a href="gmc.html#move">move</a> <a href="widgetclass.html#move">move</a> <a href="notyet.html">nextColormap</a> <a href="ximclient.html#nextFrame">nextFrame</a>
+<a href="gtermclass.html#nextMapping">nextMapping</a> <a href="notyet.html">nextRaster</a> <a href="gmc.html#notify">notify</a> <a href="uiparameterclass.html#notify">notify</a> <a href="notyet.html">nRasters</a>
+<a href="ximclient.html#pan">pan</a> <a href="widgetclass.html#do_popdown">popdown</a> <a href="widgetclass.html#popdown">popdown</a> <a href="widgetclass.html#do_popup">popup</a> <a href="widgetclass.html#popup">popup</a>
+<a href="widgetclass.html#popupSpringLoaded">popupSpringLoaded</a> <a href="servercom.html#postActivateCallback">postActivateCallback</a> <a href="servercom.html#postTimedCallback">postTimedCallback</a>
+<a href="servercom.html#postWorkCallback">postWorkCallback</a> <a href="ximclient.html#prevFrame">prevFrame</a> <a href="servercom.html#print">print</a> <a href="notyet.html">queryRaster</a>
+<a href="ximclient.html#Quit">Quit</a> <a href="gmc.html#raise">raise</a> <a href="gtermclass.html#rasterInit">rasterInit</a> <a href="notyet.html">readColormap</a> <a href="gtermclass.html#readPixels">readPixels</a>
+<a href="widgetclass.html#realize">realize</a> <a href="gmc.html#redraw">redraw</a> <a href="notyet.html">refreshMapping</a> <a href="notyet.html">refreshPixels</a> <a href="servercom.html#resetReset">reset-server</a>
+<a href="gtermclass.html#reset">reset</a> <a href="gmc.html#resize">resize</a> <a href="widgetclass.html#resize">resize</a> <a href="ximclient.html#retCursorVal">retCursorVal</a> <a href="gmc.html#rotate">rotate</a>
+<a href="gtermclass.html#selectRaster">selectRaster</a> <a href="servercom.html#send">send</a> <a href="gmc.html#setAttribute">set</a> <a href="widgetclass.html#set">set</a> <a href="gmc.html#setAttribute">setAttribute</a>
+<a href="gmc.html#setAttributes">setAttributes</a> <a href="notyet.html">setColorIndex</a> <a href="ximclient.html#setColormap">setColormap</a> <a href="gtermclass.html#setCursorPos">setCursorPos</a> <a href="gtermclass.html#setCursorType">setCursorType</a>
+<a href="notyet.html">setDataLevel</a> <a href="notyet.html">setFillType</a> <a href="ximclient.html#setFrame">setFrame</a> <a href="gtermclass.html#setGterm">setGterm</a> <a href="notyet.html">setLineStyle</a>
+<a href="notyet.html">setLineWidth</a> <a href="widgetclass.html#setList">setList</a> <a href="notyet.html">setLogRes</a> <a href="gtermclass.html#setMapping">setMapping</a> <a href="notyet.html">setPhysRes</a>
+<a href="gtermclass.html#setPixel">setPixel</a> <a href="gtermclass.html#setRaster">setRaster</a> <a href="widgetclass.html#setSensitive">setSensitive</a> <a href="notyet.html">setTextRes</a> <a href="uiparameterclass.html#setValue">setValue</a>
+<a href="gmc.html#setVertices">setVertices</a> <a href="notyet.html">startDialog</a> <a href="widgetclass.html#unhighlight">unhighlight</a> <a href="widgetclass.html#unmanage">unmanage</a> <a href="widgetclass.html#unmap">unmap</a>
+<a href="gtermclass.html#unmapPixel">unmapPixel</a> <a href="widgetclass.html#unrealize">unrealize</a> <a href="widgetclass.html#userEventHandler">userEventHandler</a> <a href="ximclient.html#windowColormap">windowColormap</a>
+<a href="notyet.html">writeColormap</a> <a href="gtermclass.html#writePixels">writePixels</a> <a href="ximclient.html#zoom">zoom</a> <a href="ximclient.html#zoom">zoomAbs</a>
+</pre>
+
diff --git a/vendor/x11iraf/obm/docs/gui.doc/athena.gif b/vendor/x11iraf/obm/docs/gui.doc/athena.gif
new file mode 100644
index 00000000..56e74e96
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/athena.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/athena.html b/vendor/x11iraf/obm/docs/gui.doc/athena.html
new file mode 100644
index 00000000..dcd3decf
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/athena.html
@@ -0,0 +1,73 @@
+<title>Athena Widgets</title>
+<h1><IMG SRC="irafgui.gif"> Athena Widgets</h1>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+The Athena widgets were written at MIT. Each of the widget names is a
+hypertext link to a page describing the widget and including an example.
+<p>
+<h2>Simple Widgets</h2>
+<dl>
+<dt><a href="commandwidget.html">Command</a>
+<dd>A push button that, when selected, may cause a specific action
+to take place. This widget can display a multi-line string or a bitmap image.
+<dt><a href="gripwidget.html">Grip</a>
+<dd>A rectangle that, when selected, will cause an action to take
+place.
+<dt><a href="labelwidget.html">Label</a>
+<dd>A rectangle that may contain one or more lines of text or a bitmap image.
+<dt><a href="listwidget.html">List</a>
+<dd>A list of text strings presented in row column format that may be
+individually selected. When an element is selected an action may take place.
+<dt><a href="pannerwidget.html">Panner</a>
+<dd>A rectangular area containing a <i>slider</i> that may be moved in two
+dimensions. Notification of movement may be continuous or discrete.
+<dt><a href="repeaterwidget.html">Repeater</a>
+<dd>A push button that triggers an action at an increasing rate when selected.
+<dt><a href="scrollbarwidget.html">Scrollbar</a>
+<dd>A rectangular area containg a <i>thumb</i> that, when slid along one
+dimension, may cause a specific action to take place. The Scrollbar may
+be oriented horixontall or vertically.
+<dt><a href="simplewidget.html">Simple</a>
+<dd>The vase class for most of the simple widgets. Provides a rectangular
+area with a settable mouse cursor and special border.
+<dt><a href="stripchartwidget.html">StripChart</a>
+<dd>A real time data graph that will automatically update and scroll.
+<dt><a href="togglewidget.html">Toggle</a>
+<dd>A push button [see Command] that contains state information. Toggles
+may also be used as radio buttons to implement a "one of many" group of
+buttons.
+</dl>
+<h2>Text Widgets</h2>
+<dl>
+<dt><a href="textwidget.html">Text</a>
+<dd>Basic text widget supports edit commands.
+<dt><a href="asciitextwidget.html">AsciiText</a>
+<dd>This widget contains a text widget and also includes AsciiSrc and
+and AsciiSink widgets.
+</dl>
+<h2>Composite and Constraint Widgets</h2>
+<dl>
+<dt><a href="boxwidget.html">Box</a>
+<dd>This widget will pack its children as tightly as possible in
+non-overlapping rows.
+<dt><a href="dialogwidget.html">Dialog</a>
+<dd>An implementation of a commonly used interaction semantic to
+prompt for auxiliary input from the user, such as a filename.
+<dt><a href="formwidget.html">Form</a>
+<dd>A more sophisticated layout widget that allows the children to specify
+their positions relative to the other children, or to the edges of the form.
+<dt><a href="panedwidget.html">Paned</a>
+<dd>Allows children to be tiled vertically or horizontally. Controls are also
+provided to allow the user to dynamically resize the individual panes.
+<dt><a href="portholewidget.html">Porthole</a>
+<dd>Allows viewing of a managed child which is as large as, or larger than its
+parent, typically under control of a Panner widget.
+<dt><a href="treewidget.html">Tree</a>
+<dd>Provides geometry management of widgets arranged in a directed, acyclic
+graph.
+<dt><a href="viewportwidget.html">Viewport</a>
+<dd>Consists of a frame, one of two scrollbars, and an inner window. The
+inner window can contain all the data that is to be displayed. This inner
+window will be clipped by the frame with the scrollbars controlling which
+section of the inner window is currently visible.
+</dl>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/blueline.gif b/vendor/x11iraf/obm/docs/gui.doc/blueline.gif
new file mode 100644
index 00000000..d911fe03
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/blueline.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/book.p1.ps.gz b/vendor/x11iraf/obm/docs/gui.doc/book.p1.ps.gz
new file mode 100644
index 00000000..360e4950
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/book.p1.ps.gz
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/clientclass.html b/vendor/x11iraf/obm/docs/gui.doc/clientclass.html
new file mode 100644
index 00000000..407c177b
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/clientclass.html
@@ -0,0 +1,75 @@
+<title>CLIENT class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> CLIENT class</h1>
+<p>
+<HR>
+<p>
+The client is the client application, which provides the functionality
+underlying the UI. When a message is sent to the client object it usually
+results in a message being sent to the client *application*, usually an
+external program communicating via IPC, which has little or no knowledge
+of the UI. The client application receives and executes commands delivered
+by the UI via the client object. Output from the client may or may not
+come back to the object manager. That portion of the output which comes
+back to the object manager is in the form of assignments of string values
+to <a href="uiparameterclass.html">UI parameter-class objects</a> (another
+way of thinking of this is that
+messages or events are sent to and acted upon by the parameter objects).
+Hence, the client object is output only so far as the client application
+is concerned.
+<p>
+The Client-class commands are used to send a message to the client.
+<p>
+<pre>
+ <a href="#gkey">gkey</a> &lt;key&gt;
+ <a href="#gcmd">gcmd</a> &lt;command-string&gt;
+ <a href="#literal">literal</a> &lt;command&gt;
+</pre>
+<p>
+or just &lt;command&gt;, e.g., "send client &lt;command&gt;" will work in most cases.
+<p>
+<a href="#gkey">GKEY</a> sends an IRAF graphics keystroke.
+<a href="#gcmd">GCMD</a> sends an
+IRAF graphics colon command. <a href="#literal">LITERAL</a> sends a literal
+command string to the
+client. The keyword "literal" may optionally be omitted, i.e., "send client
+foo" and "send client literal foo" are the same. The keyword "literal" may
+be used to ensure that the client command string which follows will not
+be interpreted as a Client-class command (such as gkey, gcmd, or literal).
+<p>
+<p>
+<h1><A NAME="gcmd">gcmd</A></h1>
+<p>
+Send a graphics command string to the client application.
+A graphics command string is a graphics cursor value with the key set
+to `:' and the command string given as the string part of the cursor
+value. The protocol module which posted the client output procedure is
+responsible for encoding and sending the cursor command.
+<p>
+Usage:
+<p>
+<pre>
+ gcmd &lt;command-string&gt;
+</pre>
+<p>
+<h1><A NAME="gkey">gkey</A></h1>
+<p>
+Send a graphics key event to the client application.
+A graphics key event is a graphics cursor value with the key set to some
+integer value and a null string part.
+<p>
+Usage:
+<p>
+<pre>
+gkey &lt;key&gt;
+</pre>
+<p>
+<h1><A NAME="literal">literal</A></h1>
+<p>
+Send a literal command to the client application.
+<p>
+Usage:
+<p>
+<pre>
+ literal &lt;command&gt;
+</pre>
+
diff --git a/vendor/x11iraf/obm/docs/gui.doc/coloredline.gif b/vendor/x11iraf/obm/docs/gui.doc/coloredline.gif
new file mode 100644
index 00000000..f08eb184
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/coloredline.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/einstein.html b/vendor/x11iraf/obm/docs/gui.doc/einstein.html
new file mode 100644
index 00000000..1d6e1927
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/einstein.html
@@ -0,0 +1,5 @@
+<title>Einstein</title>
+<p>
+<a href="notyet.html"><IMG align=middle SRC="einstein.gif"></a>
+Yep, that's uncle Albert!
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/example.html b/vendor/x11iraf/obm/docs/gui.doc/example.html
new file mode 100644
index 00000000..40b0b4cd
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/example.html
@@ -0,0 +1,6 @@
+<title>Example: Imbrowse</title>
+<h2><IMG SRC="irafgui.gif"> Example: Imbrowse</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+<a href="exampmap"><IMG SRC="imbrowse.gif" ISMAP></a>
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/exampmap b/vendor/x11iraf/obm/docs/gui.doc/exampmap
new file mode 100644
index 00000000..d2284a37
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/exampmap
@@ -0,0 +1,30 @@
+
+default imbrowsemap/none.html
+
+# The ellipse containing "panel"
+rect imbrowsemap/panel.html 287,19 366,56
+
+# The ellipse containing "objView"
+rect imbrowsemap/objView.html 226,98 312,130
+
+# The ellipse containing "controlForm"
+rect imbrowsemap/controlForm.html 266,154 382,186
+
+# The ellipse containing "headerText"
+rect imbrowsemap/headerText.html 336,96 450,130
+
+# The ellipse containing "sectionBox"
+rect imbrowsemap/sectionBox.html 461,99 577,131
+
+# The ellipse containing "statusBox"
+rect imbrowsemap/statusBox.html 75,158 202,190
+
+# The ellipse containing "dirSelect"
+rect imbrowsemap/dirSelect.html 7,280 95,320
+
+# The ellipse containing "dirName"
+rect imbrowsemap/dirName.html 74,342 167,380
+
+# The ellipse containing "imageButton"
+rect imbrowsemap/imageButton.html 171,280 298,315
+
diff --git a/vendor/x11iraf/obm/docs/gui.doc/gmc.html b/vendor/x11iraf/obm/docs/gui.doc/gmc.html
new file mode 100644
index 00000000..9e124846
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/gmc.html
@@ -0,0 +1,402 @@
+<title>Graphics Marker class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> Graphics Marker class</h1>
+<p>
+<HR>
+<p>
+A marker is a graphics object implemented by the Gterm-Image widget.
+Markers are not real toolkit widgets, but they act much like widgets and
+are interfaced as an object class under the Object Manager. The Marker
+class is not a subclass, it is a base class like Widget, but Marker objects
+can exist only as children of Gterm widgets.
+<p>
+Since markers are not independent widgets but rather part of a Gterm widget
+instance, the parent Gterm widget is partially responsible for managing
+markers. The Gterm widget implements the following commands for dealing
+with markers.
+<p>
+<pre>
+ <a href="gtermclass.html#createMarker">createMarker</a> name [attribute-list]
+ <a href="gtermclass.html#markerInit">markerInit</a>
+</pre>
+<p>
+A new marker is created by sending the createMarker message to the parent
+gterm widget. This creates a marker of the given name and type.
+The markerInit command, if sent to a gterm widget, destroys any markers
+defined for that widget and reinitializes the marker facility. Markers
+may also be created by action procedures in response to user input events.
+<p>
+A marker may be destroyed by itself in response to an input event (e.g. the
+user presses the delete key), by sending the marker the destroy message
+to tell it to destroy itself, by sending a markerInit to the parent gterm
+widget, or by destroying the marker object (or any parent) with the server
+command <a href="servercom.html#destroyObject">destroyObject</a>.
+<p>
+Once a marker has been created it behaves as an independent object and
+receives and executes messages, responds to events, generates callbacks,
+and so on. The marker class defines the following commands.
+<p>
+<pre>
+ <a href="#makeCopy">makeCopy</a> name
+ <a href="#addCallback">addCallback</a> procedure [event [event ...]]
+ <a href="#notify">notify</a> [event-type [param [param ...]]]
+ <a href="#destroy">destroy</a> [nocallback]
+<p>
+ <a href="#markpos">markpos</a>
+ <a href="#redraw">redraw</a> [function] [markpos|nomarkpos] [erase|noerase]
+<p>
+ <a href="#raise">raise</a> [reference-marker]
+ <a href="#lower">lower</a> [reference-marker]
+<p>
+ <a href="#move">move</a> x y
+ <a href="#resize">resize</a> width height
+ <a href="#rotate">rotate</a> angle # radians
+<p>
+ <a href="#setAttribute">set</a> attribute value # alias for setAttribute
+ value = <a href="#getAttribute">get</a> attribute # alias for getAttribute
+<p>
+ <a href="#setAttribute">setAttribute</a> attribute value
+ value = <a href="#getAttribute">getAttribute</a> attribute
+ <a href="#setAttributes">setAttributes</a> attribute-list
+ <a href="#getAttributes">getAttributes</a> attribute-list
+ <a href="#setVertices">setVertices</a> points first npts
+ <a href="#getVertices">getVertices</a> points first npts
+<p>
+ region = <a href="#getRegion">getRegion</a> [unmap] [coord-type]
+ <a href="#getRect">getRect</a> dx dy dnx dny
+</pre>
+<p>
+Marker positions and dimensions are given in window (raster 0) coordinates.
+<p>
+The operators raise, lower, move, resize, and rotate erase the marker,
+modify it as indicated, and redraw it with the new attributes. For finer
+control over marker attributes one can use [get|set]Attribute[s] and
+[get|set]Vertices to edit the markers directly. In this case an auto
+redraw is not performed (unless the autoRedraw marker attribute is set).
+The usual sequence is a markpos to record the marker position, one or more
+setAttribute calls to change marker attributes, then a redraw to erase
+the old marker and redraw the new one. Markers have many attributes which
+can be set to control things like the position and size, colors, line
+widths, fill type and style, font, rubber-band technique, and so on.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker types and attributes.
+<p>
+The marker type may be changed at runtime without destroying the marker.
+For example a circle can be changed to an ellipse or a rectangle. This
+also works for polygons (the vertex list is preserved and restored when
+the marker is changed back to a polygon).
+<p>
+The current shape of a marker may be queried with getVertices, which
+returns the polygon or polyline vertex list in window coordinates. A more
+powerful routine which does something similar is getRegion. This routine
+returns a high level description of the region outlined by the marker,
+giving the marker type (rectangle, circle, ellipse etc.), center, width
+and height, and so on. Any position or dimension information may
+optionally be transformed back to the original source raster, if the marker
+center is in a region of the window which is the destination of an active
+mapping. The unmap option will follow multiple mappings back to the
+original mapped source raster.
+<p>
+The getRect function returns the parameters of the region outlined by a
+rectangle marker in a form convenient for use in a Gterm setMapping call
+(this is used to display an image within a marker).
+<p>
+Default translations when pointer is over a marker.
+default Marker Translations
+<p>
+<pre>
+ Shift &lt; Btn1Motion &gt;i m_rotateResize()
+ &lt; Btn1Motion &gt; m_moveResize()
+ Shift &lt; Btn1Down &gt; m_raise() m_markpos()
+ &lt; Btn1Down &gt; m_raise() m_markposAdd()
+ &lt; Btn1Up &gt; m_redraw() m_destroyNull()
+ &lt; Btn2Down &gt; m_lower()
+ &lt; Key &gt; BackSpace m_deleteDestroy()
+ &lt; Key &gt; Delete m_deleteDestroy()
+ &lt; KeyPress &gt; m_input()
+ &lt; Motion &gt; track-cursor()
+</pre>
+<p>
+MARKER class commands.
+<p>
+makeCopy</A></h1>
+<p>
+Copy a marker. The new marker is initially identical to the
+old one, and will not be distinct until, e.g., moved to a new center.
+<p>
+Usage:
+<p>
+<pre>
+ makeCopy name
+</pre>
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Post a marker callback to be called when the specified
+event or events occurs. If no events are listed a Notify callback will
+be posted.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure [event [event ...]]
+</pre>
+<p>
+<h1><A NAME="notify">notify</A></h1>
+<p>
+Generate a Marker pseudo-event, causing any posted client
+callback procedures to be called.
+<p>
+Usage:
+<p>
+<pre>
+ notify [event-type [param [param ...]]]
+</pre>
+<p>
+<h1><A NAME="destroy">destroy</A></h1>
+<p>
+Destroy a marker. Just tell the marker to destroy itself.
+All cleanup outside the marker facility relies upon the use of callbacks.
+This includes our callback markerDestroyCallback below.
+<p>
+Usage:
+<p>
+<pre>
+ destroy
+</pre>
+<p>
+<h1><A NAME="markpos">markpos</A></h1>
+<p>
+Mark the current position of a marker for a later redraw.
+<p>
+Usage:
+<p>
+<pre>
+ markpos
+</pre>
+<p>
+Markpos is used to mark the position of a marker before changing any
+marker attributes, so that a later "redraw marked" will erase the old
+marker rather than the new one. This is necessary, for example, if any
+marker attributes are changed which affect the size or position of the
+marker.
+<p>
+<h1><A NAME="redraw">redraw</A></h1>
+<p>
+Redraw a marker.
+<p>
+Usage:
+<p>
+<pre>
+ redraw [function] [erase|noerase] [markpos|nomarkpos]
+</pre>
+<p>
+By default redraw will erase the old marker at the position indicated by
+a previous call to markpos, and redraw the marker with the current
+attributes using the drawing function copy (copy source to destination).
+Hence the usual usage is "markpos ... change marker attributes ... redraw".
+Optional arguments may be given to change the drawing function, enable or
+disable erase, or force redraw to do a markpos. These arguments may be
+given in any order.
+<p>
+The drawing functions are as given in the XLIB documentation, minus the
+"GX" prefix. The most commonly used functions are "copy" and "xor".
+A normal marker redraw uses function=copy.
+<p>
+<h1><A NAME="raise">raise</A></h1>
+<p>
+Raise a marker, i.e., cause it to be drawn on top of other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ raise [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will raise itself above this
+marker, otherwise the raised marker becomes the topmost marker.
+<p>
+<h1><A NAME="lower">lower</A></h1>
+<p>
+Lower a marker, i.e., cause it to be drawn beneath other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ lower [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will lower itself beneath this
+marker, otherwise the lowered marker becomes the lowest marker.
+<p>
+<h1><A NAME="move">move</A></h1>
+<p>
+Move a marker.
+<p>
+Usage:
+<p>
+<pre>
+ move x y
+</pre>
+<p>
+Move the marker center to the indicated coordinates in the display window.
+<p>
+<h1><A NAME="resize">resize</A></h1>
+<p>
+Resize a marker.
+<p>
+Usage:
+<p>
+<pre>
+ resize width height
+</pre>
+<p>
+Resize the marker to the indicated size. By default width and height are
+given in pixels. For a text marker one can append "ch" to indicate that
+the units are chars in whatever font is in use, e.g., "40ch" or "40 chars"
+is an acceptable value for a text marker dimension.
+<p>
+<h1><A NAME="rotate">rotate</A></h1>
+<p>
+Rotate a marker.
+<p>
+Usage:
+<p>
+<pre>
+ rotate angle
+</pre>
+<p>
+Redraw a marker oriented to the given rotation angle. The angle is
+given in radians.
+<p>
+<h1><A NAME="getAttribute">getAttribute</A></h1>
+<p>
+Return the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ value = getAttribute attribute-name
+</pre>
+<p>
+<h1><A NAME="setAttribute">setAttribute</A></h1>
+<p>
+Set the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ setAttribute attribute-name value
+</pre>
+<p>
+<h1><A NAME="getAttributes">getAttributes</A></h1>
+<p>
+Return the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ getAttributes attribute-list
+ i.e. getAttributes {name value [name value ...]}
+ or getAttributes name value [name value ...]
+</pre>
+<p>
+where "value" is the name of the variable in which the attribute value
+is to be stored.
+<p>
+<h1><A NAME="setAttributes">setAttributes</A></h1>
+<p>
+Set the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ setAttributes attribute-list
+ i.e. setAttributes {name value [name value ...]}
+</pre>
+<p>
+where "value" is the new value of the associated marker attribute.
+<p>
+<h1><A NAME="getVertices">getVertices</A></h1>
+<p>
+Get some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ getVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is returned in the
+variable "points", as a string of the form { {x y} {x y} ...}. The first
+point is number zero.
+<p>
+<h1><A NAME="setVertices">setVertices</A></h1>
+<p>
+Set some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ setVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is set using the points
+passed in the "points" variable as a string of the form { {x y} {x y} ...}.
+If FIRST and NPTS are not specified first is assumed to be zero (the first
+point) and NPTS is the length of the points array.
+<p>
+<h1><A NAME="getRegion">getRegion</A></h1>
+<p>
+Return as a text string a high level description of the
+region defined by a marker.
+<p>
+Usage:
+<p>
+<pre>
+ region = getRegion [unmap] [coord-type]
+</pre>
+<p>
+The output string defines the marker type and the major marker positional
+attributes. The region description formats for the various marker types
+follow.
+<p>
+<pre>
+ text raster x y width height
+ line raster x y x y
+ polyline raster npts { {x y} {x y} ...}
+ rectangle raster x y width height rotangle
+ circle raster x y radius
+ ellipse raster x y width height rotangle
+ polygon raster npts { {x y} {x y} ...}
+</pre>
+<p>
+Here, width and height refer to the distance from the marker center to an
+edge, not to the width or height of the whole marker. This avoids
+ambiguities about where the edge of a marker is if the width is even or
+odd. Using the center to edge measurement, the edge is at x +/- width,
+y +/- height.
+<p>
+If the "unmap" flag is given getRegion will attempt to associate the
+marker with a mapped raster, reversing any mappings from the screen back
+to the original source raster, and returning the raster number and raster
+coordinates and marker sizes. If "unmap" is not given the marker
+coordinates will refer to raster 0. Either pixel ("pixel") or NDC
+("ndc") coordinates may be returned, pixel coordinates being the default.
+<p>
+<h1><A NAME="getRect">getRect</A></h1>
+<p>
+Return the region enclosed by a rectangle marker. The rect is
+returned in a form convenient for use as the destination rect in a gterm
+widget raster mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getRect dx dy dnx dny
+</pre>
+<p>
+The rect is stored in the output arguments.
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/gterm.gif b/vendor/x11iraf/obm/docs/gui.doc/gterm.gif
new file mode 100644
index 00000000..042debf5
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/gterm.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/gtermclass.html b/vendor/x11iraf/obm/docs/gui.doc/gtermclass.html
new file mode 100644
index 00000000..5fcdab10
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/gtermclass.html
@@ -0,0 +1,694 @@
+<title>Gterm-Image widget class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> Gterm-Image widget class (a subclass of Widget).</h1>
+<p>
+<HR>
+<p>
+The gterm-image widget is a general 2D graphics-imaging widget providing
+a wide range of facilities for drawing graphics and text, for image
+display, and for graphics interaction. Normally the client communicates
+directly with the Gterm widget to draw graphics, download image data,
+and so on, using some communications protocol outside the domain of the
+object manager. Nonetheless so far as possible the facilities of the Gterm
+widget have also been made available to GUI code via the commands listed
+here.
+<p>
+The Gterm widget adds the following function to the OBM library.
+<p>
+<pre>
+ ObmPostSetGtermCallback (obm, &setgterm, setgterm_client_data)
+</pre>
+<p>
+This is called by a client application to post a procedure to be called
+when a gterm widget receives the setGterm command. The calling sequence
+for setGterm callback is as follows:
+<p>
+<pre>
+ setgterm (client_data, gterm_widget)
+</pre>
+<p>
+The purpose of this callback is to tell the client which gterm widget is
+the "active" gterm widget. This is used by clients which only support
+one active Gterm widget, i.e., which can only direct graphics output to
+one Gterm widget at a time.
+<p>
+The messages or commands that can be sent to the Gterm widget by GUI
+code follow.
+<p>
+General commands:
+<p>
+<pre>
+ <a href="#setGterm">setGterm</a> # make widget the active Gterm
+<p>
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a>
+ <a href="#addCallback">addCallback</a> procedure-name callback-type
+ <a href="#reset">reset</a>
+ <a href="#flush">flush</a>
+<p>
+ <a href="#setCursorPos">setCursorPos</a> x y [raster]
+ <a href="#getCursorPos">getCursorPos</a> x y
+ <a href="#setCursorType">setCursorType</a> cursortype
+ <a href="#bell">bell</a>
+</pre>
+<p>
+Graphics drawing commands:
+<p>
+<pre>
+ <a href="#setRaster">setRaster</a> raster
+ raster = <a href="#getRaster">getRaster</a> [raster]
+<p>
+ <a href="notyet.html">setLogRes</a> width height (unimplimented)
+ <a href="notyet.html">getLogRes</a> width height (unimplimented)
+ <a href="notyet.html">setPhysRes</a> width height (unimplimented)
+ <a href="notyet.html">getPhysRes</a> width height (unimplimented)
+ <a href="notyet.html">setTextRes</a> rows cols (unimplimented)
+ <a href="notyet.html">setDataLevel</a> level (unimplimented)
+ <a href="notyet.html">setLineWidth</a> width (unimplimented)
+ <a href="notyet.html">setLineStyle</a> style (unimplimented)
+ <a href="notyet.html">setColorIndex</a> index (unimplimented)
+ <a href="notyet.html">setFillType</a> filltype (unimplimented)
+<p>
+ <a href="#clearScreen">clearScreen</a>
+ <a href="notyet.html">drawPolyline</a> vector (unimplimented)
+ <a href="notyet.html">drawPolymarker</a> vector (unimplimented)
+ <a href="notyet.html">drawPolygon</a> vector (unimplimented)
+ <a href="notyet.html">drawMarker</a> x y xsize ysize type (unimplimented)
+<p>
+ <a href="notyet.html">drawAlphaText</a> x y text (unimplimented)
+ <a href="notyet.html">getAlphaTextSize</a> string width height base (unimplimented)
+ <a href="notyet.html">startDialog</a> (unimplimented)
+ <a href="notyet.html">endDialog</a> (unimplimented)
+ <a href="notyet.html">eraseDialog</a> (unimplimented)
+ <a href="notyet.html">drawDialogText</a> x y text (unimplimented)
+ <a href="notyet.html">getDialogTextSize</a> string width height base (unimplimented)
+</pre>
+<p>
+The coordinates used in the graphics drawing commands are logical
+coordinates as defined by setLogRes, in the coordinate system of the
+reference drawing raster as defined by setRaster. The default reference
+raster is raster zero, the widget's window. Vectors are specified as
+a list of points, e.g., { {x y} {x y} ... }.
+<p>
+Imaging commands:
+<p>
+<pre>
+ <a href="#rasterInit">rasterInit</a>
+ <a href="notyet.html">assignRaster</a> raster drawable (unimplimented)
+ <a href="notyet.html">createRaster</a> raster type width height depth (unimplimented)
+ <a href="notyet.html">destroyRaster</a> raster (unimplimented)
+ exists = <a href="notyet.html">queryRaster</a> raster type width height depth (unimplimented)
+ raster = <a href="notyet.html">nextRaster</a> [raster] (unimplimented)
+ nrasters = <a href="notyet.html">nRasters</a> [nrasters] (unimplimented)
+<p>
+ <a href="#setPixel">setPixel</a> raster x y value
+ value = <a href="#getPixel">getPixel</a> raster x y
+ <a href="#writePixels">writePixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="#readPixels">readPixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="notyet.html">refreshPixels</a> raster ct x1 y1 nx ny (unimplimented)
+ pixmap = <a href="notyet.html">createPixmap</a> src x y width height (unimplimented)
+ <a href="notyet.html">copyPixmap</a> pixmap dst x y width height (unimplimented)
+<p>
+ colormap = <a href="notyet.html">nextColormap</a> [colormap] (unimplimented)
+ <a href="notyet.html">freeColormap</a> colormap (unimplimented)
+ <a href="notyet.html">writeColormap</a> colormap first nelem colors (unimplimented)
+ <a href="notyet.html">readColormap</a> colormap first nelem colors (unimplimented)
+ <a href="#loadColormap">loadColormap</a> colormap offset scale
+<p>
+ <a href="notyet.html">initMappings</a> (unimplimented)
+ mapping = <a href="#nextMapping">nextMapping</a> [mapping]
+ <a href="notyet.html">freeMapping</a> mapping (unimplimented)
+ <a href="notyet.html">enableMapping</a> mapping (unimplimented)
+ <a href="notyet.html">disableMapping</a> mapping (unimplimented)
+ active = <a href="notyet.html">activeMapping</a> mapping (unimplimented)
+ <a href="notyet.html">refreshMapping</a> mapping (unimplimented)
+<p>
+ raster = <a href="#selectRaster">selectRaster</a> dras dt dx dy rt rx ry [map]
+ <a href="#unmapPixel">unmapPixel</a> sx sy raster rx ry [rz]
+<p>
+ <a href="notyet.html">copyRaster</a> rop src st sx sy snx sny dst dt dx dy dnx dny (unimplimented)
+ <a href="#setMapping">setMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#getMapping">getMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+<p>
+ <a href="#flip">flip</a> mapping axis [axis...]
+</pre>
+<p>
+Pixel arrays are long strings consisting either of a sequence of numeric
+pixel values separated by whitespace (space or newline), or a hex encoded
+sequence of bytes (2 hex digits per 8 bit pixel). Colors are specified
+as a list of RGB triplets, e.g., { {R G B} {R G B} ... }.
+<p>
+Refer to the documentation for the Gterm widget for a detailed description
+of rasters, mappings, and colormaps.
+<p>
+Markers:
+<p>
+<pre>
+ <a href="#createMarker">createMarker</a> name [attribute-list]
+ <a href="#markerInit">markerInit</a>
+</pre>
+<p>
+New markers may be created with createMarker. Once created, a marker
+functions under the Object Manager as a named object of class "marker".
+Refer to the marker class for a description of the commands defined for
+a marker.
+<p>
+gterm Actions List
+<p>
+<pre>
+ ignore
+ graphics-input
+ graphics-context
+ crosshair
+ track-cursor
+ enter-window
+ leave-window
+ popup-menu {not implemented}
+ reset
+ m_create
+</pre>
+<p>
+Default translations for Gterm window.
+Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu)
+<p>
+default Gterm Translations
+<p>
+<pre>
+ [Btn1Down]:m_create()
+ [Btn2Down]:crosshair(on)
+ [Btn2Motion]:crosshair(on)
+ [Btn2Up]:crosshair(off)
+ ~Ctrl ~Meta [Btn3Down]:graphics-context()
+ [EnterWindow]:enter-window()
+ [LeaveWindow]:leave-window()
+ [KeyPress]:graphics-input()
+ [Motion]:track-cursor()
+<pre>
+<p>
+<p>
+GTERM class commands.
+<p>
+<h1><A NAME="setGterm">setGterm</A></h1>
+<p>
+Set the active Gterm widget. A UI can have more than one
+gterm widget, but due to restrictions on the client-server interface, it
+may be possible for only one to receive client output at any one time (any
+gterm widget can generate input to be sent to the client). If the client
+has this restriction, the client-server interface code which uses OBM can
+call the ObmPostSetGtermCallback procedure to post a function to be called
+when the UI code calls the setGterm procedure.
+<p>
+Usage:
+<p>
+<pre>
+ setGterm
+</pre>
+<p>
+<h1><A NAME="activate">activate</A></h1>
+<p>
+Activate the gterm widget. This causes the next GIN mode
+setCursorType to warp the pointer into the gterm window.
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h1><A NAME="deactivate">deactivate</A></h1>
+<p>
+Deactivate the gterm widget. If the cursor has been warped
+into the window by a previous activate/setCursorType GIN mode, this causes
+the cursor to be warped back to where it was previously.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate
+</pre>
+<p>
+<h1><A NAME="reset">reset</A></h1>
+<p>
+Reset the gterm widget. This causes a number of state variables
+affecting graphics drawing options to be set to their default values.
+<p>
+Usage:
+<p>
+<pre>
+ reset
+</pre>
+<p>
+<h1><A NAME="flush">flush</A></h1>
+<p>
+Flush any graphics output and synchronize the state of the widget
+with what is shown on the display.
+<p>
+Usage:
+<p>
+<pre>
+ flush
+</pre>
+<p>
+The gterm widget uses XLIB, which buffers graphics drawing commands and
+automatically sends them to the X server when 1) the buffer fills,
+2) input is requested from the server. Such buffering of data is necessary
+for efficient operation and it should rarely be necessary to explicitly
+flush graphics output since XLIB does this automatically in most cases.
+An example of when explicitly flushing the ouptut might be necessary is in
+cases where smooth animation is desired and drawing the graphics in batches
+could cause the display to appear "jerky".
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Post a callback for a Gterm widget event.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure-name [callback-type]
+</pre>
+<p>
+The recognized Gterm callbacks are
+<p>
+<pre>
+
+ input Called when the graphics-input action is invoked in
+ a translation table. The default Gterm translation
+ table invokes this action when a KeyPress event occurs
+ in the Gterm window.
+ Callback: widget-name input-type event-data
+
+ resize Called when the gterm window is resized.
+ Callback: widget-name width height
+
+ reset Called when the "reset" action is invoked.
+ Callback: widget-name
+
+<pre>
+<p>
+If no callback is specified the default is "input".
+<p>
+Note that in GUI code one can also use the translation table to directly
+invoke GUI procedures without need to use the Gterm input mechanism. This
+is more flexible but we support the Gterm input callback here for
+applications that use the default translations.
+<p>
+<h1><A NAME="setCursorPos">setCursorPos</A></h1>
+<p>
+Warp the cursor (pointer) to the given coordinates. This
+is a graphics drawing command and if no raster number is specified the
+current reference drawing raster, as set with setRaster, defines the
+coordinate system.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorPos x y [raster]
+</pre>
+<p>
+A raster number may optionally given to define the raster coordinate system
+to be used. raster=0 yields screen coordinates.
+<p>
+<h1><A NAME="getCursorPos">getCursorPos</A></h1>
+<p>
+Get the cursor position (raster 0 or screen coordinates).
+<p>
+Usage:
+<p>
+<pre>
+ getCursorPos x y
+</pre>
+<p>
+<h1><A NAME="setCursorType">setCursorType</A></h1>
+<p>
+Set the cursor type.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorType cursor-type
+
+ idle default cursor
+ busy busy cursor, e.g, when program is busy
+ ginMode graphics input mode cursor, set when program is
+ waiting for graphics input
+</pre>
+<p>
+<h1><A NAME="bell">bell</A></h1>
+<p>
+Gterm widget sound output.
+<p>
+Usage:
+<p>
+<pre>
+ bell
+</pre>
+<p>
+<h1><A NAME="setRaster">setRaster</A></h1>
+<p>
+Set the number of the raster to be used to define the drawing
+context (e.g. coordinate system) for graphics and text drawing functions.
+<p>
+Usage:
+<p>
+<pre>
+ setRaster raster-number
+</pre>
+<p>
+<h1><A NAME="getRaster">getRaster</A></h1>
+<p>
+Get the number of the raster which defines the drawing
+context, as set in the last setRaster call.
+<p>
+Usage:
+<p>
+<pre>
+ raster = getRaster [raster]
+</pre>
+<p>
+If the name of a variable is given the raster number will be stored
+directly in that variable.
+<p>
+<h1><A NAME="clearScreen">clearScreen</A></h1>
+<p>
+Clear the "screen", i.e., window. This action clears the
+drawing window and sets a number of drawing state variables to their default
+values.
+<p>
+Usage:
+<p>
+<pre>
+ clearScreen
+</pre>
+<p>
+<h1><A NAME="rasterInit">rasterInit</A></h1>
+<p>
+Initialize the raster subsystem, deleting all rasters and
+mappings and freeing the dynamic part of the colortable.
+<p>
+Usage:
+<p>
+<pre>
+ rasterInit
+</pre>
+<p>
+<h1><A NAME="writePixels">writePixels</A></h1>
+<p>
+Set the values of some subset of the pixels in a raster.
+If any mappings are defined on the affected region and are enabled, any
+destination rasters will be automatically updated as defined by the mapping.
+<p>
+Usage:
+<p>
+<pre>
+ writePixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be written.
+</pre>
+<p>
+Most real-world image processing applications get the Gterm widget handle
+with setGterm and pass binary data to the widget by calling GtWritePixels
+directly. This is the most efficient approach for serious image processing
+where large amounts of data are involved. However, being able to read and
+write raster pixels directly in a GUI can be useful in specialized
+applications, e.g., where the image is computed or modified by the GUI.
+<p>
+<h1><A NAME="setPixel">setPixel</A></h1>
+<p>
+Set the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ setPixel raster x y value
+
+ raster The raster number.
+ x, y The pixel to be set.
+ value The pixel value.
+</pre>
+<p>
+This routine is more efficient than writePixels for setting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be set.
+<p>
+<h1><A NAME="readPixels">readPixels</A></h1>
+<p>
+Get the values of some subset of the pixels in a raster.
+<p>
+Usage:
+<p>
+<pre>
+ readPixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be read.
+</pre>
+<p>
+Use readPixels to read a block of pixels, and getPixel to get the value
+of a single pixel.
+<p>
+<h1><A NAME="getPixel">getPixel</A></h1>
+<p>
+Get the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ getPixel raster x y
+
+ raster The raster number.
+ x, y The pixel to be set.
+</pre>
+<p>
+This routine is more efficient than readPixels for getting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be read.
+<p>
+<h1><A NAME="nextMapping">nextMapping</A></h1>
+<p>
+Return the index of the next unused mapping.
+<p>
+Usage:
+<p>
+<pre>
+ nextMapping
+</pre>
+<p>
+Returns the mapping number as the function value.
+<p>
+<h1><A NAME="getMapping">getMapping</A></h1>
+<p>
+Get a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters except the mapping number are output parameters.
+<p>
+<h1><A NAME="setMapping">setMapping</A></h1>
+<p>
+Set a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ setMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters are input parameters.
+<p>
+<h1><A NAME="loadColormap">loadColormap</A></h1>
+<p>
+Load a colormap.
+<p>
+Usage:
+<p>
+<pre>
+ loadColormap colormap [offset [scale]]
+</pre>
+<p>
+The offset and scale parameters may be used to adjust the brightness and
+contrast of the image when the colormap is loaded. The normalized colormap
+has offset=0.5, scale=1.0. Colormap zero is the hardware colormap.
+<p>
+<h1><A NAME="selectRaster">selectRaster</A></h1>
+<p>
+Given the raw screen coordinates SX,SY (or coords in
+any destination raster), determine the mapping and source raster which are
+mapped to that pixel and return the raster and mapping numbers and the
+coordinates of the same pixel in the source raster.
+<p>
+Usage:
+<p>
+<pre>
+ raster = selectRaster dras dt dx dy rt rx ry [map]
+</pre>
+<p>
+where
+<p>
+<pre>
+ dras display raster
+ dt,rt coordinate type - "pixel" or "ndc"
+ dx,dy display raster coordinates (input)
+ rx,ry source raster coordinates (output)
+ map mapping selected (output)
+</pre>
+<p>
+Note that the coordinates returned by selectRaster are measured (taking
+a line as an example) from zero at the left edge of the first pixel, to
+"width" at the right edge of the last pixel. This means that the floating
+point coordinates of the center of raster pixel N will be N + 0.5. For
+example, if we input screen coordinates (dras=0), x=117, and no mapping
+is in effect, the floating point raster coordinates returned will be 117.5.
+The difference occurs because the input coordinate is a pixel number
+(integer) while the output coordinate is a floating point coordinate
+measuring the continuously variable location a pixel. int(x) will convert
+this coordinate to a raster pixel number.
+<p>
+<h1><A NAME="unmapPixel">unmapPixel</A></h1>
+<p>
+unmapPixel is a simplified, less general version of
+selectRaster which will automatically follow graphics pipelines back to
+the original mapped raster. If desired the raster pixel value can be
+returned as well as the raster number and raster pixel coordinates
+corresponding to a screen (raster 0) pixel.
+<p>
+Usage:
+<p>
+<pre>
+ unmapPixel sx sy raster rx ry [rz]
+</pre>
+<p>
+where
+<p>
+<pre>
+ sx,sy "screen" (raster 0) coordinates
+ raster original mapped raster (output)
+ rx,ry source raster coordinates (output)
+ rz source raster pixel value (output)
+<pre>
+<p>
+By following graphics pipelines back to the original source raster we mean
+the following. If raster A is mapped to raster B which is mapped to C (the
+screen), given a screen coordinate in the mapped region unmapPixel will
+return the raster number and coordinates for raster A.
+<p>
+<h1><A NAME="flip">flip</A></h1>
+<p>
+Edit a mapping to flip the mapped subimage in X and/or Y.
+<p>
+Usage:
+<p>
+<pre>
+ flip mapping axis [axis]
+</pre>
+<p>
+where axis is "x" or "y". This is a convenience routine for changing only
+the flip portion of a mapping.
+<p>
+<h1><A NAME="markerInit">markerInit</A></h1>
+<p>
+Initialize the Marker subsystem for a Gterm widget.
+This destroys all markers and initializes the marker subsystem.
+<p>
+Usage:
+<p>
+<pre>
+ markerInit
+</pre>
+<p>
+<h1><A NAME="createMarker">createMarker</A></h1>
+<p>
+Create a new marker.
+<p>
+Usage:
+<p>
+<pre>
+ createMarker name attribute-list
+ e.g. createMarker name {attribute value [attribute value ...]}
+ or createMarker name attribute value [attribute value ...]
+<pre>
+<p>
+Any marker attribute may be assigned a value when the marker is created.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker attribute names. Often the
+the attributes "type" and "createMode" need to be specified at marker
+create time.
+<p>
+<pre>
+ type The marker type: text, rectangle, circle, etc.
+
+ createMode A marker should be created with createMode=interactive
+ if the user is expected to interactively drag out
+ the marker using the pointer and either the default
+ or an application specified translation table. A
+ marker can also be created interactively using only
+ the m_create (marker create) action, however m_create
+ does not allow the marker attributes to be set.
+<pre>
+<p>
+There are any number of ways to use a GUI to create a marker under the
+Object Manager, but an example might be using a translation to call a GUI
+procedure which issues the createMarker call. For example a pointer down
+event could translate as "call(newMarker,$name,$x,$y) m_create()" where
+newMarker is a GUI marker creation procedure which sends a createMarker
+message to the Gterm widget. The GUI procedure could set the marker
+attributes as desired, possibly using additional GUI components to define
+the marker attributes. The m_create action will notice that a
+createMarker has been executed and will merely activate the marker and
+give it the pointer focus (i.e. install the marker translations). The
+user will then use the pointer or keyboard to drag out the marker.
+<p>
+If the marker is created noninteractive the application must set the marker
+position and size using marker attributes. If the marker is sensitive
+the user can then use the marker's translations to interactively modify
+the marker (resize it, move it, etc.). All markers which are visible and
+sensitive and which have the necessary translations can be interactively
+modified by the user; the reason for creating a marker in interactive mode
+is to allow the initial marker position and size to be specified
+interactively *when* the marker is created, instead of afterwards.
+<p>
+Any number of attributes may be given when the marker is created. Most
+marker attributes can also be modified after a marker has been created
+by sending setAttribute messages to the marker.
+
diff --git a/vendor/x11iraf/obm/docs/gui.doc/gui.html b/vendor/x11iraf/obm/docs/gui.doc/gui.html
new file mode 100644
index 00000000..d7e20546
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/gui.html
@@ -0,0 +1,93 @@
+<html>
+<body bgcolor=#FFFFFF>
+
+<title>IRAF Object Manager</title>
+<h1>IRAF Object Manager</h1>
+<HR>
+<p>
+An Object Manager (OBM) user interface (UI) consists of one or more windows
+containing an arbitrary hierarchy of widgets. These widgets and their
+runtime actions are defined by an interpreted text program uploaded
+by the client application, which does not itself deal directly with
+the window user interface. Currently, this interpreted program is written
+in Tcl.
+<p>
+The object manager provides a higher level of abstraction for dealing
+with widgets and other UI objects. The main function of the object
+manager is to deliver messages to UI objects. Each instance of a widget,
+the client programs, and the OBM itself are
+objects in the UI. The UI contains other types of objects however,
+including the client object (client application), the server object
+(the object manager itself), and the application specific UI parameters,
+each of which is an object with a callback list of UI procedures to be
+called when the parameter value changes. All of these UI objects can
+receive messages and take actions as a result. Messages may come from the
+client application, or as a result of actions executed by the interpreted
+UI code in response to graphics events.
+<p>
+<h2>Object classes:</h2>
+<p>
+<pre>
+<a href="Client.html">Client</a> the client application
+<a href="Server.html">Server</a> the object manager itself
+<a href="widgetclass.html">Widget</a> widgets
+<a href="uiparameterclass.html">ParameterUI</a> control parameter
+<a href="gtermclass.html">Gterm</a> graphics/imaging widget
+<a href="gmc.html">Graphics Markers</a> marker widgets
+<a href="ximclient.html">Image Client</a> imageing widget
+<p>
+<a href="notyet.html">Various Xt and Athena widgets</a>
+ {box, shell, label, command, text, list, etc.}
+</pre>
+<p>
+To locate specific IRAF GUI commands quickly, here is an
+<pre>
+ <a href="alphabetic.html">alphabetized list of IRAF GUI commands</a>
+</pre>
+<p>
+Sophisticated graphics applications will download a UI during initialization
+to define a custom graphics user interface. This is done by sending a
+message to the object manager. Naive applications assume a simple graphics
+terminal and do not download a UI; in this case, a default UI is created
+for the application when the UI is enabled with ObmEnable. The default
+UI is a single top level shell window containing a single gterm (graphics
+terminal) widget.
+<p>
+<pre>
+ <a href="servercom.html#resetReset">reset-server</a>
+ <a href="servercom.html#appInitialize">appInitialize</a> appname,appclass,resources
+ <a href="servercom.html#createObjects">createObjects</a> [resource-name]
+ (UI specific code)
+ <a href="servercom.html#activate">activate</a>
+</pre>
+<p>
+A UI specification consists of a sequence of commands to be executed by
+the server object. This is downloaded by the client as a message for the
+server object. The commands should include "reset-server" (this must be
+the first executable command), "appInitialize" (defines the UI objects and
+their resources), and "createObjects" (creates the objects and the widget
+tree), followed by any UI specific commands to define and register UI
+callback procedures. Finally, "activate" is executed to activate the new
+user interface.
+<p>
+Class descriptors for all UI object classes. In the following, only the
+class initializer function needs to be set statically, since the class
+initializer function will initialize the remaining fields of the class
+descriptor at run time when the object manager is opened.
+<p>
+<pre>
+ Server Client Parameter Gterm Core
+ Object Widget Command Grip Label
+ List Scrollbar StripChart Toggle SimpleMenu
+ Sme SmeBSB SmeLine MenuButton AsciiText
+ Box Dialog Form Paned Viewport
+
+ Shell
+ OverrideShell
+ WMShell
+ TransientShell
+ TopLevelShell
+ ApplicationShell
+</pre>
+</body>
+</html>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/guiintro.html b/vendor/x11iraf/obm/docs/gui.doc/guiintro.html
new file mode 100644
index 00000000..81511434
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/guiintro.html
@@ -0,0 +1,9 @@
+<title>Introduction and Overview</title>
+<h2><IMG SRC="irafgui.gif"> Introduction and Overview</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<h3>Design Philosophy</h3>
+<p>
+<h3>Basic Tools</h3>
+<p>
+<h3><a href="example.html">An Example</a></h3>
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowse.gif b/vendor/x11iraf/obm/docs/gui.doc/imbrowse.gif
new file mode 100644
index 00000000..af1e7c0a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowse.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/controlForm.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/controlForm.html
new file mode 100644
index 00000000..88e74c83
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/controlForm.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the controlForm</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirName.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirName.html
new file mode 100644
index 00000000..4c4b3cb3
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirName.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the dirName</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirSelect.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirSelect.html
new file mode 100644
index 00000000..fe8f8f40
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/dirSelect.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the dirSelect</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/headerText.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/headerText.html
new file mode 100644
index 00000000..a132c5f3
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/headerText.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the headerText</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/imageButton.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/imageButton.html
new file mode 100644
index 00000000..12595f3c
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/imageButton.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the imageButton</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/none.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/none.html
new file mode 100644
index 00000000..9cd7d5e3
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/none.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse none</title>
+<h2><IMG SRC="irafgui.gif"> You selected none of the ellipses</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/objView.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/objView.html
new file mode 100644
index 00000000..a830a57a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/objView.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the objView</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/panel.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/panel.html
new file mode 100644
index 00000000..b6b0ff2e
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/panel.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the panel</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/sectionBox.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/sectionBox.html
new file mode 100644
index 00000000..60895b18
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/sectionBox.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the sectionBox</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/statusBox.html b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/statusBox.html
new file mode 100644
index 00000000..061f5045
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imbrowsemap/statusBox.html
@@ -0,0 +1,3 @@
+<title>Example: Imbrowse panel</title>
+<h2><IMG SRC="irafgui.gif"> You selected the statusBox</h2>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
diff --git a/vendor/x11iraf/obm/docs/gui.doc/imtool.gif b/vendor/x11iraf/obm/docs/gui.doc/imtool.gif
new file mode 100644
index 00000000..a29811ef
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/imtool.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/intro.gif b/vendor/x11iraf/obm/docs/gui.doc/intro.gif
new file mode 100644
index 00000000..7f7af646
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/intro.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/irafgui.gif b/vendor/x11iraf/obm/docs/gui.doc/irafgui.gif
new file mode 100644
index 00000000..032c72d5
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/irafgui.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/llama.gif b/vendor/x11iraf/obm/docs/gui.doc/llama.gif
new file mode 100644
index 00000000..be0ceef4
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/llama.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/marker.gif b/vendor/x11iraf/obm/docs/gui.doc/marker.gif
new file mode 100644
index 00000000..639b19bd
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/marker.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/newgui.html b/vendor/x11iraf/obm/docs/gui.doc/newgui.html
new file mode 100644
index 00000000..36e7ec1a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/newgui.html
@@ -0,0 +1,18 @@
+<title>IRAF GUI Documentation</title>
+<h1><IMG SRC="irafgui.gif"> IRAF Graphical User Interfaces</h1>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+This hypertext work is introductory documentation for the IRAF graphical
+user interface facility introduced with IRAF version 2.10.3. Questions
+can be directed, via electronic mail, to iraf.noao.edu or posted to the
+newsgroup adass.iraf.programmer.
+<p>
+<pre>
+<a href="guiintro.html"><IMG ALIGN=MIDDLE SRC="intro.gif"></a> An introduction and overview
+
+<a href="widgets.html"><IMG ALIGN=MIDDLE SRC="widgets.gif"></a> The widgets and how they work
+
+<a href="tcl.html"><IMG ALIGN=MIDDLE SRC="tcl.gif"></a> The language used to build GUIs
+
+<a href="notyet2.html"><IMG ALIGN=MIDDLE SRC="softgui.gif"></a> Software - GUI communication
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/notyet.html b/vendor/x11iraf/obm/docs/gui.doc/notyet.html
new file mode 100644
index 00000000..9a292a44
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/notyet.html
@@ -0,0 +1,5 @@
+<title>NOTYET</title>
+<p>
+<a href="einstein.html"><IMG align=middle SRC="einstein.gif"></a>
+The info you requested is not yet available.
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/notyet2.html b/vendor/x11iraf/obm/docs/gui.doc/notyet2.html
new file mode 100644
index 00000000..2a6e3dca
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/notyet2.html
@@ -0,0 +1,5 @@
+<title>NOTYET</title>
+<p>
+<IMG align=middle SRC="llama.gif">
+The info you requested is not yet available.
+<p>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/otherwidgets.html b/vendor/x11iraf/obm/docs/gui.doc/otherwidgets.html
new file mode 100644
index 00000000..f477fdc7
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/otherwidgets.html
@@ -0,0 +1,10 @@
+<title>Other Widgets</title>
+<h1><IMG SRC="irafgui.gif"> Other Widgets</h1>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+There are a few more widgets to be aware of, these are the parameter
+widgets, ....
+<p>
+<pre>
+<a href="parameterwidgets.html">Parameter Widget</a>
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/params.gif b/vendor/x11iraf/obm/docs/gui.doc/params.gif
new file mode 100644
index 00000000..053f424b
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/params.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/redline.gif b/vendor/x11iraf/obm/docs/gui.doc/redline.gif
new file mode 100644
index 00000000..574a6c8a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/redline.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/serverclass.html b/vendor/x11iraf/obm/docs/gui.doc/serverclass.html
new file mode 100644
index 00000000..3fdaec2a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/serverclass.html
@@ -0,0 +1,38 @@
+<title>SERVER class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> SERVER class</h1>
+<p>
+<HR>
+<p>
+The server, or object manager, is the control center of the user interface.
+The server object provides a Tcl interpreter calling custom object manager
+commands. These are used to define and initialize the user interface, and
+execute UI action procedures at runtime.
+<p>
+<pre>
+ <a href="servercom.html#resetReset">reset-server</a>
+ <a href="servercom.html#appInitialize">appInitialize</a> appname,appclass,resources
+ <a href="servercom.html#createObjects">createObjects</a> [resource-name]
+ <a href="servercom.html#destroyObject">destroyObject</a> object
+ <a href="servercom.html#activate">activate</a>
+ <a href="servercom.html#deactivate">deactivate</a> [unmap]
+<p>
+ value = <a href="servercom.html#getResource">getResource</a> resource-name [default-value [class]]</a>
+ <a href="servercom.html#getResources">getResources</a> resource-list
+<p>
+ <a href="servercom.html#createMenu">createMenu</a> menu-name parent item-list
+ <a href="servercom.html#createMenu">editMenu</a> menu-name parent item-list
+ <a href="servercom.html#destroyMenu">destroyMenu</a> menu-name
+<p>
+ <a href="servercom.html#createBitmap">createBitmap</a> name width height data
+ <a href="servercom.html#createCursor">createCursor</a> name source mask fg_color bg_color x_hot y_hot
+ <a href="servercom.html#createPixmap">createPixmap</a> name width height depth fg_color bg_color data
+<p>
+ <a href="servercom.html#print">print</a> arg [arg ...] # debug messages
+ <a href="servercom.html#send">send</a> object message
+<p>
+ <a href="servercom.html#postActivateCallback">postActivateCallback</a> procedure
+id = <a href="servercom.html#postTimedCallback">postTimedCallback</a> procedure msec [client-data]
+ <a href="servercom.html#deleteTimedCallback">deleteTimedCallback</a> id
+ id = <a href="servercom.html#postWorkCallback">postWorkCallback</a> procedure [client-data]
+ <a href="servercom.html#deleteWorkCallback">deleteWorkCallback</a> id
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/servercom.html b/vendor/x11iraf/obm/docs/gui.doc/servercom.html
new file mode 100644
index 00000000..16c4c24e
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/servercom.html
@@ -0,0 +1,375 @@
+<h1><A NAME="serverReset">serverReset</A></h1>
+<p>
+The "reset-server" command is implemented as a special case in ServerEvaluate.
+After doing a true reset ServerEvaluate calls Tcl_Eval to evaluate the full
+message which still contains the reset-server command. We want to ignore
+this the second time, so we treat the command here as a no-op.
+<p>
+Usage:
+<p>
+<pre>
+ reset-server
+</pre>
+<p>
+Note: for reset-server to be recognized by ServerEvaluate and really reset
+things, it must be the first command in a message to the server.
+<p>
+<h1><A NAME="appInitialize>appInitialize</A></h1>
+<p>
+TCL command to initialize the server for a new application, setting the
+application name and loading the application resources.
+<p>
+Usage:
+<p>
+<pre>
+ appInitialize appname, appclass, resources
+</pre>
+<p>
+<h1><A NAME ="createObjects">createObjects</A></h1>
+<p>
+TCL command to create the tree of UI objects comprising the user interface.
+The object tree is defined by a string valued resource. If no resource is
+named the default "objects" resource will be used.
+<p>
+Usage:
+<p>
+<pre>
+ createObjects [resource-name]
+</pre>
+<h1><A NAME="destroyObject">destroyObject</A></h1>
+<p>
+Destroy an object and all of its children.
+<p>
+Usage:
+<pre>
+ destroyObject object-name
+</pre>
+<p>
+<h1><A NAME="activate">activate</A></h1>
+Activate the user interface. When called the first time the user interface
+is created and activated, thereafter the UI is merely reactivated (e.g.
+mapped if unmapped).
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h1><A NAME="deactivate">deactivate</A></h1>
+<p>
+Deactivate the user interface. Optionally unmaps the UI and calls the Obm
+client back to let it know that the UI has been deactivated.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate [unmap]
+</pre>
+<p>
+<h1><A NAME="getResource">getResource</A></h1>
+<p>
+Get the string value of the specified application resource (window
+system parameter). This allows use of the resource mechanism to supply
+default values for GUI parameters.
+<p>
+Usage:
+<p>
+<pre>
+ value = getResource resource-name [class [default-value]]
+</pre>
+<p>
+In the simplest case one merely requests a resource by name and the
+string value is returned as the function value. If the resource has
+an entry in the fallback resources for the application (appInitialize
+resource list) then a value is guaranteed to be returned.
+<p>
+If the Class name for the resource is given then a class default value
+will be returned if no entry is found for the name resource instance. This
+is useful when there are a number of resources of the same type (same class).
+If most or all resources in the same class have the same default value one
+need only make one entry for the Class in the application defaults resource
+list. It is up to the application developer to define the class name of a
+resource - the class name can be any string. Examples are "Font", "Cursor",
+etc. By convention the first character of a class name is capitalized, while
+instance names begin with a lower case letter.
+<p>
+If there is an entry for the named resource in the resource list passed to
+appInitialize then a value string is guaranteed to be returned. This will be
+either the appInitialize default, or a value specified by the system or the
+user in an X resources file. If one is not certain a default value is defined
+somewhere, a default value should be specified in the getResource call as
+shown above.
+<p>
+See also getResources, used to get multiple resources in one call.
+<p>
+<h1><A NAME="getResources">getResources</A></h1>
+<p>
+Get the string values of a list of resources.
+<p>
+Usage:
+<p>
+<pre>
+ getResources resource-list
+</pre>
+<p>
+e.g.
+<pre>
+ getResources {
+ { resource [variable class [default-value]]] }
+ { resource [variable class [default-value]]] }
+ (etc.)
+ }
+</pre>
+<p>
+<h1><A NAME="createMenu">createMenu, editMenu</A></h1>
+<p>
+Create or modify a menu. The editMenu function is an alias for createMenu.
+<p>
+Usage:
+<pre>
+ createMenu menu-name parent item-list
+</pre>
+<p>
+e.g.,
+<pre>
+ createMenu menu-name parent {
+ { label function data [options...] }
+ { label function data [options...] }
+ (etc.)
+ }
+</pre>
+<p>
+where
+<p>
+<pre>
+ menu-name is the object name for the menu popup shell
+ parent is the parent widget of the menu shell
+ label is a menu item label
+ function is the function to be performed when the menu
+ item is selected, e.g., f.exec, f.data, f.space, or f.line.
+ data is function dependent data
+ options are option-name option-value pairs, as specified
+ below.
+</pre>
+<p>
+In the item list the fields label and option-value may be any Tcl expression.
+Expressions are evaluated in the server context. The data field is a Tcl
+script to be executed when the menu item is selected.
+<p>
+Options are specified as "option option-value". The menu item options are
+as follows.
+<p>
+<pre>
+ bitmap A bitmap to be displayed left justified in the label field
+ (e.g. to indicate a parameter setting).
+ sensitive Specifies whether the menu item is active (sensitive=true)
+ or inactive (sensitive=false, item grayed out).
+ accelerator Specifies an input translation (accelerator, e.g.,
+ keyboard event) which can be used to execute the
+ menu item.
+</pre>
+<p>
+The option-value field may be any Tcl expression.
+<p>
+Example:
+<p>
+<pre>
+ createMenu fileMenu toplevel {
+ { "File Menu" f.title}
+ { Open f.exec openFile}
+ { Save f.exec saveFile}
+ { Load f.menu loadMenu}
+ { no-label f.line }
+ { Quit f.exec "send client Quit" }
+ }
+</pre>
+<p>
+The first createMenu is called for a given menu the menu is created, added
+to the menu list, and all window system widgets are created for the menu.
+Subsequent calls will result in only the changed parts of the menu being
+altered provided the changes are not great. Hence this routine can be called
+to efficiently modify a menu when minor runtime changes occur, e.g., an
+item label or action changes, the item value changes state, and so on,
+without need for the GUI code to know how to make the necessary detailed
+changes to the widgets used to implement the menu.
+<p>
+<h1><A NAME="destroyMenu">destroyMenu</A></h1>
+<p>
+Destroy a menu. This can be used to free up the resources used by a
+menu, e.g., if the menu is not expected to be needed again for a while.
+<p>
+Usage:
+<p>
+<pre>
+ destroyMenu menu-name
+</pre>
+<p>
+<h1><A NAME="createBitmap">createBitmap</A></h1>
+<p>
+Create a named bitmap. This replaces any old bitmap of the same name. The
+new bitmap is cached in server memory; when a widget bitmap resource is set,
+the bitmap cache will be searched for the named bitmap before asking Xlib
+to find the bitmap.
+<p>
+Usage:
+<p>
+<pre>
+ createBitmap name width height data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createBitmap foo 16 16 {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+<p>
+<h1><A NAME="createCursor">createCursor</A></h1>
+<p>
+Create a cursor from bitmap data. The cursor is entered into the server's
+cursor cache and will override any existing entry of the same name.
+<p>
+Usage:
+<p>
+<pre>
+ createCursor name source mask fg_color bg_color x_hot y_hot
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createCursor foo bitmap1 bitmap2 black white 8 8
+</pre>
+<p>
+The named bitmaps must be created first with createBitmap.
+<p>
+<h1><A NAME="createPixmap">createPixmap</A></h1>
+<p>
+Create a named pixmap. This replaces any old pixmap of the same name. The
+new pixmap is cached in server memory; when a widget pixmap resource is set,
+the pixmap cache will be searched for the named pixmap before asking Xlib
+to find the pixmap.
+<p>
+Usage:
+<p>
+<pre>
+ createPixmap name width height depth fg_color bg_color data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createPixmap foo 16 16 8 black white {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+</pre>
+<p>
+<h1><A NAME="print">print</A></h1>
+<p>
+Print a string on the standard output. This is used mainly for debugging
+user interfaces.
+<p>
+Usage:
+<p>
+<pre>
+ print arg [arg ...]
+</pre>
+<p>
+<h1><A NAME="send">send</A></h1>
+<p>
+Send a message to an object. The object interprets the message and returns
+a function value as the string result of the TCL command.
+<p>
+Usage
+<p>
+<pre>
+ send &lt;object&gt; &lt;message&gt;
+</pre>
+<p>
+<h1><A NAME="postActivateCallback">postActivateCallback</A></h1>
+<p>
+Post a callback procedure to be called when the UI is activated. The UI is
+activated when it is first downloaded to server, but it may also be
+activated (reactivated) after the application has exited and is later
+restarted, or when the UI is deactivated and reactivated. Note
+that the UI state vis-a-vis the external world (client application) may
+no longer be accurate after it has been idle for a time and then reactivated.
+<p>
+Usage:
+<p>
+<pre>
+ postActivateCallback &lt;procedure&gt;
+</pre>
+<p>
+<p>
+<h1><A NAME="postTimedCallback">postTimedCallback</A></h1>
+<p>
+Post a callback to call the named procedure back after a specified delay
+in milliseconds.
+<p>
+Usage:
+<p>
+<pre>
+ id = postTimedCallback procedure msec [client-data]
+</pre>
+<p>
+After the specified delay the user callback procedure will be called with
+client_data (if given) as the single argument. Only one call will be made;
+the client must repost the callback in each call if the procedure is to be
+repeatedly executed.
+<p>
+An ID value is returned which may be passed to deleteTimedCallback to delete
+the timer.
+<p>
+<h1><A NAME="deleteTimedCallback">deleteTimedCallback</A></h1>
+<p>
+Delete a timer callback procedure. This procedure is typically used to
+break a timer loop, where the timer procedure repeatedly reposts itself at
+the end of each interval.
+<p>
+Usage:
+<p>
+<pre>
+ deleteTimedCallback id
+</pre>
+<p>
+The ID string is returned by postTimedCallback when a timer is posted.
+<p>
+<h1><A NAME="postWorkCallback">postWorkCallback</A></h1>
+<p>
+Post a callback for a procedure to be called when the server is idle.
+Work procedures are used to perform computations in the background while
+the user interface remains active and able to respond to input events.
+This works only if the user work procedure does its job in small increments,
+doing only a small amount of processing in each call. The work procedure
+will be called repeatedly until it returns a status indicating that it has
+finished its task.
+<p>
+Usage:
+<p>
+<pre>
+ id = postWorkCallback procedure [client-data]
+</pre>
+<p>
+When the server has nothing else to do the user work procedure will be
+called with client_data (if given) as the single argument. The work procedure
+should return the string "done" when all processing is finished, or any other
+string if the procedure is to be called again.
+<p>
+An ID value is returned which may be passed to deleteWorkCallback to delete
+the work procedure.
+<p>
+<h1><A NAME="deleteWorkCallback">deleteWorkCallback</A></h1>
+<p>
+Delete a work callback procedure.
+<p>
+Usage:
+<p>
+<pre>
+ deleteWorkCallback id
+</pre>
+<p>
+The ID string is returned by postWorkCallback when a work procedure is posted.
diff --git a/vendor/x11iraf/obm/docs/gui.doc/softgui.gif b/vendor/x11iraf/obm/docs/gui.doc/softgui.gif
new file mode 100644
index 00000000..7e287b10
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/softgui.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/tcl.gif b/vendor/x11iraf/obm/docs/gui.doc/tcl.gif
new file mode 100644
index 00000000..804a4afb
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/tcl.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/tcl.html b/vendor/x11iraf/obm/docs/gui.doc/tcl.html
new file mode 100644
index 00000000..259192f2
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/tcl.html
@@ -0,0 +1,7 @@
+<title>Tcl page</title>
+<h1>Tcl page</h1>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+<a href="book.p1.ps"><h2>John Ousterhout's Tcl book</a> (over 700 Kbytes of PostScript)</h2>
+<p>
+<a href="TclQuickRef.html"><h2>Tcl Quick Reference</h2></a>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/uiparameterclass.html b/vendor/x11iraf/obm/docs/gui.doc/uiparameterclass.html
new file mode 100644
index 00000000..fe189fc5
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/uiparameterclass.html
@@ -0,0 +1,107 @@
+<title>UI PARAMETER class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> UI PARAMETER class</h1>
+<p>
+<HR>
+<p>
+The UI parameter class is used for client-UI communications. The client
+does not control the user interface directly, rather the UI defines a set
+of abstract UI parameters, and during execution the client application
+assigns values to these parameters. These UI parameters should be thought
+of as describing the runtime state of the client as viewed by the GUI.
+The GUI is free to interpret this state information in any way, including
+ignoring it. Many GUIs can be written which use the same client state
+as described by the UI parameters.
+<p>
+Assigning a value to a UI parameter causes the new value to be stored, and
+any parameter action procedures registered by the UI to be called.
+The action or actions [if any] taken when a parameter value changes are
+arbitrary, e.g. the action might be something as simple as changing a
+displayed value of a UI widget, or something more complex like displaying
+a popup.
+<p>
+UI Parameter class commands:
+<p>
+<pre>
+ <a href="#getValue">getValue</a>
+ <a href="#setValue">setValue</a> &lt;new-value&gt;
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt;
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#notify">notify</a>
+</pre>
+<p>
+The most common usage is for the GUI to post one or more callbacks for
+each UI parameter. When the UI parameter value is changed [with setValue,
+e.g. by the client] the GUI callback procedures are called with the old
+and new UI parameter values on the command line. addCallback is used to
+add a callback procedure, and deleteCallback to delete one. Multiple
+callbacks may be registered for a single UI parameter. notify is used
+to simulate a parameter value change, causing any callback procedures to
+be invoked.
+<p>
+The callback procedure is called as follows:
+<p>
+<pre>
+ user-procedure param-name {old-value} {new-value}
+</pre>
+<p>
+The important thing to note here is that the old and new value strings
+are quoted with braces. This prevents any interpretation of the string
+by Tcl when the callback is executed, which is necessary because the
+strings can contain arbitrary data. When Tcl calls the callback the
+first level of braces will be stripped off, leaving old-value and new-value
+each as a single string argument.
+<p>
+<p>
+<h2><A NAME="setValue">setValue</A></h2>
+<p>
+Set the value of a parameter, and notify all clients
+via the posted callback procedures that the parameter value has changed.
+<p>
+Usage:
+<p>
+<pre>
+ setValue &lt;new-value&gt;
+</pre>
+<p>
+<h2><A NAME="getValue">getValue</A></h2>
+<p>
+Get the value of a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ getValue
+</pre>
+<p>
+<h2><A NAME="notify">notify</A></h2>
+<p>
+Notify the registered clients of a parameter as if the
+value had changed.
+<p>
+Usage:
+<p>
+<pre>
+ notify
+</pre>
+<p>
+<h2><A NAME="addCallback">addCallback</A></h2>
+<p>
+Add a callback procedure to the callback list for
+a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h2><A NAME="deleteCallback">deleteCallback</A></h2>
+<p>
+Delete a callback procedure previously registered
+for a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/widgetclass.html b/vendor/x11iraf/obm/docs/gui.doc/widgetclass.html
new file mode 100644
index 00000000..78d534db
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/widgetclass.html
@@ -0,0 +1,450 @@
+<title>WIDGET class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> WIDGET class</h1>
+<p>
+<HR>
+<p>
+The Widget class is the generic or base class for the window system
+toolkit widgets supported by the object manager. The Widget class
+supports a number of different Xt widget classes using a table driven
+approach to describe each widget. Any widget may be created, destroyed,
+and manipulated in various ways using only the generic Widget class
+procedures and Widget-specific resources. The Widget class may be
+subclassed to support complex Widgets that require custom class-specific
+commands for use by the GUI code.
+<p>
+Generic Widget-class commands:
+<p>
+<pre>
+ <a href="#set">set</a> &lt;resource-name&gt; &lt;value&gt;
+ <a href="#get">get</a> &lt;resource-name&gt;
+<p>
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt; [<callback-name>]
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#setSensitive">setSensitive</a> &lt;sensitive&gt;
+ <a href="#isSensitive">isSensitive</a>
+<p>
+ <a href="#realize">realize</a>
+ <a href="#unrealize">unrealize</a>
+ <a href="#isRealized">isRealizeed</a>
+ <a href="#map">map</a>
+ <a href="#unmap">unmap</a>
+ <a href="#manage">manage</a> child [child ...]
+ <a href="#unmanage">unmanage</a> child [child ...]
+ <a href="#popup">popup</a> [grab-kind]
+ <a href="#popdown">popdown</a>
+ <a href="#popupSpringLoaded">popupSpringLoaded</a>
+<p>
+ <a href="#move">move</a> &lt;x&gt; &lt;y&gt;
+ <a href="#resize">resize</a> &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+ <a href="#configure">configure</a> &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+The most important Widget commands are set/get resource, and the
+callbacks. The widget sensitivity can be set and queried using set/get
+resource, but special procedures are provided to make this common operation
+more convenient.
+<p>
+Class specific functions:
+<p>
+<pre>
+ <a href="#append">append</a> text # text widget
+ <a href="#setList">setList</a> list [resize] # list widget
+ value = <a href="#getItem">getItem</a> itemno
+ <a href="#highlight">highlight</a> itemno
+ <a href="#unhighlight">unhighlight</a>
+</pre>
+<p>
+Ideally the widget class should be subclassed for widgets that require
+class-specific functions, but in simple cases involving standard widgets
+the support is built into the widget class code as a special case.
+<p>
+Special actions (used in translations):
+<p>
+<pre>
+ <a href="#do_userproc">call</a> (proc [,arg, ...])
+ <a href="#do_popup">popup</a> (menu-name [xoffset [yoffset]])
+ <a href="#do_popdown">popdown</a> (menu-name)
+</pre>
+<p>
+The "call" action is a very general mechanism which allows any GUI procedure
+to be registered with any translation using the X translation table
+mechanism. The popup and popdown actions are used for popup menus. The
+menu will be popped up at the event coordinates plus the optional offsets
+if given.
+<p>
+Event handling:
+<p>
+<pre>
+ <a href="#addEventHandler">addEventHandler</a> &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+Event callback:
+<p>
+<pre>
+ <a href="#userEventHandler">userEventHandler</a> widget event-type time wx wy rx ry other
+</pre>
+<p>
+In most cases translations are preferable to events, but a GUI can capture
+raw events if it wishes by adding event handlers. Nearly all of the X
+event types are supported. The callback syntax employs a number of
+standard arguments, followed by a number of event-specific arguments.
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Add a callback procedure to the callback list for
+a widget. If no callback name is given, "callback" is assumed.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback <procedure-name> [&lt;callback-name&gt;]
+</pre>
+<p>
+Specific widgets only support certain types of callbacks. There is no
+checking that the callback type specified is supported by a widget; the
+wrong type of callback can be registered, but it will never be called.
+<p>
+<h1><A NAME="deleteCallback">deleteCallback</A></h1>
+<p>
+Delete a callback procedure previously registered
+for a widget.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h1><A NAME="do_userproc">do_userproc (call)</A></h1>
+<p>
+Translation action procedure used to call general user
+action procedures in the interpreter. The name of the user procedure to
+be called is given as the first argument in the translation. For example,
+the translation "call(foo,a,b,c)" would cause procedure foo to be called
+with the arguments (a,b,c). The following arguments are special:
+<p>
+<pre>
+ Argument Replaced by
+<p>
+ $name object name of widget
+ $time event->time
+ $x event->x
+ $y event->y
+ $x_root event->x_root
+ $y_root event->y_root
+</pre>
+<p>
+The "user procedure" can be any server procedure.
+<p>
+<h1><A NAME="do_popup">do_popup</A></h1>
+<p>
+Popup a menu (or other spring loaded popup) at the location
+of the event which triggered this action.
+<p>
+Usage:
+<p>
+<pre>
+ popup(menu-name [xoffset [yoffset]])
+</pre>
+<p>
+<h1><A NAME="do_popdown">do_popdown</A></h1>
+<p>
+Pop down a menu.
+<p>
+Usage:
+<p>
+<pre>
+ popdown(menu-name)
+</pre>
+<p>
+<h1><A NAME="set">set</A></h1>
+<p>
+Set a widget resource.
+<p>
+Usage:
+<p>
+<pre>
+ set &lt;resource-name&gt; &lt;value&gt;
+</pre>
+<p>
+<h1><A NAME="get">get</A></h1>
+<p>
+Get a widget resource value as a string.
+<p>
+Usage:
+<p>
+<pre>
+ get &lt;resource-name&gt;
+</pre>
+<p>
+<h1><A NAME="append">append</A></h1>
+<p>
+Append data to a text widget.
+<p>
+Usage:
+<p>
+<pre>
+ append &lt;text&gt;
+</pre>
+<p>
+<h1><A NAME="setList">setList</A></h1>
+<p>
+Set the item list of a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ setList list [resize]
+</pre>
+<p>
+The list is a simple list of strings, passed as a single string argument to
+setList (quotes, braces, etc. may be used to quote strings containing
+special characters).
+<p>
+<h1><A NAME="getItem">getItem</A></h1>
+<p>
+Get an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ value = getItem itemno
+</pre>
+<p>
+If ITEMNO is a number the indicated list item is returned, or the string
+"EOF" if the requested item is beyond the end of the list. Otherwise the
+currently selected item is returned, and the index of the item is returned
+in the output variable ITEMNO. If no item is currently selected ITEMNO
+will be set to "none" on output.
+<p>
+<h1><A NAME="highlight">highlight</A></h1>
+<p>
+Highlight an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ highlight itemno
+</pre>
+<p>
+The indicated item of the list is highlighted as if the item had been
+selected by the user. Any previously highlighted item is unhighlighted.
+<p>
+<h1><A NAME="unhighlight">unhighlight</A></h1>
+<p>
+Unhighlight the currently highlighted item in a
+list widget.
+<p>
+Usage:
+<p>
+<pre>
+ unhighlight
+</pre>
+<p>
+Any currently highlighted item in the list widget is unhighlighted.
+<p>
+<h1><A NAME="realize">realize</A></h1>
+<p>
+Realize a widget. This activates and assigns windows for
+a widget and all of its descendants. Realizing a widget does not in itself
+cause it to appear on the screen.
+<p>
+Usage:
+<p>
+<pre>
+ realize
+</pre>
+<p>
+<h1><A NAME="unrealize">unrealize</A></h1>
+<p>
+Unrealize a widget. This destroys the windows assigned
+to a widget and all of its descendants.
+<p>
+Usage:
+<p>
+<pre>
+ unrealize
+</pre>
+<p>
+<h1><A NAME="isRealized">isRealized</A></h1>
+<p>
+Test whether a widget is realized.
+<p>
+Usage:
+<p>
+<pre>
+ isRealized
+</pre>
+<p>
+<h1><A NAME="map">map</A></h1>
+<p>
+Map a widget.
+<p>
+Usage:
+<p>
+<pre>
+ map
+</pre>
+<p>
+<h1><A NAME="unmap">unmap</A></h1>
+<p>
+Unmap a widget.
+<p>
+Usage:
+<p>
+<pre>
+ unmap
+</pre>
+<p>
+<h1><A NAME="manage">manage</A></h1>
+<p>
+Manage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Managing the
+children makes them appear in the window, possibly causing the other
+children to be rearranged in the window.
+<p>
+Usage:
+<p>
+<pre>
+ manage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h1><A NAME="unmanage">unmanage</A></h1>
+<p>
+Unmanage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Unmanaging the
+children makes them disappear from the window and be removed from geometry
+management, possibly causing the other children to be rearranged in the
+window.
+<p>
+Usage:
+<p>
+<pre>
+ unmanage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h1><A NAME="popup">popup</A></h1>
+<p>
+Popup a shell widget. If no grab is indicated the popup
+can remain up while other windows accept input.
+<p>
+Usage:
+<p>
+<pre>
+ popup [grab-kind]
+</pre>
+<p>
+<h1><A NAME="popdown">popdown</A></h1>
+<p>
+Popdown a shell widget.
+<p>
+Usage:
+<p>
+<pre>
+ popdown
+</pre>
+<p>
+<h1><A NAME="popupSpringLoaded">popupSpringLoaded</A></h1>
+<p>
+Popup a shell widget, e.g., a popup menu.
+This implies an exclusive grab.
+<p>
+Usage:
+<p>
+<pre>
+ popupSpringLoaded
+</pre>
+<p>
+<h1><A NAME="move">move</A></h1>
+<p>
+Move a widget to the given window relative coordinates.
+<p>
+Usage:
+<p>
+<pre>
+ move &lt;x&gt; &lt;y&gt;
+</pre>
+<p>
+<h1><A NAME="resize">resize</A></h1>
+<p>
+Resize a widget.
+<p>
+Usage:
+<p>
+<pre>
+ resize &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h1><A NAME="configure">configure</A></h1>
+<p>
+Configure a widget, i.e., execute a simultaneous
+move and resize.
+<p>
+Usage:
+<p>
+<pre>
+ configure &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h1><A NAME="setSensitive">setSensitive</A></h1>
+<p>
+Set the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ setSensitive &lt;sensitive&gt;
+</pre>
+<p>
+<h1><A NAME="isSensitive">isSensitive</A></h1>
+<p>
+Test the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ isSensitive
+</pre>
+<p>
+<h1><A NAME="addEventHandler">addEventHandler</A></h1>
+<p>
+Add a custom event handler to a widget. A list
+of event masks is given to define the classes of events the user supplied
+event handling procedure is to receive.
+<p>
+Usage:
+<p>
+<pre>
+ addEventHandler &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+<h1><A NAME="removeEventHandler">removeEventHandler</A></h1>
+<p>
+Remove an event handler previously posted
+with addEventHandler, above.
+<p>
+Usage:
+<p>
+<pre>
+ removeEventHandler procname
+</pre>
+<p>
+<h1><A NAME="event">event</A></h1>
+<p>
+Generic event handler called when a widget event handler
+posted by addEventHandler is called.
+<p>
+The user event handler is called as
+<p>
+<pre>
+ userEventHandler widget event-type time wx wy rx ry other
+</pre>
+<p>
+where "other" is an event-type specific list of fields describing the
+the event.
diff --git a/vendor/x11iraf/obm/docs/gui.doc/widgets.gif b/vendor/x11iraf/obm/docs/gui.doc/widgets.gif
new file mode 100644
index 00000000..17f9371e
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/widgets.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/gui.doc/widgets.html b/vendor/x11iraf/obm/docs/gui.doc/widgets.html
new file mode 100644
index 00000000..af80a997
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/widgets.html
@@ -0,0 +1,14 @@
+<title>The Widgets</title>
+<h1><IMG SRC="irafgui.gif"> Widgets</h1>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<p>
+The basic widgets available to the IRAF GUI implimenter are the Athena
+Widgets, the gterm widget, the image display widget, and markers.
+<p>
+<pre>
+<a href="athena.html"><IMG ALIGN=MIDDLE SRC="athena.gif"></a> Athena widgets <a href="notyet2.html"><IMG ALIGN=MIDDLE SRC="gterm.gif"></a> Gterm widget
+
+<a href="notyet2.html"><IMG ALIGN=MIDDLE SRC="imtool.gif"></a> Imtool widget <a href="notyet2.html"><IMG ALIGN=MIDDLE SRC="marker.gif"></a> Marker widgets
+
+<a href="parameterwidget.html"><IMG ALIGN=MIDDLE SRC="params.gif"></a> Parameters
+</pre>
diff --git a/vendor/x11iraf/obm/docs/gui.doc/ximclient.html b/vendor/x11iraf/obm/docs/gui.doc/ximclient.html
new file mode 100644
index 00000000..12eac899
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/gui.doc/ximclient.html
@@ -0,0 +1,194 @@
+<title>XIMCLIENT</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> XIMCLIENT</h1>
+<p>
+<HR>
+<p>
+The Ximtool "client" object. This code implements an OBM client and
+responds to messages sent to the client object by the GUI code executing
+under the object manager.
+<p>
+Client commands:
+<p>
+<pre>
+ <a href="#setFrame">setFrame</a> frameno
+ frameno = <a href="#getFrame">getFrame</a> [raster]
+ <a href="#nextFrame">nextFrame</a>
+ <a href="#prevFrame">prevFrame</a>
+ <a href="#matchFrames">matchFrames</a> [frame]
+ <a href="#fitFrame">fitFrame</a>
+
+ <a href="#setColormap">setColormap</a> colormap
+ <a href="#windowColormap">windowColormap</a> offset scale
+ <a href="#zoom">zoom</a> [mag | xmag ymag [ xcen ycen ]]
+ <a href="#zoom">zoomAbs</a> [mag | xmag ymag [ xcen ycen ]]
+ <a href="#pan">pan</a> xcen ycen
+ <a href="#flip">flip</a> axis [axis ...]
+
+
+ wcsstr = <a href="#encodewcs">encodewcs</a> sx sy sz
+ <a href="#retCursorVal">retCursorVal</a> sx sy [frame [wcs [key [strval]]]]
+
+ <a href="#Quit">Quit</a>
+</pre>
+<p>
+XIMTOOL CLIENT commands.
+<p>
+<h1><A NAME="Quit">Quit</A></h1>
+<p>
+Exit ximtool.
+<p>
+Usage:
+<p>
+<pre>
+ Quit
+</pre>
+<p>
+<h1><A NAME="setFrame">setFrame</A></h1>
+<p>
+Set the frame to be displayed.
+<p>
+Usage:
+<p>
+<pre>
+ setFrame <frameno>
+</pre>
+<p>
+<h1><A NAME="getFrame">getFrame</A></h1>
+<p>
+Get the frame number.
+<p>
+Usage:
+<p>
+<pre>
+ getFrame [raster]
+</pre>
+<p>
+This routine has two forms. When called with no argument getFrame returns
+the current display frame. When called with a raster number getFrame
+returns the frame number with which the raster is associated.
+<p>
+<h1><A NAME="nextFrame">nextFrame</A></h1>
+<p>
+Display the next frame in sequence.
+<p>
+Usage:
+<p>
+<pre>
+ nextFrame
+</pre>
+<p>
+<h1><A NAME="prevFrame">prevFrame</A></h1>
+<p>
+Display the previous frame in sequence.
+<p>
+Usage:
+<p>
+<pre>
+ prevFrame
+</pre>
+<p>
+<h1><A NAME="matchFrames">matchFrames</A></h1>
+<p>
+Set the enhancement of all frames to match the current
+display frame.
+<p>
+Usage:
+<p>
+<pre>
+ matchFrames [frame]
+</pre>
+<p>
+<h1><A NAME="fitFrame">fitFrame</A></h1>
+<p>
+Attempt to make the display window the same size as the frame
+buffer.
+<p>
+Usage:
+<p>
+<pre>
+ fitFrame
+</pre>
+<p>
+<h1><A NAME="setColormap">setColormap</A></h1>
+<p>
+Set the colormap for the current display frame.
+<p>
+Usage:
+<p>
+<pre>
+ setColormap <colormap>
+</pre>
+<p>
+<h1><A NAME="windowColormap">windowColormap</A></h1>
+<p>
+Set the colormap for the current display frame.
+<p>
+Usage:
+<p>
+<pre>
+ windowColormap <offset> <scale>
+</pre>
+<p>
+<h1><A NAME="zoom">zoom, zoomAbs</A></h1>
+<p>
+Set the zoom factors for the current frame to the given values.
+A zoom factor > 1 enlarges the image, < 1 shrinks the image, 1.0 maps
+one source pixel to one destination pixel.
+<p>
+Usage:
+<p>
+<pre>
+ zoom <xymag> 1 argument
+ zoom <xmag> <ymag> 2 arguments
+ zoom <xmag> <ymag> <xcen> <ycen> 4 arguments
+</pre>
+<p>
+When called as "zoom" the magnification is relative to the fixed scaling,
+if any, used to scale the frame to fit the display window at mag=1.0.
+When called as zoomAbs" the magnification given is the actual scale factor
+used to map raster pixels to display pixels.
+<p>
+<h1><A NAME="pan">pan</A></h1>
+<p>
+Pan the current frame, i.e., change the view center.
+<p>
+Usage:
+<p>
+<pre>
+ pan <xcen> <ycen>
+</pre>
+<p>
+<h1><A NAME="flip">flip</A></h1>
+<p>
+Flip the current display frame in the indicated axis or axes.
+<p>
+Usage:
+<p>
+<pre>
+ flip [axis [axis ...]]
+</pre>
+<p>
+<h1><A NAME="retCursorVal">retCursorVal</A></h1>
+<p>
+Return a cursor value to the ximtool client process. This
+should be executed by the GUI to terminate a cursor read.
+<p>
+Usage:
+<p>
+<pre>
+ retCursorVal sx sy [frame [wcs [key [strval]]]]
+</pre>
+<p>
+<h1><A NAME="encodewcs">encodewcs</A></h1>
+<p>
+Convert raw screen coordinates x,y,z (z=pixel value) to
+world coordinates using the WCS passed to ximtool by the client application
+when the frame was loaded. The encoded description of the current position
+and pixel value is returned to the GUI as a string value.
+<p>
+Usage:
+<p>
+<pre>
+ string = encodewcs sx sy sz
+</pre>
+<p>
diff --git a/vendor/x11iraf/obm/docs/obm/Client.html b/vendor/x11iraf/obm/docs/obm/Client.html
new file mode 100644
index 00000000..407c177b
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Client.html
@@ -0,0 +1,75 @@
+<title>CLIENT class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> CLIENT class</h1>
+<p>
+<HR>
+<p>
+The client is the client application, which provides the functionality
+underlying the UI. When a message is sent to the client object it usually
+results in a message being sent to the client *application*, usually an
+external program communicating via IPC, which has little or no knowledge
+of the UI. The client application receives and executes commands delivered
+by the UI via the client object. Output from the client may or may not
+come back to the object manager. That portion of the output which comes
+back to the object manager is in the form of assignments of string values
+to <a href="uiparameterclass.html">UI parameter-class objects</a> (another
+way of thinking of this is that
+messages or events are sent to and acted upon by the parameter objects).
+Hence, the client object is output only so far as the client application
+is concerned.
+<p>
+The Client-class commands are used to send a message to the client.
+<p>
+<pre>
+ <a href="#gkey">gkey</a> &lt;key&gt;
+ <a href="#gcmd">gcmd</a> &lt;command-string&gt;
+ <a href="#literal">literal</a> &lt;command&gt;
+</pre>
+<p>
+or just &lt;command&gt;, e.g., "send client &lt;command&gt;" will work in most cases.
+<p>
+<a href="#gkey">GKEY</a> sends an IRAF graphics keystroke.
+<a href="#gcmd">GCMD</a> sends an
+IRAF graphics colon command. <a href="#literal">LITERAL</a> sends a literal
+command string to the
+client. The keyword "literal" may optionally be omitted, i.e., "send client
+foo" and "send client literal foo" are the same. The keyword "literal" may
+be used to ensure that the client command string which follows will not
+be interpreted as a Client-class command (such as gkey, gcmd, or literal).
+<p>
+<p>
+<h1><A NAME="gcmd">gcmd</A></h1>
+<p>
+Send a graphics command string to the client application.
+A graphics command string is a graphics cursor value with the key set
+to `:' and the command string given as the string part of the cursor
+value. The protocol module which posted the client output procedure is
+responsible for encoding and sending the cursor command.
+<p>
+Usage:
+<p>
+<pre>
+ gcmd &lt;command-string&gt;
+</pre>
+<p>
+<h1><A NAME="gkey">gkey</A></h1>
+<p>
+Send a graphics key event to the client application.
+A graphics key event is a graphics cursor value with the key set to some
+integer value and a null string part.
+<p>
+Usage:
+<p>
+<pre>
+gkey &lt;key&gt;
+</pre>
+<p>
+<h1><A NAME="literal">literal</A></h1>
+<p>
+Send a literal command to the client application.
+<p>
+Usage:
+<p>
+<pre>
+ literal &lt;command&gt;
+</pre>
+
diff --git a/vendor/x11iraf/obm/docs/obm/Gterm.html b/vendor/x11iraf/obm/docs/obm/Gterm.html
new file mode 100644
index 00000000..5fcdab10
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Gterm.html
@@ -0,0 +1,694 @@
+<title>Gterm-Image widget class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> Gterm-Image widget class (a subclass of Widget).</h1>
+<p>
+<HR>
+<p>
+The gterm-image widget is a general 2D graphics-imaging widget providing
+a wide range of facilities for drawing graphics and text, for image
+display, and for graphics interaction. Normally the client communicates
+directly with the Gterm widget to draw graphics, download image data,
+and so on, using some communications protocol outside the domain of the
+object manager. Nonetheless so far as possible the facilities of the Gterm
+widget have also been made available to GUI code via the commands listed
+here.
+<p>
+The Gterm widget adds the following function to the OBM library.
+<p>
+<pre>
+ ObmPostSetGtermCallback (obm, &setgterm, setgterm_client_data)
+</pre>
+<p>
+This is called by a client application to post a procedure to be called
+when a gterm widget receives the setGterm command. The calling sequence
+for setGterm callback is as follows:
+<p>
+<pre>
+ setgterm (client_data, gterm_widget)
+</pre>
+<p>
+The purpose of this callback is to tell the client which gterm widget is
+the "active" gterm widget. This is used by clients which only support
+one active Gterm widget, i.e., which can only direct graphics output to
+one Gterm widget at a time.
+<p>
+The messages or commands that can be sent to the Gterm widget by GUI
+code follow.
+<p>
+General commands:
+<p>
+<pre>
+ <a href="#setGterm">setGterm</a> # make widget the active Gterm
+<p>
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a>
+ <a href="#addCallback">addCallback</a> procedure-name callback-type
+ <a href="#reset">reset</a>
+ <a href="#flush">flush</a>
+<p>
+ <a href="#setCursorPos">setCursorPos</a> x y [raster]
+ <a href="#getCursorPos">getCursorPos</a> x y
+ <a href="#setCursorType">setCursorType</a> cursortype
+ <a href="#bell">bell</a>
+</pre>
+<p>
+Graphics drawing commands:
+<p>
+<pre>
+ <a href="#setRaster">setRaster</a> raster
+ raster = <a href="#getRaster">getRaster</a> [raster]
+<p>
+ <a href="notyet.html">setLogRes</a> width height (unimplimented)
+ <a href="notyet.html">getLogRes</a> width height (unimplimented)
+ <a href="notyet.html">setPhysRes</a> width height (unimplimented)
+ <a href="notyet.html">getPhysRes</a> width height (unimplimented)
+ <a href="notyet.html">setTextRes</a> rows cols (unimplimented)
+ <a href="notyet.html">setDataLevel</a> level (unimplimented)
+ <a href="notyet.html">setLineWidth</a> width (unimplimented)
+ <a href="notyet.html">setLineStyle</a> style (unimplimented)
+ <a href="notyet.html">setColorIndex</a> index (unimplimented)
+ <a href="notyet.html">setFillType</a> filltype (unimplimented)
+<p>
+ <a href="#clearScreen">clearScreen</a>
+ <a href="notyet.html">drawPolyline</a> vector (unimplimented)
+ <a href="notyet.html">drawPolymarker</a> vector (unimplimented)
+ <a href="notyet.html">drawPolygon</a> vector (unimplimented)
+ <a href="notyet.html">drawMarker</a> x y xsize ysize type (unimplimented)
+<p>
+ <a href="notyet.html">drawAlphaText</a> x y text (unimplimented)
+ <a href="notyet.html">getAlphaTextSize</a> string width height base (unimplimented)
+ <a href="notyet.html">startDialog</a> (unimplimented)
+ <a href="notyet.html">endDialog</a> (unimplimented)
+ <a href="notyet.html">eraseDialog</a> (unimplimented)
+ <a href="notyet.html">drawDialogText</a> x y text (unimplimented)
+ <a href="notyet.html">getDialogTextSize</a> string width height base (unimplimented)
+</pre>
+<p>
+The coordinates used in the graphics drawing commands are logical
+coordinates as defined by setLogRes, in the coordinate system of the
+reference drawing raster as defined by setRaster. The default reference
+raster is raster zero, the widget's window. Vectors are specified as
+a list of points, e.g., { {x y} {x y} ... }.
+<p>
+Imaging commands:
+<p>
+<pre>
+ <a href="#rasterInit">rasterInit</a>
+ <a href="notyet.html">assignRaster</a> raster drawable (unimplimented)
+ <a href="notyet.html">createRaster</a> raster type width height depth (unimplimented)
+ <a href="notyet.html">destroyRaster</a> raster (unimplimented)
+ exists = <a href="notyet.html">queryRaster</a> raster type width height depth (unimplimented)
+ raster = <a href="notyet.html">nextRaster</a> [raster] (unimplimented)
+ nrasters = <a href="notyet.html">nRasters</a> [nrasters] (unimplimented)
+<p>
+ <a href="#setPixel">setPixel</a> raster x y value
+ value = <a href="#getPixel">getPixel</a> raster x y
+ <a href="#writePixels">writePixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="#readPixels">readPixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="notyet.html">refreshPixels</a> raster ct x1 y1 nx ny (unimplimented)
+ pixmap = <a href="notyet.html">createPixmap</a> src x y width height (unimplimented)
+ <a href="notyet.html">copyPixmap</a> pixmap dst x y width height (unimplimented)
+<p>
+ colormap = <a href="notyet.html">nextColormap</a> [colormap] (unimplimented)
+ <a href="notyet.html">freeColormap</a> colormap (unimplimented)
+ <a href="notyet.html">writeColormap</a> colormap first nelem colors (unimplimented)
+ <a href="notyet.html">readColormap</a> colormap first nelem colors (unimplimented)
+ <a href="#loadColormap">loadColormap</a> colormap offset scale
+<p>
+ <a href="notyet.html">initMappings</a> (unimplimented)
+ mapping = <a href="#nextMapping">nextMapping</a> [mapping]
+ <a href="notyet.html">freeMapping</a> mapping (unimplimented)
+ <a href="notyet.html">enableMapping</a> mapping (unimplimented)
+ <a href="notyet.html">disableMapping</a> mapping (unimplimented)
+ active = <a href="notyet.html">activeMapping</a> mapping (unimplimented)
+ <a href="notyet.html">refreshMapping</a> mapping (unimplimented)
+<p>
+ raster = <a href="#selectRaster">selectRaster</a> dras dt dx dy rt rx ry [map]
+ <a href="#unmapPixel">unmapPixel</a> sx sy raster rx ry [rz]
+<p>
+ <a href="notyet.html">copyRaster</a> rop src st sx sy snx sny dst dt dx dy dnx dny (unimplimented)
+ <a href="#setMapping">setMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#getMapping">getMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+<p>
+ <a href="#flip">flip</a> mapping axis [axis...]
+</pre>
+<p>
+Pixel arrays are long strings consisting either of a sequence of numeric
+pixel values separated by whitespace (space or newline), or a hex encoded
+sequence of bytes (2 hex digits per 8 bit pixel). Colors are specified
+as a list of RGB triplets, e.g., { {R G B} {R G B} ... }.
+<p>
+Refer to the documentation for the Gterm widget for a detailed description
+of rasters, mappings, and colormaps.
+<p>
+Markers:
+<p>
+<pre>
+ <a href="#createMarker">createMarker</a> name [attribute-list]
+ <a href="#markerInit">markerInit</a>
+</pre>
+<p>
+New markers may be created with createMarker. Once created, a marker
+functions under the Object Manager as a named object of class "marker".
+Refer to the marker class for a description of the commands defined for
+a marker.
+<p>
+gterm Actions List
+<p>
+<pre>
+ ignore
+ graphics-input
+ graphics-context
+ crosshair
+ track-cursor
+ enter-window
+ leave-window
+ popup-menu {not implemented}
+ reset
+ m_create
+</pre>
+<p>
+Default translations for Gterm window.
+Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu)
+<p>
+default Gterm Translations
+<p>
+<pre>
+ [Btn1Down]:m_create()
+ [Btn2Down]:crosshair(on)
+ [Btn2Motion]:crosshair(on)
+ [Btn2Up]:crosshair(off)
+ ~Ctrl ~Meta [Btn3Down]:graphics-context()
+ [EnterWindow]:enter-window()
+ [LeaveWindow]:leave-window()
+ [KeyPress]:graphics-input()
+ [Motion]:track-cursor()
+<pre>
+<p>
+<p>
+GTERM class commands.
+<p>
+<h1><A NAME="setGterm">setGterm</A></h1>
+<p>
+Set the active Gterm widget. A UI can have more than one
+gterm widget, but due to restrictions on the client-server interface, it
+may be possible for only one to receive client output at any one time (any
+gterm widget can generate input to be sent to the client). If the client
+has this restriction, the client-server interface code which uses OBM can
+call the ObmPostSetGtermCallback procedure to post a function to be called
+when the UI code calls the setGterm procedure.
+<p>
+Usage:
+<p>
+<pre>
+ setGterm
+</pre>
+<p>
+<h1><A NAME="activate">activate</A></h1>
+<p>
+Activate the gterm widget. This causes the next GIN mode
+setCursorType to warp the pointer into the gterm window.
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h1><A NAME="deactivate">deactivate</A></h1>
+<p>
+Deactivate the gterm widget. If the cursor has been warped
+into the window by a previous activate/setCursorType GIN mode, this causes
+the cursor to be warped back to where it was previously.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate
+</pre>
+<p>
+<h1><A NAME="reset">reset</A></h1>
+<p>
+Reset the gterm widget. This causes a number of state variables
+affecting graphics drawing options to be set to their default values.
+<p>
+Usage:
+<p>
+<pre>
+ reset
+</pre>
+<p>
+<h1><A NAME="flush">flush</A></h1>
+<p>
+Flush any graphics output and synchronize the state of the widget
+with what is shown on the display.
+<p>
+Usage:
+<p>
+<pre>
+ flush
+</pre>
+<p>
+The gterm widget uses XLIB, which buffers graphics drawing commands and
+automatically sends them to the X server when 1) the buffer fills,
+2) input is requested from the server. Such buffering of data is necessary
+for efficient operation and it should rarely be necessary to explicitly
+flush graphics output since XLIB does this automatically in most cases.
+An example of when explicitly flushing the ouptut might be necessary is in
+cases where smooth animation is desired and drawing the graphics in batches
+could cause the display to appear "jerky".
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Post a callback for a Gterm widget event.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure-name [callback-type]
+</pre>
+<p>
+The recognized Gterm callbacks are
+<p>
+<pre>
+
+ input Called when the graphics-input action is invoked in
+ a translation table. The default Gterm translation
+ table invokes this action when a KeyPress event occurs
+ in the Gterm window.
+ Callback: widget-name input-type event-data
+
+ resize Called when the gterm window is resized.
+ Callback: widget-name width height
+
+ reset Called when the "reset" action is invoked.
+ Callback: widget-name
+
+<pre>
+<p>
+If no callback is specified the default is "input".
+<p>
+Note that in GUI code one can also use the translation table to directly
+invoke GUI procedures without need to use the Gterm input mechanism. This
+is more flexible but we support the Gterm input callback here for
+applications that use the default translations.
+<p>
+<h1><A NAME="setCursorPos">setCursorPos</A></h1>
+<p>
+Warp the cursor (pointer) to the given coordinates. This
+is a graphics drawing command and if no raster number is specified the
+current reference drawing raster, as set with setRaster, defines the
+coordinate system.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorPos x y [raster]
+</pre>
+<p>
+A raster number may optionally given to define the raster coordinate system
+to be used. raster=0 yields screen coordinates.
+<p>
+<h1><A NAME="getCursorPos">getCursorPos</A></h1>
+<p>
+Get the cursor position (raster 0 or screen coordinates).
+<p>
+Usage:
+<p>
+<pre>
+ getCursorPos x y
+</pre>
+<p>
+<h1><A NAME="setCursorType">setCursorType</A></h1>
+<p>
+Set the cursor type.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorType cursor-type
+
+ idle default cursor
+ busy busy cursor, e.g, when program is busy
+ ginMode graphics input mode cursor, set when program is
+ waiting for graphics input
+</pre>
+<p>
+<h1><A NAME="bell">bell</A></h1>
+<p>
+Gterm widget sound output.
+<p>
+Usage:
+<p>
+<pre>
+ bell
+</pre>
+<p>
+<h1><A NAME="setRaster">setRaster</A></h1>
+<p>
+Set the number of the raster to be used to define the drawing
+context (e.g. coordinate system) for graphics and text drawing functions.
+<p>
+Usage:
+<p>
+<pre>
+ setRaster raster-number
+</pre>
+<p>
+<h1><A NAME="getRaster">getRaster</A></h1>
+<p>
+Get the number of the raster which defines the drawing
+context, as set in the last setRaster call.
+<p>
+Usage:
+<p>
+<pre>
+ raster = getRaster [raster]
+</pre>
+<p>
+If the name of a variable is given the raster number will be stored
+directly in that variable.
+<p>
+<h1><A NAME="clearScreen">clearScreen</A></h1>
+<p>
+Clear the "screen", i.e., window. This action clears the
+drawing window and sets a number of drawing state variables to their default
+values.
+<p>
+Usage:
+<p>
+<pre>
+ clearScreen
+</pre>
+<p>
+<h1><A NAME="rasterInit">rasterInit</A></h1>
+<p>
+Initialize the raster subsystem, deleting all rasters and
+mappings and freeing the dynamic part of the colortable.
+<p>
+Usage:
+<p>
+<pre>
+ rasterInit
+</pre>
+<p>
+<h1><A NAME="writePixels">writePixels</A></h1>
+<p>
+Set the values of some subset of the pixels in a raster.
+If any mappings are defined on the affected region and are enabled, any
+destination rasters will be automatically updated as defined by the mapping.
+<p>
+Usage:
+<p>
+<pre>
+ writePixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be written.
+</pre>
+<p>
+Most real-world image processing applications get the Gterm widget handle
+with setGterm and pass binary data to the widget by calling GtWritePixels
+directly. This is the most efficient approach for serious image processing
+where large amounts of data are involved. However, being able to read and
+write raster pixels directly in a GUI can be useful in specialized
+applications, e.g., where the image is computed or modified by the GUI.
+<p>
+<h1><A NAME="setPixel">setPixel</A></h1>
+<p>
+Set the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ setPixel raster x y value
+
+ raster The raster number.
+ x, y The pixel to be set.
+ value The pixel value.
+</pre>
+<p>
+This routine is more efficient than writePixels for setting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be set.
+<p>
+<h1><A NAME="readPixels">readPixels</A></h1>
+<p>
+Get the values of some subset of the pixels in a raster.
+<p>
+Usage:
+<p>
+<pre>
+ readPixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be read.
+</pre>
+<p>
+Use readPixels to read a block of pixels, and getPixel to get the value
+of a single pixel.
+<p>
+<h1><A NAME="getPixel">getPixel</A></h1>
+<p>
+Get the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ getPixel raster x y
+
+ raster The raster number.
+ x, y The pixel to be set.
+</pre>
+<p>
+This routine is more efficient than readPixels for getting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be read.
+<p>
+<h1><A NAME="nextMapping">nextMapping</A></h1>
+<p>
+Return the index of the next unused mapping.
+<p>
+Usage:
+<p>
+<pre>
+ nextMapping
+</pre>
+<p>
+Returns the mapping number as the function value.
+<p>
+<h1><A NAME="getMapping">getMapping</A></h1>
+<p>
+Get a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters except the mapping number are output parameters.
+<p>
+<h1><A NAME="setMapping">setMapping</A></h1>
+<p>
+Set a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ setMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters are input parameters.
+<p>
+<h1><A NAME="loadColormap">loadColormap</A></h1>
+<p>
+Load a colormap.
+<p>
+Usage:
+<p>
+<pre>
+ loadColormap colormap [offset [scale]]
+</pre>
+<p>
+The offset and scale parameters may be used to adjust the brightness and
+contrast of the image when the colormap is loaded. The normalized colormap
+has offset=0.5, scale=1.0. Colormap zero is the hardware colormap.
+<p>
+<h1><A NAME="selectRaster">selectRaster</A></h1>
+<p>
+Given the raw screen coordinates SX,SY (or coords in
+any destination raster), determine the mapping and source raster which are
+mapped to that pixel and return the raster and mapping numbers and the
+coordinates of the same pixel in the source raster.
+<p>
+Usage:
+<p>
+<pre>
+ raster = selectRaster dras dt dx dy rt rx ry [map]
+</pre>
+<p>
+where
+<p>
+<pre>
+ dras display raster
+ dt,rt coordinate type - "pixel" or "ndc"
+ dx,dy display raster coordinates (input)
+ rx,ry source raster coordinates (output)
+ map mapping selected (output)
+</pre>
+<p>
+Note that the coordinates returned by selectRaster are measured (taking
+a line as an example) from zero at the left edge of the first pixel, to
+"width" at the right edge of the last pixel. This means that the floating
+point coordinates of the center of raster pixel N will be N + 0.5. For
+example, if we input screen coordinates (dras=0), x=117, and no mapping
+is in effect, the floating point raster coordinates returned will be 117.5.
+The difference occurs because the input coordinate is a pixel number
+(integer) while the output coordinate is a floating point coordinate
+measuring the continuously variable location a pixel. int(x) will convert
+this coordinate to a raster pixel number.
+<p>
+<h1><A NAME="unmapPixel">unmapPixel</A></h1>
+<p>
+unmapPixel is a simplified, less general version of
+selectRaster which will automatically follow graphics pipelines back to
+the original mapped raster. If desired the raster pixel value can be
+returned as well as the raster number and raster pixel coordinates
+corresponding to a screen (raster 0) pixel.
+<p>
+Usage:
+<p>
+<pre>
+ unmapPixel sx sy raster rx ry [rz]
+</pre>
+<p>
+where
+<p>
+<pre>
+ sx,sy "screen" (raster 0) coordinates
+ raster original mapped raster (output)
+ rx,ry source raster coordinates (output)
+ rz source raster pixel value (output)
+<pre>
+<p>
+By following graphics pipelines back to the original source raster we mean
+the following. If raster A is mapped to raster B which is mapped to C (the
+screen), given a screen coordinate in the mapped region unmapPixel will
+return the raster number and coordinates for raster A.
+<p>
+<h1><A NAME="flip">flip</A></h1>
+<p>
+Edit a mapping to flip the mapped subimage in X and/or Y.
+<p>
+Usage:
+<p>
+<pre>
+ flip mapping axis [axis]
+</pre>
+<p>
+where axis is "x" or "y". This is a convenience routine for changing only
+the flip portion of a mapping.
+<p>
+<h1><A NAME="markerInit">markerInit</A></h1>
+<p>
+Initialize the Marker subsystem for a Gterm widget.
+This destroys all markers and initializes the marker subsystem.
+<p>
+Usage:
+<p>
+<pre>
+ markerInit
+</pre>
+<p>
+<h1><A NAME="createMarker">createMarker</A></h1>
+<p>
+Create a new marker.
+<p>
+Usage:
+<p>
+<pre>
+ createMarker name attribute-list
+ e.g. createMarker name {attribute value [attribute value ...]}
+ or createMarker name attribute value [attribute value ...]
+<pre>
+<p>
+Any marker attribute may be assigned a value when the marker is created.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker attribute names. Often the
+the attributes "type" and "createMode" need to be specified at marker
+create time.
+<p>
+<pre>
+ type The marker type: text, rectangle, circle, etc.
+
+ createMode A marker should be created with createMode=interactive
+ if the user is expected to interactively drag out
+ the marker using the pointer and either the default
+ or an application specified translation table. A
+ marker can also be created interactively using only
+ the m_create (marker create) action, however m_create
+ does not allow the marker attributes to be set.
+<pre>
+<p>
+There are any number of ways to use a GUI to create a marker under the
+Object Manager, but an example might be using a translation to call a GUI
+procedure which issues the createMarker call. For example a pointer down
+event could translate as "call(newMarker,$name,$x,$y) m_create()" where
+newMarker is a GUI marker creation procedure which sends a createMarker
+message to the Gterm widget. The GUI procedure could set the marker
+attributes as desired, possibly using additional GUI components to define
+the marker attributes. The m_create action will notice that a
+createMarker has been executed and will merely activate the marker and
+give it the pointer focus (i.e. install the marker translations). The
+user will then use the pointer or keyboard to drag out the marker.
+<p>
+If the marker is created noninteractive the application must set the marker
+position and size using marker attributes. If the marker is sensitive
+the user can then use the marker's translations to interactively modify
+the marker (resize it, move it, etc.). All markers which are visible and
+sensitive and which have the necessary translations can be interactively
+modified by the user; the reason for creating a marker in interactive mode
+is to allow the initial marker position and size to be specified
+interactively *when* the marker is created, instead of afterwards.
+<p>
+Any number of attributes may be given when the marker is created. Most
+marker attributes can also be modified after a marker has been created
+by sending setAttribute messages to the marker.
+
diff --git a/vendor/x11iraf/obm/docs/obm/Marker.html b/vendor/x11iraf/obm/docs/obm/Marker.html
new file mode 100644
index 00000000..9e124846
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Marker.html
@@ -0,0 +1,402 @@
+<title>Graphics Marker class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> Graphics Marker class</h1>
+<p>
+<HR>
+<p>
+A marker is a graphics object implemented by the Gterm-Image widget.
+Markers are not real toolkit widgets, but they act much like widgets and
+are interfaced as an object class under the Object Manager. The Marker
+class is not a subclass, it is a base class like Widget, but Marker objects
+can exist only as children of Gterm widgets.
+<p>
+Since markers are not independent widgets but rather part of a Gterm widget
+instance, the parent Gterm widget is partially responsible for managing
+markers. The Gterm widget implements the following commands for dealing
+with markers.
+<p>
+<pre>
+ <a href="gtermclass.html#createMarker">createMarker</a> name [attribute-list]
+ <a href="gtermclass.html#markerInit">markerInit</a>
+</pre>
+<p>
+A new marker is created by sending the createMarker message to the parent
+gterm widget. This creates a marker of the given name and type.
+The markerInit command, if sent to a gterm widget, destroys any markers
+defined for that widget and reinitializes the marker facility. Markers
+may also be created by action procedures in response to user input events.
+<p>
+A marker may be destroyed by itself in response to an input event (e.g. the
+user presses the delete key), by sending the marker the destroy message
+to tell it to destroy itself, by sending a markerInit to the parent gterm
+widget, or by destroying the marker object (or any parent) with the server
+command <a href="servercom.html#destroyObject">destroyObject</a>.
+<p>
+Once a marker has been created it behaves as an independent object and
+receives and executes messages, responds to events, generates callbacks,
+and so on. The marker class defines the following commands.
+<p>
+<pre>
+ <a href="#makeCopy">makeCopy</a> name
+ <a href="#addCallback">addCallback</a> procedure [event [event ...]]
+ <a href="#notify">notify</a> [event-type [param [param ...]]]
+ <a href="#destroy">destroy</a> [nocallback]
+<p>
+ <a href="#markpos">markpos</a>
+ <a href="#redraw">redraw</a> [function] [markpos|nomarkpos] [erase|noerase]
+<p>
+ <a href="#raise">raise</a> [reference-marker]
+ <a href="#lower">lower</a> [reference-marker]
+<p>
+ <a href="#move">move</a> x y
+ <a href="#resize">resize</a> width height
+ <a href="#rotate">rotate</a> angle # radians
+<p>
+ <a href="#setAttribute">set</a> attribute value # alias for setAttribute
+ value = <a href="#getAttribute">get</a> attribute # alias for getAttribute
+<p>
+ <a href="#setAttribute">setAttribute</a> attribute value
+ value = <a href="#getAttribute">getAttribute</a> attribute
+ <a href="#setAttributes">setAttributes</a> attribute-list
+ <a href="#getAttributes">getAttributes</a> attribute-list
+ <a href="#setVertices">setVertices</a> points first npts
+ <a href="#getVertices">getVertices</a> points first npts
+<p>
+ region = <a href="#getRegion">getRegion</a> [unmap] [coord-type]
+ <a href="#getRect">getRect</a> dx dy dnx dny
+</pre>
+<p>
+Marker positions and dimensions are given in window (raster 0) coordinates.
+<p>
+The operators raise, lower, move, resize, and rotate erase the marker,
+modify it as indicated, and redraw it with the new attributes. For finer
+control over marker attributes one can use [get|set]Attribute[s] and
+[get|set]Vertices to edit the markers directly. In this case an auto
+redraw is not performed (unless the autoRedraw marker attribute is set).
+The usual sequence is a markpos to record the marker position, one or more
+setAttribute calls to change marker attributes, then a redraw to erase
+the old marker and redraw the new one. Markers have many attributes which
+can be set to control things like the position and size, colors, line
+widths, fill type and style, font, rubber-band technique, and so on.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker types and attributes.
+<p>
+The marker type may be changed at runtime without destroying the marker.
+For example a circle can be changed to an ellipse or a rectangle. This
+also works for polygons (the vertex list is preserved and restored when
+the marker is changed back to a polygon).
+<p>
+The current shape of a marker may be queried with getVertices, which
+returns the polygon or polyline vertex list in window coordinates. A more
+powerful routine which does something similar is getRegion. This routine
+returns a high level description of the region outlined by the marker,
+giving the marker type (rectangle, circle, ellipse etc.), center, width
+and height, and so on. Any position or dimension information may
+optionally be transformed back to the original source raster, if the marker
+center is in a region of the window which is the destination of an active
+mapping. The unmap option will follow multiple mappings back to the
+original mapped source raster.
+<p>
+The getRect function returns the parameters of the region outlined by a
+rectangle marker in a form convenient for use in a Gterm setMapping call
+(this is used to display an image within a marker).
+<p>
+Default translations when pointer is over a marker.
+default Marker Translations
+<p>
+<pre>
+ Shift &lt; Btn1Motion &gt;i m_rotateResize()
+ &lt; Btn1Motion &gt; m_moveResize()
+ Shift &lt; Btn1Down &gt; m_raise() m_markpos()
+ &lt; Btn1Down &gt; m_raise() m_markposAdd()
+ &lt; Btn1Up &gt; m_redraw() m_destroyNull()
+ &lt; Btn2Down &gt; m_lower()
+ &lt; Key &gt; BackSpace m_deleteDestroy()
+ &lt; Key &gt; Delete m_deleteDestroy()
+ &lt; KeyPress &gt; m_input()
+ &lt; Motion &gt; track-cursor()
+</pre>
+<p>
+MARKER class commands.
+<p>
+makeCopy</A></h1>
+<p>
+Copy a marker. The new marker is initially identical to the
+old one, and will not be distinct until, e.g., moved to a new center.
+<p>
+Usage:
+<p>
+<pre>
+ makeCopy name
+</pre>
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Post a marker callback to be called when the specified
+event or events occurs. If no events are listed a Notify callback will
+be posted.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure [event [event ...]]
+</pre>
+<p>
+<h1><A NAME="notify">notify</A></h1>
+<p>
+Generate a Marker pseudo-event, causing any posted client
+callback procedures to be called.
+<p>
+Usage:
+<p>
+<pre>
+ notify [event-type [param [param ...]]]
+</pre>
+<p>
+<h1><A NAME="destroy">destroy</A></h1>
+<p>
+Destroy a marker. Just tell the marker to destroy itself.
+All cleanup outside the marker facility relies upon the use of callbacks.
+This includes our callback markerDestroyCallback below.
+<p>
+Usage:
+<p>
+<pre>
+ destroy
+</pre>
+<p>
+<h1><A NAME="markpos">markpos</A></h1>
+<p>
+Mark the current position of a marker for a later redraw.
+<p>
+Usage:
+<p>
+<pre>
+ markpos
+</pre>
+<p>
+Markpos is used to mark the position of a marker before changing any
+marker attributes, so that a later "redraw marked" will erase the old
+marker rather than the new one. This is necessary, for example, if any
+marker attributes are changed which affect the size or position of the
+marker.
+<p>
+<h1><A NAME="redraw">redraw</A></h1>
+<p>
+Redraw a marker.
+<p>
+Usage:
+<p>
+<pre>
+ redraw [function] [erase|noerase] [markpos|nomarkpos]
+</pre>
+<p>
+By default redraw will erase the old marker at the position indicated by
+a previous call to markpos, and redraw the marker with the current
+attributes using the drawing function copy (copy source to destination).
+Hence the usual usage is "markpos ... change marker attributes ... redraw".
+Optional arguments may be given to change the drawing function, enable or
+disable erase, or force redraw to do a markpos. These arguments may be
+given in any order.
+<p>
+The drawing functions are as given in the XLIB documentation, minus the
+"GX" prefix. The most commonly used functions are "copy" and "xor".
+A normal marker redraw uses function=copy.
+<p>
+<h1><A NAME="raise">raise</A></h1>
+<p>
+Raise a marker, i.e., cause it to be drawn on top of other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ raise [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will raise itself above this
+marker, otherwise the raised marker becomes the topmost marker.
+<p>
+<h1><A NAME="lower">lower</A></h1>
+<p>
+Lower a marker, i.e., cause it to be drawn beneath other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ lower [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will lower itself beneath this
+marker, otherwise the lowered marker becomes the lowest marker.
+<p>
+<h1><A NAME="move">move</A></h1>
+<p>
+Move a marker.
+<p>
+Usage:
+<p>
+<pre>
+ move x y
+</pre>
+<p>
+Move the marker center to the indicated coordinates in the display window.
+<p>
+<h1><A NAME="resize">resize</A></h1>
+<p>
+Resize a marker.
+<p>
+Usage:
+<p>
+<pre>
+ resize width height
+</pre>
+<p>
+Resize the marker to the indicated size. By default width and height are
+given in pixels. For a text marker one can append "ch" to indicate that
+the units are chars in whatever font is in use, e.g., "40ch" or "40 chars"
+is an acceptable value for a text marker dimension.
+<p>
+<h1><A NAME="rotate">rotate</A></h1>
+<p>
+Rotate a marker.
+<p>
+Usage:
+<p>
+<pre>
+ rotate angle
+</pre>
+<p>
+Redraw a marker oriented to the given rotation angle. The angle is
+given in radians.
+<p>
+<h1><A NAME="getAttribute">getAttribute</A></h1>
+<p>
+Return the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ value = getAttribute attribute-name
+</pre>
+<p>
+<h1><A NAME="setAttribute">setAttribute</A></h1>
+<p>
+Set the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ setAttribute attribute-name value
+</pre>
+<p>
+<h1><A NAME="getAttributes">getAttributes</A></h1>
+<p>
+Return the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ getAttributes attribute-list
+ i.e. getAttributes {name value [name value ...]}
+ or getAttributes name value [name value ...]
+</pre>
+<p>
+where "value" is the name of the variable in which the attribute value
+is to be stored.
+<p>
+<h1><A NAME="setAttributes">setAttributes</A></h1>
+<p>
+Set the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ setAttributes attribute-list
+ i.e. setAttributes {name value [name value ...]}
+</pre>
+<p>
+where "value" is the new value of the associated marker attribute.
+<p>
+<h1><A NAME="getVertices">getVertices</A></h1>
+<p>
+Get some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ getVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is returned in the
+variable "points", as a string of the form { {x y} {x y} ...}. The first
+point is number zero.
+<p>
+<h1><A NAME="setVertices">setVertices</A></h1>
+<p>
+Set some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ setVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is set using the points
+passed in the "points" variable as a string of the form { {x y} {x y} ...}.
+If FIRST and NPTS are not specified first is assumed to be zero (the first
+point) and NPTS is the length of the points array.
+<p>
+<h1><A NAME="getRegion">getRegion</A></h1>
+<p>
+Return as a text string a high level description of the
+region defined by a marker.
+<p>
+Usage:
+<p>
+<pre>
+ region = getRegion [unmap] [coord-type]
+</pre>
+<p>
+The output string defines the marker type and the major marker positional
+attributes. The region description formats for the various marker types
+follow.
+<p>
+<pre>
+ text raster x y width height
+ line raster x y x y
+ polyline raster npts { {x y} {x y} ...}
+ rectangle raster x y width height rotangle
+ circle raster x y radius
+ ellipse raster x y width height rotangle
+ polygon raster npts { {x y} {x y} ...}
+</pre>
+<p>
+Here, width and height refer to the distance from the marker center to an
+edge, not to the width or height of the whole marker. This avoids
+ambiguities about where the edge of a marker is if the width is even or
+odd. Using the center to edge measurement, the edge is at x +/- width,
+y +/- height.
+<p>
+If the "unmap" flag is given getRegion will attempt to associate the
+marker with a mapped raster, reversing any mappings from the screen back
+to the original source raster, and returning the raster number and raster
+coordinates and marker sizes. If "unmap" is not given the marker
+coordinates will refer to raster 0. Either pixel ("pixel") or NDC
+("ndc") coordinates may be returned, pixel coordinates being the default.
+<p>
+<h1><A NAME="getRect">getRect</A></h1>
+<p>
+Return the region enclosed by a rectangle marker. The rect is
+returned in a form convenient for use as the destination rect in a gterm
+widget raster mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getRect dx dy dnx dny
+</pre>
+<p>
+The rect is stored in the output arguments.
+<p>
diff --git a/vendor/x11iraf/obm/docs/obm/Parameter.html b/vendor/x11iraf/obm/docs/obm/Parameter.html
new file mode 100644
index 00000000..fe189fc5
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Parameter.html
@@ -0,0 +1,107 @@
+<title>UI PARAMETER class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> UI PARAMETER class</h1>
+<p>
+<HR>
+<p>
+The UI parameter class is used for client-UI communications. The client
+does not control the user interface directly, rather the UI defines a set
+of abstract UI parameters, and during execution the client application
+assigns values to these parameters. These UI parameters should be thought
+of as describing the runtime state of the client as viewed by the GUI.
+The GUI is free to interpret this state information in any way, including
+ignoring it. Many GUIs can be written which use the same client state
+as described by the UI parameters.
+<p>
+Assigning a value to a UI parameter causes the new value to be stored, and
+any parameter action procedures registered by the UI to be called.
+The action or actions [if any] taken when a parameter value changes are
+arbitrary, e.g. the action might be something as simple as changing a
+displayed value of a UI widget, or something more complex like displaying
+a popup.
+<p>
+UI Parameter class commands:
+<p>
+<pre>
+ <a href="#getValue">getValue</a>
+ <a href="#setValue">setValue</a> &lt;new-value&gt;
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt;
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#notify">notify</a>
+</pre>
+<p>
+The most common usage is for the GUI to post one or more callbacks for
+each UI parameter. When the UI parameter value is changed [with setValue,
+e.g. by the client] the GUI callback procedures are called with the old
+and new UI parameter values on the command line. addCallback is used to
+add a callback procedure, and deleteCallback to delete one. Multiple
+callbacks may be registered for a single UI parameter. notify is used
+to simulate a parameter value change, causing any callback procedures to
+be invoked.
+<p>
+The callback procedure is called as follows:
+<p>
+<pre>
+ user-procedure param-name {old-value} {new-value}
+</pre>
+<p>
+The important thing to note here is that the old and new value strings
+are quoted with braces. This prevents any interpretation of the string
+by Tcl when the callback is executed, which is necessary because the
+strings can contain arbitrary data. When Tcl calls the callback the
+first level of braces will be stripped off, leaving old-value and new-value
+each as a single string argument.
+<p>
+<p>
+<h2><A NAME="setValue">setValue</A></h2>
+<p>
+Set the value of a parameter, and notify all clients
+via the posted callback procedures that the parameter value has changed.
+<p>
+Usage:
+<p>
+<pre>
+ setValue &lt;new-value&gt;
+</pre>
+<p>
+<h2><A NAME="getValue">getValue</A></h2>
+<p>
+Get the value of a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ getValue
+</pre>
+<p>
+<h2><A NAME="notify">notify</A></h2>
+<p>
+Notify the registered clients of a parameter as if the
+value had changed.
+<p>
+Usage:
+<p>
+<pre>
+ notify
+</pre>
+<p>
+<h2><A NAME="addCallback">addCallback</A></h2>
+<p>
+Add a callback procedure to the callback list for
+a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h2><A NAME="deleteCallback">deleteCallback</A></h2>
+<p>
+Delete a callback procedure previously registered
+for a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
diff --git a/vendor/x11iraf/obm/docs/obm/Server.html b/vendor/x11iraf/obm/docs/obm/Server.html
new file mode 100644
index 00000000..3fdaec2a
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Server.html
@@ -0,0 +1,38 @@
+<title>SERVER class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> SERVER class</h1>
+<p>
+<HR>
+<p>
+The server, or object manager, is the control center of the user interface.
+The server object provides a Tcl interpreter calling custom object manager
+commands. These are used to define and initialize the user interface, and
+execute UI action procedures at runtime.
+<p>
+<pre>
+ <a href="servercom.html#resetReset">reset-server</a>
+ <a href="servercom.html#appInitialize">appInitialize</a> appname,appclass,resources
+ <a href="servercom.html#createObjects">createObjects</a> [resource-name]
+ <a href="servercom.html#destroyObject">destroyObject</a> object
+ <a href="servercom.html#activate">activate</a>
+ <a href="servercom.html#deactivate">deactivate</a> [unmap]
+<p>
+ value = <a href="servercom.html#getResource">getResource</a> resource-name [default-value [class]]</a>
+ <a href="servercom.html#getResources">getResources</a> resource-list
+<p>
+ <a href="servercom.html#createMenu">createMenu</a> menu-name parent item-list
+ <a href="servercom.html#createMenu">editMenu</a> menu-name parent item-list
+ <a href="servercom.html#destroyMenu">destroyMenu</a> menu-name
+<p>
+ <a href="servercom.html#createBitmap">createBitmap</a> name width height data
+ <a href="servercom.html#createCursor">createCursor</a> name source mask fg_color bg_color x_hot y_hot
+ <a href="servercom.html#createPixmap">createPixmap</a> name width height depth fg_color bg_color data
+<p>
+ <a href="servercom.html#print">print</a> arg [arg ...] # debug messages
+ <a href="servercom.html#send">send</a> object message
+<p>
+ <a href="servercom.html#postActivateCallback">postActivateCallback</a> procedure
+id = <a href="servercom.html#postTimedCallback">postTimedCallback</a> procedure msec [client-data]
+ <a href="servercom.html#deleteTimedCallback">deleteTimedCallback</a> id
+ id = <a href="servercom.html#postWorkCallback">postWorkCallback</a> procedure [client-data]
+ <a href="servercom.html#deleteWorkCallback">deleteWorkCallback</a> id
+</pre>
diff --git a/vendor/x11iraf/obm/docs/obm/Widget.html b/vendor/x11iraf/obm/docs/obm/Widget.html
new file mode 100644
index 00000000..78d534db
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/Widget.html
@@ -0,0 +1,450 @@
+<title>WIDGET class</title>
+<h1><IMG SRC="/iraf/web/images/iraf.gif"> WIDGET class</h1>
+<p>
+<HR>
+<p>
+The Widget class is the generic or base class for the window system
+toolkit widgets supported by the object manager. The Widget class
+supports a number of different Xt widget classes using a table driven
+approach to describe each widget. Any widget may be created, destroyed,
+and manipulated in various ways using only the generic Widget class
+procedures and Widget-specific resources. The Widget class may be
+subclassed to support complex Widgets that require custom class-specific
+commands for use by the GUI code.
+<p>
+Generic Widget-class commands:
+<p>
+<pre>
+ <a href="#set">set</a> &lt;resource-name&gt; &lt;value&gt;
+ <a href="#get">get</a> &lt;resource-name&gt;
+<p>
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt; [<callback-name>]
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#setSensitive">setSensitive</a> &lt;sensitive&gt;
+ <a href="#isSensitive">isSensitive</a>
+<p>
+ <a href="#realize">realize</a>
+ <a href="#unrealize">unrealize</a>
+ <a href="#isRealized">isRealizeed</a>
+ <a href="#map">map</a>
+ <a href="#unmap">unmap</a>
+ <a href="#manage">manage</a> child [child ...]
+ <a href="#unmanage">unmanage</a> child [child ...]
+ <a href="#popup">popup</a> [grab-kind]
+ <a href="#popdown">popdown</a>
+ <a href="#popupSpringLoaded">popupSpringLoaded</a>
+<p>
+ <a href="#move">move</a> &lt;x&gt; &lt;y&gt;
+ <a href="#resize">resize</a> &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+ <a href="#configure">configure</a> &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+The most important Widget commands are set/get resource, and the
+callbacks. The widget sensitivity can be set and queried using set/get
+resource, but special procedures are provided to make this common operation
+more convenient.
+<p>
+Class specific functions:
+<p>
+<pre>
+ <a href="#append">append</a> text # text widget
+ <a href="#setList">setList</a> list [resize] # list widget
+ value = <a href="#getItem">getItem</a> itemno
+ <a href="#highlight">highlight</a> itemno
+ <a href="#unhighlight">unhighlight</a>
+</pre>
+<p>
+Ideally the widget class should be subclassed for widgets that require
+class-specific functions, but in simple cases involving standard widgets
+the support is built into the widget class code as a special case.
+<p>
+Special actions (used in translations):
+<p>
+<pre>
+ <a href="#do_userproc">call</a> (proc [,arg, ...])
+ <a href="#do_popup">popup</a> (menu-name [xoffset [yoffset]])
+ <a href="#do_popdown">popdown</a> (menu-name)
+</pre>
+<p>
+The "call" action is a very general mechanism which allows any GUI procedure
+to be registered with any translation using the X translation table
+mechanism. The popup and popdown actions are used for popup menus. The
+menu will be popped up at the event coordinates plus the optional offsets
+if given.
+<p>
+Event handling:
+<p>
+<pre>
+ <a href="#addEventHandler">addEventHandler</a> &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+Event callback:
+<p>
+<pre>
+ <a href="#userEventHandler">userEventHandler</a> widget event-type time wx wy rx ry other
+</pre>
+<p>
+In most cases translations are preferable to events, but a GUI can capture
+raw events if it wishes by adding event handlers. Nearly all of the X
+event types are supported. The callback syntax employs a number of
+standard arguments, followed by a number of event-specific arguments.
+<p>
+<h1><A NAME="addCallback">addCallback</A></h1>
+<p>
+Add a callback procedure to the callback list for
+a widget. If no callback name is given, "callback" is assumed.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback <procedure-name> [&lt;callback-name&gt;]
+</pre>
+<p>
+Specific widgets only support certain types of callbacks. There is no
+checking that the callback type specified is supported by a widget; the
+wrong type of callback can be registered, but it will never be called.
+<p>
+<h1><A NAME="deleteCallback">deleteCallback</A></h1>
+<p>
+Delete a callback procedure previously registered
+for a widget.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h1><A NAME="do_userproc">do_userproc (call)</A></h1>
+<p>
+Translation action procedure used to call general user
+action procedures in the interpreter. The name of the user procedure to
+be called is given as the first argument in the translation. For example,
+the translation "call(foo,a,b,c)" would cause procedure foo to be called
+with the arguments (a,b,c). The following arguments are special:
+<p>
+<pre>
+ Argument Replaced by
+<p>
+ $name object name of widget
+ $time event->time
+ $x event->x
+ $y event->y
+ $x_root event->x_root
+ $y_root event->y_root
+</pre>
+<p>
+The "user procedure" can be any server procedure.
+<p>
+<h1><A NAME="do_popup">do_popup</A></h1>
+<p>
+Popup a menu (or other spring loaded popup) at the location
+of the event which triggered this action.
+<p>
+Usage:
+<p>
+<pre>
+ popup(menu-name [xoffset [yoffset]])
+</pre>
+<p>
+<h1><A NAME="do_popdown">do_popdown</A></h1>
+<p>
+Pop down a menu.
+<p>
+Usage:
+<p>
+<pre>
+ popdown(menu-name)
+</pre>
+<p>
+<h1><A NAME="set">set</A></h1>
+<p>
+Set a widget resource.
+<p>
+Usage:
+<p>
+<pre>
+ set &lt;resource-name&gt; &lt;value&gt;
+</pre>
+<p>
+<h1><A NAME="get">get</A></h1>
+<p>
+Get a widget resource value as a string.
+<p>
+Usage:
+<p>
+<pre>
+ get &lt;resource-name&gt;
+</pre>
+<p>
+<h1><A NAME="append">append</A></h1>
+<p>
+Append data to a text widget.
+<p>
+Usage:
+<p>
+<pre>
+ append &lt;text&gt;
+</pre>
+<p>
+<h1><A NAME="setList">setList</A></h1>
+<p>
+Set the item list of a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ setList list [resize]
+</pre>
+<p>
+The list is a simple list of strings, passed as a single string argument to
+setList (quotes, braces, etc. may be used to quote strings containing
+special characters).
+<p>
+<h1><A NAME="getItem">getItem</A></h1>
+<p>
+Get an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ value = getItem itemno
+</pre>
+<p>
+If ITEMNO is a number the indicated list item is returned, or the string
+"EOF" if the requested item is beyond the end of the list. Otherwise the
+currently selected item is returned, and the index of the item is returned
+in the output variable ITEMNO. If no item is currently selected ITEMNO
+will be set to "none" on output.
+<p>
+<h1><A NAME="highlight">highlight</A></h1>
+<p>
+Highlight an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ highlight itemno
+</pre>
+<p>
+The indicated item of the list is highlighted as if the item had been
+selected by the user. Any previously highlighted item is unhighlighted.
+<p>
+<h1><A NAME="unhighlight">unhighlight</A></h1>
+<p>
+Unhighlight the currently highlighted item in a
+list widget.
+<p>
+Usage:
+<p>
+<pre>
+ unhighlight
+</pre>
+<p>
+Any currently highlighted item in the list widget is unhighlighted.
+<p>
+<h1><A NAME="realize">realize</A></h1>
+<p>
+Realize a widget. This activates and assigns windows for
+a widget and all of its descendants. Realizing a widget does not in itself
+cause it to appear on the screen.
+<p>
+Usage:
+<p>
+<pre>
+ realize
+</pre>
+<p>
+<h1><A NAME="unrealize">unrealize</A></h1>
+<p>
+Unrealize a widget. This destroys the windows assigned
+to a widget and all of its descendants.
+<p>
+Usage:
+<p>
+<pre>
+ unrealize
+</pre>
+<p>
+<h1><A NAME="isRealized">isRealized</A></h1>
+<p>
+Test whether a widget is realized.
+<p>
+Usage:
+<p>
+<pre>
+ isRealized
+</pre>
+<p>
+<h1><A NAME="map">map</A></h1>
+<p>
+Map a widget.
+<p>
+Usage:
+<p>
+<pre>
+ map
+</pre>
+<p>
+<h1><A NAME="unmap">unmap</A></h1>
+<p>
+Unmap a widget.
+<p>
+Usage:
+<p>
+<pre>
+ unmap
+</pre>
+<p>
+<h1><A NAME="manage">manage</A></h1>
+<p>
+Manage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Managing the
+children makes them appear in the window, possibly causing the other
+children to be rearranged in the window.
+<p>
+Usage:
+<p>
+<pre>
+ manage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h1><A NAME="unmanage">unmanage</A></h1>
+<p>
+Unmanage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Unmanaging the
+children makes them disappear from the window and be removed from geometry
+management, possibly causing the other children to be rearranged in the
+window.
+<p>
+Usage:
+<p>
+<pre>
+ unmanage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h1><A NAME="popup">popup</A></h1>
+<p>
+Popup a shell widget. If no grab is indicated the popup
+can remain up while other windows accept input.
+<p>
+Usage:
+<p>
+<pre>
+ popup [grab-kind]
+</pre>
+<p>
+<h1><A NAME="popdown">popdown</A></h1>
+<p>
+Popdown a shell widget.
+<p>
+Usage:
+<p>
+<pre>
+ popdown
+</pre>
+<p>
+<h1><A NAME="popupSpringLoaded">popupSpringLoaded</A></h1>
+<p>
+Popup a shell widget, e.g., a popup menu.
+This implies an exclusive grab.
+<p>
+Usage:
+<p>
+<pre>
+ popupSpringLoaded
+</pre>
+<p>
+<h1><A NAME="move">move</A></h1>
+<p>
+Move a widget to the given window relative coordinates.
+<p>
+Usage:
+<p>
+<pre>
+ move &lt;x&gt; &lt;y&gt;
+</pre>
+<p>
+<h1><A NAME="resize">resize</A></h1>
+<p>
+Resize a widget.
+<p>
+Usage:
+<p>
+<pre>
+ resize &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h1><A NAME="configure">configure</A></h1>
+<p>
+Configure a widget, i.e., execute a simultaneous
+move and resize.
+<p>
+Usage:
+<p>
+<pre>
+ configure &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h1><A NAME="setSensitive">setSensitive</A></h1>
+<p>
+Set the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ setSensitive &lt;sensitive&gt;
+</pre>
+<p>
+<h1><A NAME="isSensitive">isSensitive</A></h1>
+<p>
+Test the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ isSensitive
+</pre>
+<p>
+<h1><A NAME="addEventHandler">addEventHandler</A></h1>
+<p>
+Add a custom event handler to a widget. A list
+of event masks is given to define the classes of events the user supplied
+event handling procedure is to receive.
+<p>
+Usage:
+<p>
+<pre>
+ addEventHandler &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+<h1><A NAME="removeEventHandler">removeEventHandler</A></h1>
+<p>
+Remove an event handler previously posted
+with addEventHandler, above.
+<p>
+Usage:
+<p>
+<pre>
+ removeEventHandler procname
+</pre>
+<p>
+<h1><A NAME="event">event</A></h1>
+<p>
+Generic event handler called when a widget event handler
+posted by addEventHandler is called.
+<p>
+The user event handler is called as
+<p>
+<pre>
+ userEventHandler widget event-type time wx wy rx ry other
+</pre>
+<p>
+where "other" is an event-type specific list of fields describing the
+the event.
diff --git a/vendor/x11iraf/obm/docs/obm/alphabetic.html b/vendor/x11iraf/obm/docs/obm/alphabetic.html
new file mode 100644
index 00000000..0c141617
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/alphabetic.html
@@ -0,0 +1,39 @@
+<title>Alphabetized list of GUI commands</title>
+<IMG SRC="/iraf/web/projects/x11iraf/docs/gui.doc/blueline.gif">
+<pre>
+<a href="gtermclass.html#activate">activate</a> <a href="servercom.html#activate">activate</a> <a href="notyet.html">activeMapping</a> <a href="gmc.html#addCallback">addCallback</a> <a href="gtermclass.html#addCallback">addCallback</a>
+<a href="uiparameterclass.html#addCallback">addCallback</a> <a href="widgetclass.html#addCallback">addCallback</a> <a href="widgetclass.html#addEventHandler">addEventHandler</a> <a href="widgetclass.html#append">append</a> <a href="servercom.html#appInitialize">appInitialize</a>
+<a href="notyet.html">assignRaster</a> <a href="gtermclass.html#bell">bell</a> <a href="widgetclass.html#do_userproc">call</a> <a href="gtermclass.html#clearScreen">clearScreen</a> <a href="widgetclass.html#configure">configure</a>
+<a href="notyet.html">copyPixmap</a> <a href="notyet.html">copyRaster</a> <a href="servercom.html#createBitmap">createBitmap</a> <a href="servercom.html#createCursor">createCursor</a> <a href="gtermclass.html#createMarker">createMarker</a>
+<a href="servercom.html#createMenu">createMenu</a> <a href="servercom.html#createObjects">createObjects</a> <a href="notyet.html">createPixmap</a> <a href="servercom.html#createPixmap">createPixmap</a> <a href="notyet.html">createRaster</a>
+<a href="gtermclass.html#deactivate">deactivate</a> <a href="servercom.html#deactivate">deactivate</a> <a href="uiparameterclass.html#deleteCallback">deleteCallback</a> <a href="widgetclass.html#deleteCallback">deleteCallback</a> <a href="servercom.html#deleteTimedCallback">deleteTimedCallback</a>
+<a href="servercom.html#deleteWorkCallback">deleteWorkCallback</a> <a href="gmc.html#destroy">destroy</a> <a href="servercom.html#destroyMenu">destroyMenu</a> <a href="servercom.html#destroyObject">destroyObject</a>
+<a href="notyet.html">destroyRaster</a> <a href="notyet.html">disableMapping</a> <a href="notyet.html">drawAlphaText</a> <a href="notyet.html">drawDialogText</a> <a href="notyet.html">drawMarker</a>
+<a href="notyet.html">drawPolygon</a> <a href="notyet.html">drawPolyline</a> <a href="notyet.html">drawPolymarker</a> <a href="servercom.html#createMenu">editMenu</a> <a href="notyet.html">enableMapping</a>
+<a href="ximclient.html#encodewcs">encodewcs</a> <a href="notyet.html">endDialog</a> <a href="notyet.html">eraseDialog</a> <a href="ximclient.html#fitFrame">fitFrame</a> <a href="gtermclass.html#flip">flip</a>
+<a href="ximclient.html#flip">flip</a> <a href="gtermclass.html#flush">flush</a> <a href="notyet.html">freeColormap</a> <a href="notyet.html">freeMapping</a> <a href="clientclass.html#gcmd">gcmd</a>
+<a href="gmc.html#getAttribute">get</a> <a href="widgetclass.html#get">get</a> <a href="notyet.html">getAlphaTextSize</a> <a href="gmc.html#getAttribute">getAttribute</a>
+<a href="gmc.html#getAttributes">getAttributes</a> <a href="gtermclass.html#getCursorPos">getCursorPos</a> <a href="notyet.html">getDialogTextSize</a> <a href="ximclient.html#getFrame">getFrame</a>
+<a href="widgetclass.html#getItem">getItem</a> <a href="notyet.html">getLogRes</a> <a href="gtermclass.html#getMapping">getMapping</a> <a href="notyet.html">getPhysRes</a> <a href="gtermclass.html#getPixel">getPixel</a>
+<a href="gtermclass.html#getRaster">getRaster</a> <a href="gmc.html#getRect">getRect</a> <a href="gmc.html#getRegion">getRegion</a> <a href="servercom.html#getResource">getResource</a> <a href="servercom.html#getResources">getResources</a>
+<a href="uiparameterclass.html#getValue">getValue</a> <a href="gmc.html#getVertices">getVertices</a> <a href="clientclass.html#gkey">gkey</a> <a href="widgetclass.html#highlight">highlight</a> <a href="notyet.html">initMappings</a>
+<a href="widgetclass.html#isRealized">isRealized</a> <a href="widgetclass.html#isSensitive">isSensitive</a> <a href="clientclass.html#literal">literal</a> <a href="gtermclass.html#loadColormap">loadColormap</a> <a href="gmc.html#lower">lower</a>
+<a href="gmc.html#makeCopy">makeCopy</a> <a href="widgetclass.html#manage">manage</a> <a href="widgetclass.html#map">map</a> <a href="gtermclass.html#markerInit">markerInit</a> <a href="gmc.html#markpos">markpos</a>
+<a href="ximclient.html#matchFrames">matchFrames</a> <a href="gmc.html#move">move</a> <a href="widgetclass.html#move">move</a> <a href="notyet.html">nextColormap</a> <a href="ximclient.html#nextFrame">nextFrame</a>
+<a href="gtermclass.html#nextMapping">nextMapping</a> <a href="notyet.html">nextRaster</a> <a href="gmc.html#notify">notify</a> <a href="uiparameterclass.html#notify">notify</a> <a href="notyet.html">nRasters</a>
+<a href="ximclient.html#pan">pan</a> <a href="widgetclass.html#do_popdown">popdown</a> <a href="widgetclass.html#popdown">popdown</a> <a href="widgetclass.html#do_popup">popup</a> <a href="widgetclass.html#popup">popup</a>
+<a href="widgetclass.html#popupSpringLoaded">popupSpringLoaded</a> <a href="servercom.html#postActivateCallback">postActivateCallback</a> <a href="servercom.html#postTimedCallback">postTimedCallback</a>
+<a href="servercom.html#postWorkCallback">postWorkCallback</a> <a href="ximclient.html#prevFrame">prevFrame</a> <a href="servercom.html#print">print</a> <a href="notyet.html">queryRaster</a>
+<a href="ximclient.html#Quit">Quit</a> <a href="gmc.html#raise">raise</a> <a href="gtermclass.html#rasterInit">rasterInit</a> <a href="notyet.html">readColormap</a> <a href="gtermclass.html#readPixels">readPixels</a>
+<a href="widgetclass.html#realize">realize</a> <a href="gmc.html#redraw">redraw</a> <a href="notyet.html">refreshMapping</a> <a href="notyet.html">refreshPixels</a> <a href="servercom.html#resetReset">reset-server</a>
+<a href="gtermclass.html#reset">reset</a> <a href="gmc.html#resize">resize</a> <a href="widgetclass.html#resize">resize</a> <a href="ximclient.html#retCursorVal">retCursorVal</a> <a href="gmc.html#rotate">rotate</a>
+<a href="gtermclass.html#selectRaster">selectRaster</a> <a href="servercom.html#send">send</a> <a href="gmc.html#setAttribute">set</a> <a href="widgetclass.html#set">set</a> <a href="gmc.html#setAttribute">setAttribute</a>
+<a href="gmc.html#setAttributes">setAttributes</a> <a href="notyet.html">setColorIndex</a> <a href="ximclient.html#setColormap">setColormap</a> <a href="gtermclass.html#setCursorPos">setCursorPos</a> <a href="gtermclass.html#setCursorType">setCursorType</a>
+<a href="notyet.html">setDataLevel</a> <a href="notyet.html">setFillType</a> <a href="ximclient.html#setFrame">setFrame</a> <a href="gtermclass.html#setGterm">setGterm</a> <a href="notyet.html">setLineStyle</a>
+<a href="notyet.html">setLineWidth</a> <a href="widgetclass.html#setList">setList</a> <a href="notyet.html">setLogRes</a> <a href="gtermclass.html#setMapping">setMapping</a> <a href="notyet.html">setPhysRes</a>
+<a href="gtermclass.html#setPixel">setPixel</a> <a href="gtermclass.html#setRaster">setRaster</a> <a href="widgetclass.html#setSensitive">setSensitive</a> <a href="notyet.html">setTextRes</a> <a href="uiparameterclass.html#setValue">setValue</a>
+<a href="gmc.html#setVertices">setVertices</a> <a href="notyet.html">startDialog</a> <a href="widgetclass.html#unhighlight">unhighlight</a> <a href="widgetclass.html#unmanage">unmanage</a> <a href="widgetclass.html#unmap">unmap</a>
+<a href="gtermclass.html#unmapPixel">unmapPixel</a> <a href="widgetclass.html#unrealize">unrealize</a> <a href="widgetclass.html#userEventHandler">userEventHandler</a> <a href="ximclient.html#windowColormap">windowColormap</a>
+<a href="notyet.html">writeColormap</a> <a href="gtermclass.html#writePixels">writePixels</a> <a href="ximclient.html#zoom">zoom</a> <a href="ximclient.html#zoom">zoomAbs</a>
+</pre>
+
diff --git a/vendor/x11iraf/obm/docs/obm/index.html b/vendor/x11iraf/obm/docs/obm/index.html
new file mode 100644
index 00000000..b7e531ca
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/index.html
@@ -0,0 +1,2515 @@
+<html>
+<body bgcolor=#FFFFFF>
+<title>IRAF Object Manager Tutorial</title>
+
+<center>
+<h1>IRAF Object Manager Tutorial</h1>
+</center>
+<hr noshade=5>
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#1">1. Introduction</a>
+<li><a href="#2">2. System Architecture</a>
+<li><a href="#3">3. The Client Process</a>
+ <ul>
+ <li><a href="#3.1">3.1 IRAF Graphics Task</a>
+ <ul>
+ <li><a href="#3.1.1">3.1.1 XGterm</a>
+ </ul>
+ <li><a href="#3.2">3.2 Standalone Task</a>
+ <li><a href="#3.3">3.3 OBM Shell</a>
+ <li><a href="#3.4">3.4 Named External Clients</a>
+ </ul>
+<li><a href="#4">4. UI Definition File</a>
+ <ul>
+ <li><a href="#4.1">4.1 Example Interface</a>
+ </ul>
+<li><a href="#5">5. Widget Toolkit</a>
+<li><a href="#6">6. Object Classes</a>
+ <ul>
+ <li><a href="#6.1">6.1 Client</a>
+ <ul>
+ <li><a href="#6.1.1">6.1.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.2">6.2 Server</a>
+ <ul>
+ <li><a href="#6.2.1">6.2.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.3">6.3 Gterm</a>
+ <ul>
+ <li><a href="#6.3.1">6.3.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.4">6.4 HTML</a>
+ <ul>
+ <li><a href="#6.4.1">6.4.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.5">6.5 Markers</a>
+ <ul>
+ <li><a href="#6.5.1">6.5.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.6">6.6 Widget</a>
+ <ul>
+ <li><a href="#6.6.1">6.6.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.7">6.7 Parameter</a>
+ <ul>
+ <li><a href="#6.7.1">6.7.1 Command Summary</a>
+ </ul>
+ </ul>
+</ul>
+
+<hr noshade=5>
+
+<a name="1"></a>
+<h3>1. Introduction</h3>
+<p>
+An Object Manager (OBM) user interface (UI) consists of one or more windows
+containing an arbitrary hierarchy of widgets. These widgets and their
+runtime actions are defined by an interpreted text program uploaded
+by the client application, which does not itself deal directly with the
+window user interface. This interpreted program is currently written
+as a Tcl script.
+<p>
+The OBM provides a high level abstraction for dealing with widgets and
+other UI objects. The main function of the object manager is to deliver
+messages to UI objects. Each instance of a widget is an object in the
+interface. The UI contains other types of objects as well, including the
+client object (client application), the server object (the object manager
+itself), and the application specific UI parameters, each of which is an
+object with a callback list of procedures to be called when the parameter
+value changes. All of these UI objects can receive messages and take actions
+as a result. Messages may come from the client application, or as a result
+of actions executed by the interpreted UI code in response to graphics events.
+<hr noshade=5>
+<p>
+<a name="2"></a>
+<h3>2. System Architecture</h3>
+<p>
+For a complete description of the OBM system architecture see Tody, D,
+ADASS Proceedings 1994. A <a href="todyd.ps">postscript version of this
+paper</a> is also vailable.
+<p>
+<hr noshade=5>
+<p>
+<a name="3"></a>
+<h3>3. The Client Process</h3>
+<p>
+ The primary advantage of the OBM architecture over traditional GUI
+design is the separation of the user interface from the executable client
+code, meaning that either can be completely rewritten or developed separately
+without affecting the other so long as the messaging between the two
+remains the same. The client itself is responsible for initializing the OBM
+toolkit and uploading the UI definition file, after that it usually enters
+an event loop of some kind (e.g. an iraf graphics cursor loop, or X event
+handler) to process actions defined in the client callbacks.
+<p>
+ It's important that the client program maintain the state of the
+application rather than the UI file. For example, a text widget in the
+interface may instruct the client to load a file, however if this cannot
+be done the interface should not have independently reset labels or
+whatever assuming the action was done at all. Instead, the client program
+uses the Parameter Class objects in the interface to update the state of
+the GUI as a result of some action (whose origins may not have been in the
+GUI at all). So for example a sequence of events could be something like
+
+<ul><ul>
+<li> User selects a widget in the interface, it's callback sends a
+ message to the client directing some action be taken
+<li> Client receives the message and performs an action in the client
+<li> If action fails, (optionally) notify GUI of failure (e.g. send a
+ message to an 'alert' parameter to popup a dialog box, beep the
+ terminal, etc)
+<li> If action succeeds, notify GUI of new state (e.g. send a message
+ to the 'filename' Parameter object containing the new file name).
+<li> Callback on the 'filename' parameter then updates the status bar
+ widget with the name of the new active file.
+</ul></ul>
+
+<p>
+ The messaging between the client and UI depend on the details of how
+the client is implemented. In general any callback procedure in the UI can
+send a message to any other object in the interface, but the client should
+generally communicate only via the Parameter objects to avoid side effects
+and maintain a clear separation between the UI and the client code.
+
+<a name="3.1"></a>
+<h3>3.1 IRAF Graphics Task</h3>
+
+<a name="3.1.1"></a>
+<h3>3.1.1 XGterm</h3>
+
+<a name="3.2"></a>
+<h3>3.2 Standalone Task</h3>
+
+<a name="3.3"></a>
+<h3>3.3 OBM Shell</h3>
+<p>
+ The <i>obmsh</i> is a unix shell interpreter for GUI scripts. It is
+a minimal standalone client with a single callback to exit the application,
+otherwise it's only job is to activate the GUI file. Any messages sent to
+the client (except a 'quit') are simply absorbed by the client
+<p>
+ Despite the apparent lack of functionality this is sometimes all
+that is required for an interface that can operate independently. Remember
+that the Tcl scripting language has it's own facilities for file I/O,
+process execution, etc, all of which are still available in the GUI. In
+the case of IRAF tasks it's an interface violation to use these facilities
+directly, however they still allow for the easy creation of a GUI which
+requires no real underlying client (e.g. a tcl debug shell, a calculator
+application, task launcher, etc).
+
+<a name="3.4"></a>
+<h3>3.4 Named External Clients</h3>
+
+<p>
+<p>
+<hr noshade=5>
+<p>
+<a name="4"></a>
+<h3>4. UI Definition File</h3>
+<p>
+A UI definition consists of a sequence of commands to be executed by the
+server object using Tcl is used as an embedded interpreter within the OBM.
+The Tcl script contains several required OBM-specific functions (in
+addition to the user-defined callbacks) which is uploaded by the client
+as a message for the server object.
+<pre>
+ <a href="#resetReset">reset-server</a>
+ <a href="#appInitialize">appInitialize</a> appName appClass Resources
+ <a href="#createObjects">createObjects</a> [name]
+ <a href="#activate">activate</a>
+</pre>
+<p>
+All UI files must begin with a <b>reset-server</b> command to initialize
+the OBM. An <b>appInitialize</b> call is then made to define all of the
+widgets and resources used in the interface, initializing the interface
+used by the application. The <b>createObjects</b> function then actually
+creates the widgets in the server, more specifically it creates the widgets
+defined by the named <i>objects</i> resource. Lastly, the <b>activate</b>
+call is used to activate the interface, i.e. put it on the screen.
+
+<p>
+<a name="4.1"></a>
+<h3>4.1 Example</h3>
+A complete "hello, world" GUI definition might look something like:
+<pre>
+ 1) <b>reset-server</b>
+ 2) <b>appInitialize</b> <i>hello Hello</i> {
+ 3) *objects:\
+ 4) toplevel Form helloForm\
+ 5) helloForm Label helloLabel\
+ 6) helloForm Command quitButton
+ 7)
+ 8) *background: gray
+ 9) *helloLabel.label: Hello, world!
+ 10) *quitButton.fromHoriz: helloLabel
+ 11) *quitButton.label: Quit
+ 12) }
+ 13)
+ 14) <b>createObjects</b>
+ 15) <b>activate</b>
+ 16)
+ 17) <b>proc</b> Quit <b>args</b> {
+ 18) <b>send client gkey</b> q
+ 19) <b>deactivate unmap</b>
+ 20) } ; <b>send</b> quitButton <b>addCallback</b> Quit
+</pre>
+
+where a line-by-line analysis of the GUI shows:
+
+<dl>
+<dt>Line 1: <dd>- The <b>reset-server</b> command must be the first line in
+the UI file since it's primary purpose is to initialize the OBM (i.e. a
+call to the <i>ObmInitialize()</i> procedure). Subsequent calls (in the
+same UI file or a different UI) are effectively a no-op.
+<dt>Lines 2-12: <dd>- The <b>appInitialize</b> command defines the widgets
+and resources to be used in the interface. The first argument gives the
+name of the application, the second argument is the application class name
+for purposes of specifying resources in the environment, and the last
+argument is a Tcl list (hence the braces) of resources for the application.
+<p>
+The primary purpose of the call is to initialize the X11 part of the system
+by defining the application context and the list of fallback resources. The
+<i>objects</i> resource is a required element listing the widget hierarchy
+to be used. Remaining resources are used to specify labels, colors, layout,
+etc and serve as an app-defaults file for the GUI, interacting with the
+normal resource database in the usual way. For example, a user's .Xdefaults
+file may specify a "<b>font</b>" resource, unless this is overridden in
+some way in the UI file this is the font that will be used. Resources may
+be specified with either "loose" (i.e. the '*') or "tight" (i.e. the '.')
+bindings with as much detail as is needed.
+<dt>Line 14: <dd>- The <b>createObjects</b> command is what actually calls
+each widget's Initialize() method to create the widget in the application
+and in the X11 server.
+<p>
+With no argument, the default value used is simply
+the <b>objects</b> resource. However, it's possible to specify a named
+argument and make repeated calls to <b>createObjects</b> to build any number
+widget trees prior to activating the interface. This can be useful for
+example to specify a "main_objects" resource contains all the widgets for
+the main panel, and a "help_objects" specfiying widgets used for the UI
+help panel, which makes the definition file easier to organize. In the
+past however UI files were written with a single long list (easily many
+hundreds of lines) of objects followed by an even longer list of their
+resources under a single <b>appInitialize</b> call, creating a monolithic
+and unmanageably GUI definition file. Later on we'll see how complex GUIs
+can be divided into separate pieces making it easier to reuse code and
+manage the interface more efficiently.
+<dt>Line 15: <dd>- The <b>activate</b> command is what creates the interface
+on the screen, i.e. it calls the Realize() method for each widget to
+instantiate it in the server and draw the window.
+<dt>Lines 17-19: <dd>- Lastly we have the user-defined callback procedures.
+On line 17 we define a procedure <i>Quit</i> which we use to shut down the
+interface and client application. The body of the procedure first sends the
+client object the graphics keystroke 'q' to shut down the client, then calls
+the <b>deactivate</b> command to close the interface. On the last line
+we send a message to the <i>quitButton</i> widget telling it to add this
+procedure to it's callback list, so when the Button is selected this
+procedure will be called as a result.
+</dl>
+<p>
+<hr noshade=6>
+
+<a name="5"></a>
+<h3>5. Widget Toolkit</h3>
+<p>
+<p>
+<hr noshade=6>
+
+<a name="6"></a>
+<h3>5. Object Classes</h3>
+<p>
+The following OBM object classes are currently defined:
+<pre>
+ <a href="#6.1">Client</a> The Client application
+ <a href="#6.2">Server</a> The OBM itself
+ <a href="#6.3">Gterm</a> Gterm graphics/imaging widget class
+ <a href="#6.4">HTML</a> HTML widget class
+ <a href="#6.5">Markers</a> Gterm markers class
+ <a href="#6.6">Widget</a> General widget class
+ <a href="#6.7">Parameter</a> UI Parameter class
+<p>
+ Various Xt and Athena widgets
+ <i>{box, shell, label, command, text, list, etc.}</i>
+ Misc Other X11 Widgets
+ <i>{Layout, Tabs, ListTree, etc}</i>
+</pre>
+<p>
+OBM client applications will upload a UI during initialization to define a
+custom graphics user interface. This is done by sending a message to the
+object manager. Non-GUI applications assume a simple graphics
+terminal and do not upload a UI; instead, a default UI is created
+for the application consisting of a single top level shell containing a
+Gterm (Tek 4012 graphics/imaging) widget.
+<p>
+
+<hr noshade=5>
+
+<a name="5.1"></a>
+<h3>5.1 Client</h3>
+<p>
+The client is the client application, which provides the functionality
+underlying the UI. When a message is sent to the client object it usually
+results in a message being sent to the client *application*, usually an
+external program communicating via IPC, which has little or no knowledge
+of the UI. The client application receives and executes commands delivered
+by the UI via the client object. Output from the client may or may not
+come back to the object manager. That portion of the output which comes
+back to the object manager is in the form of assignments of string values
+to <a href="#5.7.html">UI Parameter class objects</a> (another way of thinking
+of this is that messages or events are sent to and acted upon by the parameter
+objects). Hence, the client object is output only so far as the client
+application is concerned.
+<p>
+The Client-class commands are used to send a message to the client.
+<p>
+<pre>
+ <a href="#gkey">gkey</a> &lt;key&gt;
+ <a href="#gcmd">gcmd</a> &lt;command-string&gt;
+ <a href="#literal">literal</a> &lt;command&gt;
+</pre>
+<p>
+or just &lt;command&gt;, e.g., "send client &lt;command&gt;" will work in most cases.
+<p>
+<a href="#gkey">GKEY</a> sends an IRAF graphics keystroke.
+<a href="#gcmd">GCMD</a> sends an
+IRAF graphics colon command. <a href="#literal">LITERAL</a> sends a literal
+command string to the
+client. The keyword "literal" may optionally be omitted, i.e., "send client
+foo" and "send client literal foo" are the same. The keyword "literal" may
+be used to ensure that the client command string which follows will not
+be interpreted as a Client-class command (such as gkey, gcmd, or literal).
+<p>
+<a name="5.1.1"></a>
+<h2>5.1.1 Command Summary</h2>
+<p>
+<h3><A NAME="gcmd">gcmd</A></h3>
+<p>
+Send a graphics command string to the client application.
+A graphics command string is a graphics cursor value with the key set
+to `:' and the command string given as the string part of the cursor
+value. The protocol module which posted the client output procedure is
+responsible for encoding and sending the cursor command.
+<p>
+Usage:
+<p>
+<pre>
+ gcmd &lt;command-string&gt;
+</pre>
+<p>
+<h3><A NAME="gkey">gkey</A></h3>
+<p>
+Send a graphics key event to the client application.
+A graphics key event is a graphics cursor value with the key set to some
+integer value and a null string part.
+<p>
+Usage:
+<p>
+<pre>
+gkey &lt;key&gt;
+</pre>
+<p>
+<h3><A NAME="literal">literal</A></h3>
+<p>
+Send a literal command to the client application.
+<p>
+Usage:
+<p>
+<pre>
+ literal &lt;command&gt;
+</pre>
+
+<hr noshade=5>
+
+<a name="6.2"></a>
+<h3>6.2 Server</h3>
+<p>
+The server, or object manager, is the control center of the user interface.
+The server object provides a Tcl interpreter calling custom object manager
+commands. These are used to define and initialize the user interface, and
+execute UI action procedures at runtime.
+<p>
+<pre>
+ <a href="#resetReset">reset-server</a>
+ <a href="#appInitialize">appInitialize</a> appname,appclass,resources
+ <a href="#createObjects">createObjects</a> [resource-name]
+ <a href="#destroyObject">destroyObject</a> object
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a> [unmap]
+<p>
+ value = <a href="#getResource">getResource</a> resource-name [default-value [class]]</a>
+ <a href="#getResources">getResources</a> resource-list
+<p>
+ <a href="#createMenu">createMenu</a> menu-name parent item-list
+ <a href="#createMenu">editMenu</a> menu-name parent item-list
+ <a href="#destroyMenu">destroyMenu</a> menu-name
+<p>
+ <a href="#createBitmap">createBitmap</a> name width height data
+ <a href="#createCursor">createCursor</a> name source mask fg_color bg_color x_hot y_hot
+ <a href="#createPixmap">createPixmap</a> name width height depth fg_color bg_color data
+<p>
+ <a href="#print">print</a> arg [arg ...] # debug messages
+ <a href="#send">send</a> object message
+<p>
+ <a href="#postActivateCallback">postActivateCallback</a> procedure
+id = <a href="#postTimedCallback">postTimedCallback</a> procedure msec [client-data]
+ <a href="#deleteTimedCallback">deleteTimedCallback</a> id
+ id = <a href="#postWorkCallback">postWorkCallback</a> procedure [client-data]
+ <a href="#deleteWorkCallback">deleteWorkCallback</a> id
+</pre>
+
+<a name="6.2.1"></a>
+<h2>6.2.1 Command Summary</h2>
+<p>
+<h3><A NAME="serverReset">serverReset</A></h3>
+<p>
+The "reset-server" command is implemented as a special case in ServerEvaluate.
+After doing a true reset ServerEvaluate calls Tcl_Eval to evaluate the full
+message which still contains the reset-server command. We want to ignore
+this the second time, so we treat the command here as a no-op.
+<p>
+Usage:
+<p>
+<pre>
+ reset-server
+</pre>
+<p>
+Note: for reset-server to be recognized by ServerEvaluate and really reset
+things, it must be the first command in a message to the server.
+<p>
+<h3><A NAME="appInitialize>appInitialize</A></h3>
+<p>
+TCL command to initialize the server for a new application, setting the
+application name and loading the application resources.
+<p>
+Usage:
+<p>
+<pre>
+ appInitialize appname, appclass, resources
+</pre>
+<p>
+<h3><A NAME ="createObjects">createObjects</A></h3>
+<p>
+TCL command to create the tree of UI objects comprising the user interface.
+The object tree is defined by a string valued resource. If no resource is
+named the default "objects" resource will be used.
+<p>
+Usage:
+<p>
+<pre>
+ createObjects [resource-name]
+</pre>
+<h3><A NAME="destroyObject">destroyObject</A></h3>
+<p>
+Destroy an object and all of its children.
+<p>
+Usage:
+<pre>
+ destroyObject object-name
+</pre>
+<p>
+<h3><A NAME="activate">activate</A></h3>
+Activate the user interface. When called the first time the user interface
+is created and activated, thereafter the UI is merely reactivated (e.g.
+mapped if unmapped).
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h3><A NAME="deactivate">deactivate</A></h3>
+<p>
+Deactivate the user interface. Optionally unmaps the UI and calls the Obm
+client back to let it know that the UI has been deactivated.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate [unmap]
+</pre>
+<p>
+<h3><A NAME="getResource">getResource</A></h3>
+<p>
+Get the string value of the specified application resource (window
+system parameter). This allows use of the resource mechanism to supply
+default values for GUI parameters.
+<p>
+Usage:
+<p>
+<pre>
+ value = getResource resource-name [class [default-value]]
+</pre>
+<p>
+In the simplest case one merely requests a resource by name and the
+string value is returned as the function value. If the resource has
+an entry in the fallback resources for the application (appInitialize
+resource list) then a value is guaranteed to be returned.
+<p>
+If the Class name for the resource is given then a class default value
+will be returned if no entry is found for the name resource instance. This
+is useful when there are a number of resources of the same type (same class).
+If most or all resources in the same class have the same default value one
+need only make one entry for the Class in the application defaults resource
+list. It is up to the application developer to define the class name of a
+resource - the class name can be any string. Examples are "Font", "Cursor",
+etc. By convention the first character of a class name is capitalized, while
+instance names begin with a lower case letter.
+<p>
+If there is an entry for the named resource in the resource list passed to
+appInitialize then a value string is guaranteed to be returned. This will be
+either the appInitialize default, or a value specified by the system or the
+user in an X resources file. If one is not certain a default value is defined
+somewhere, a default value should be specified in the getResource call as
+shown above.
+<p>
+See also getResources, used to get multiple resources in one call.
+<p>
+<h3><A NAME="getResources">getResources</A></h3>
+<p>
+Get the string values of a list of resources.
+<p>
+Usage:
+<p>
+<pre>
+ getResources resource-list
+</pre>
+<p>
+e.g.
+<pre>
+ getResources {
+ { resource [variable class [default-value]]] }
+ { resource [variable class [default-value]]] }
+ (etc.)
+ }
+</pre>
+<p>
+<h3><A NAME="createMenu">createMenu, editMenu</A></h3>
+<p>
+Create or modify a menu. The editMenu function is an alias for createMenu.
+<p>
+Usage:
+<pre>
+ createMenu menu-name parent item-list
+</pre>
+<p>
+e.g.,
+<pre>
+ createMenu menu-name parent {
+ { label function data [options...] }
+ { label function data [options...] }
+ (etc.)
+ }
+</pre>
+<p>
+where
+<p>
+<pre>
+ menu-name is the object name for the menu popup shell
+ parent is the parent widget of the menu shell
+ label is a menu item label
+ function is the function to be performed when the menu
+ item is selected, e.g., f.exec, f.data, f.space, or f.line.
+ data is function dependent data
+ options are option-name option-value pairs, as specified
+ below.
+</pre>
+<p>
+In the item list the fields label and option-value may be any Tcl expression.
+Expressions are evaluated in the server context. The data field is a Tcl
+script to be executed when the menu item is selected.
+<p>
+Options are specified as "option option-value". The menu item options are
+as follows.
+<p>
+<pre>
+ bitmap A bitmap to be displayed left justified in the label field
+ (e.g. to indicate a parameter setting).
+ sensitive Specifies whether the menu item is active (sensitive=true)
+ or inactive (sensitive=false, item grayed out).
+ accelerator Specifies an input translation (accelerator, e.g.,
+ keyboard event) which can be used to execute the
+ menu item.
+</pre>
+<p>
+The option-value field may be any Tcl expression.
+<p>
+Example:
+<p>
+<pre>
+ createMenu fileMenu toplevel {
+ { "File Menu" f.title}
+ { Open f.exec openFile}
+ { Save f.exec saveFile}
+ { Load f.menu loadMenu}
+ { no-label f.line }
+ { Quit f.exec "send client Quit" }
+ }
+</pre>
+<p>
+The first createMenu is called for a given menu the menu is created, added
+to the menu list, and all window system widgets are created for the menu.
+Subsequent calls will result in only the changed parts of the menu being
+altered provided the changes are not great. Hence this routine can be called
+to efficiently modify a menu when minor runtime changes occur, e.g., an
+item label or action changes, the item value changes state, and so on,
+without need for the GUI code to know how to make the necessary detailed
+changes to the widgets used to implement the menu.
+<p>
+<h3><A NAME="destroyMenu">destroyMenu</A></h3>
+<p>
+Destroy a menu. This can be used to free up the resources used by a
+menu, e.g., if the menu is not expected to be needed again for a while.
+<p>
+Usage:
+<p>
+<pre>
+ destroyMenu menu-name
+</pre>
+<p>
+<h3><A NAME="createBitmap">createBitmap</A></h3>
+<p>
+Create a named bitmap. This replaces any old bitmap of the same name. The
+new bitmap is cached in server memory; when a widget bitmap resource is set,
+the bitmap cache will be searched for the named bitmap before asking Xlib
+to find the bitmap.
+<p>
+Usage:
+<p>
+<pre>
+ createBitmap name width height data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createBitmap foo 16 16 {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+<p>
+<h3><A NAME="createCursor">createCursor</A></h3>
+<p>
+Create a cursor from bitmap data. The cursor is entered into the server's
+cursor cache and will override any existing entry of the same name.
+<p>
+Usage:
+<p>
+<pre>
+ createCursor name source mask fg_color bg_color x_hot y_hot
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createCursor foo bitmap1 bitmap2 black white 8 8
+</pre>
+<p>
+The named bitmaps must be created first with createBitmap.
+<p>
+<h3><A NAME="createPixmap">createPixmap</A></h3>
+<p>
+Create a named pixmap. This replaces any old pixmap of the same name. The
+new pixmap is cached in server memory; when a widget pixmap resource is set,
+the pixmap cache will be searched for the named pixmap before asking Xlib
+to find the pixmap.
+<p>
+Usage:
+<p>
+<pre>
+ createPixmap name width height depth fg_color bg_color data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createPixmap foo 16 16 8 black white {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+</pre>
+<p>
+<h3><A NAME="print">print</A></h3>
+<p>
+Print a string on the standard output. This is used mainly for debugging
+user interfaces.
+<p>
+Usage:
+<p>
+<pre>
+ print arg [arg ...]
+</pre>
+<p>
+<h3><A NAME="send">send</A></h3>
+<p>
+Send a message to an object. The object interprets the message and returns
+a function value as the string result of the TCL command.
+<p>
+Usage
+<p>
+<pre>
+ send &lt;object&gt; &lt;message&gt;
+</pre>
+<p>
+<h3><A NAME="postActivateCallback">postActivateCallback</A></h3>
+<p>
+Post a callback procedure to be called when the UI is activated. The UI is
+activated when it is first downloaded to server, but it may also be
+activated (reactivated) after the application has exited and is later
+restarted, or when the UI is deactivated and reactivated. Note
+that the UI state vis-a-vis the external world (client application) may
+no longer be accurate after it has been idle for a time and then reactivated.
+<p>
+Usage:
+<p>
+<pre>
+ postActivateCallback &lt;procedure&gt;
+</pre>
+<p>
+<p>
+<h3><A NAME="postTimedCallback">postTimedCallback</A></h3>
+<p>
+Post a callback to call the named procedure back after a specified delay
+in milliseconds.
+<p>
+Usage:
+<p>
+<pre>
+ id = postTimedCallback procedure msec [client-data]
+</pre>
+<p>
+After the specified delay the user callback procedure will be called with
+client_data (if given) as the single argument. Only one call will be made;
+the client must repost the callback in each call if the procedure is to be
+repeatedly executed.
+<p>
+An ID value is returned which may be passed to deleteTimedCallback to delete
+the timer.
+<p>
+<h3><A NAME="deleteTimedCallback">deleteTimedCallback</A></h3>
+<p>
+Delete a timer callback procedure. This procedure is typically used to
+break a timer loop, where the timer procedure repeatedly reposts itself at
+the end of each interval.
+<p>
+Usage:
+<p>
+<pre>
+ deleteTimedCallback id
+</pre>
+<p>
+The ID string is returned by postTimedCallback when a timer is posted.
+<p>
+<h3><A NAME="postWorkCallback">postWorkCallback</A></h3>
+<p>
+Post a callback for a procedure to be called when the server is idle.
+Work procedures are used to perform computations in the background while
+the user interface remains active and able to respond to input events.
+This works only if the user work procedure does its job in small increments,
+doing only a small amount of processing in each call. The work procedure
+will be called repeatedly until it returns a status indicating that it has
+finished its task.
+<p>
+Usage:
+<p>
+<pre>
+ id = postWorkCallback procedure [client-data]
+</pre>
+<p>
+When the server has nothing else to do the user work procedure will be
+called with client_data (if given) as the single argument. The work procedure
+should return the string "done" when all processing is finished, or any other
+string if the procedure is to be called again.
+<p>
+An ID value is returned which may be passed to deleteWorkCallback to delete
+the work procedure.
+<p>
+<h3><A NAME="deleteWorkCallback">deleteWorkCallback</A></h3>
+<p>
+Delete a work callback procedure.
+<p>
+Usage:
+<p>
+<pre>
+ deleteWorkCallback id
+</pre>
+<p>
+The ID string is returned by postWorkCallback when a work procedure is posted.
+
+<hr noshade=5>
+
+<a name="6.3"></a>
+<h3>6.3 Gterm</h3>
+<p>
+The gterm-image widget is a general 2D graphics-imaging widget providing
+a wide range of facilities for drawing graphics and text, for image
+display, and for graphics interaction. Normally the client communicates
+directly with the Gterm widget to draw graphics, download image data,
+and so on, using some communications protocol outside the domain of the
+object manager. Nonetheless so far as possible the facilities of the Gterm
+widget have also been made available to GUI code via the commands listed
+here.
+<p>
+The Gterm widget adds the following function to the OBM library.
+<p>
+<pre>
+ ObmPostSetGtermCallback (obm, &setgterm, setgterm_client_data)
+</pre>
+<p>
+This is called by a client application to post a procedure to be called
+when a gterm widget receives the setGterm command. The calling sequence
+for setGterm callback is as follows:
+<p>
+<pre>
+ setgterm (client_data, gterm_widget)
+</pre>
+<p>
+The purpose of this callback is to tell the client which gterm widget is
+the "active" gterm widget. This is used by clients which only support
+one active Gterm widget, i.e., which can only direct graphics output to
+one Gterm widget at a time.
+<p>
+The messages or commands that can be sent to the Gterm widget by GUI
+code follow.
+<p>
+General commands:
+<p>
+<pre>
+ <a href="#setGterm">setGterm</a> # make widget the active Gterm
+<p>
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a>
+ <a href="#addCallback">addCallback</a> procedure-name callback-type
+ <a href="#reset">reset</a>
+ <a href="#flush">flush</a>
+<p>
+ <a href="#setCursorPos">setCursorPos</a> x y [raster]
+ <a href="#getCursorPos">getCursorPos</a> x y
+ <a href="#setCursorType">setCursorType</a> cursortype
+ <a href="#bell">bell</a>
+</pre>
+<p>
+Graphics drawing commands:
+<p>
+<pre>
+ <a href="#setRaster">setRaster</a> raster
+ raster = <a href="#getRaster">getRaster</a> [raster]
+<p>
+ <a href="notyet.html">setLogRes</a> width height
+ <a href="notyet.html">getLogRes</a> width height
+ <a href="notyet.html">setPhysRes</a> width height
+ <a href="notyet.html">getPhysRes</a> width height
+ <a href="notyet.html">setTextRes</a> rows cols
+ <a href="notyet.html">setDataLevel</a> level
+ <a href="notyet.html">setLineWidth</a> width
+ <a href="notyet.html">setLineStyle</a> style
+ <a href="notyet.html">setColorIndex</a> index
+ <a href="notyet.html">setFillType</a> filltype
+<p>
+ <a href="#clearScreen">clearScreen</a>
+ <a href="notyet.html">drawPolyline</a> vector
+ <a href="notyet.html">drawPolymarker</a> vector
+ <a href="notyet.html">drawPolygon</a> vector
+ <a href="notyet.html">drawMarker</a> x y xsize ysize type
+<p>
+ <a href="notyet.html">drawAlphaText</a> x y text
+ <a href="notyet.html">getAlphaTextSize</a> string width height base
+ <a href="notyet.html">startDialog</a>
+ <a href="notyet.html">endDialog</a>
+ <a href="notyet.html">eraseDialog</a>
+ <a href="notyet.html">drawDialogText</a> x y text
+ <a href="notyet.html">getDialogTextSize</a> string width height base
+</pre>
+<p>
+The coordinates used in the graphics drawing commands are logical
+coordinates as defined by setLogRes, in the coordinate system of the
+reference drawing raster as defined by setRaster. The default reference
+raster is raster zero, the widget's window. Vectors are specified as
+a list of points, e.g., { {x y} {x y} ... }.
+<p>
+Imaging commands:
+<p>
+<pre>
+ <a href="#rasterInit">rasterInit</a>
+ <a href="notyet.html">assignRaster</a> raster drawable
+ <a href="notyet.html">createRaster</a> raster type width height depth
+ <a href="notyet.html">destroyRaster</a> raster
+ exists = <a href="notyet.html">queryRaster</a> raster type width height depth
+ raster = <a href="notyet.html">nextRaster</a> [raster]
+ nrasters = <a href="notyet.html">nRasters</a> [nrasters]
+<p>
+ <a href="#setPixel">setPixel</a> raster x y value
+ value = <a href="#getPixel">getPixel</a> raster x y
+ <a href="#writePixels">writePixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="#readPixels">readPixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="notyet.html">refreshPixels</a> raster ct x1 y1 nx ny
+ pixmap = <a href="notyet.html">createPixmap</a> src x y width height
+ <a href="notyet.html">copyPixmap</a> pixmap dst x y width height
+<p>
+ colormap = <a href="notyet.html">nextColormap</a> [colormap]
+ <a href="notyet.html">freeColormap</a> colormap
+ <a href="notyet.html">writeColormap</a> colormap first nelem colors
+ <a href="notyet.html">readColormap</a> colormap first nelem colors
+ <a href="#loadColormap">loadColormap</a> colormap offset scale
+<p>
+ <a href="notyet.html">initMappings</a>
+ mapping = <a href="#nextMapping">nextMapping</a> [mapping]
+ <a href="notyet.html">freeMapping</a> mapping
+ <a href="notyet.html">enableMapping</a> mapping
+ <a href="notyet.html">disableMapping</a> mapping
+ active = <a href="notyet.html">activeMapping</a> mapping
+ <a href="notyet.html">refreshMapping</a> mapping
+<p>
+ raster = <a href="#selectRaster">selectRaster</a> dras dt dx dy rt rx ry [map]
+ <a href="#unmapPixel">unmapPixel</a> sx sy raster rx ry [rz]
+<p>
+ <a href="notyet.html">copyRaster</a> rop src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#setMapping">setMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#getMapping">getMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+<p>
+ <a href="#flip">flip</a> mapping axis [axis...]
+</pre>
+<p>
+Pixel arrays are long strings consisting either of a sequence of numeric
+pixel values separated by whitespace (space or newline), or a hex encoded
+sequence of bytes (2 hex digits per 8 bit pixel). Colors are specified
+as a list of RGB triplets, e.g., { {R G B} {R G B} ... }.
+<p>
+Refer to the documentation for the Gterm widget for a detailed description
+of rasters, mappings, and colormaps.
+<p>
+Markers:
+<p>
+<pre>
+ <a href="#createMarker">createMarker</a> name [attribute-list]
+ <a href="#markerInit">markerInit</a>
+</pre>
+<p>
+New markers may be created with createMarker. Once created, a marker
+functions under the Object Manager as a named object of class "marker".
+Refer to the marker class for a description of the commands defined for
+a marker.
+<p>
+gterm Actions List
+<p>
+<pre>
+ ignore
+ graphics-input
+ graphics-context
+ crosshair
+ track-cursor
+ enter-window
+ leave-window
+ popup-menu {not implemented}
+ reset
+ m_create
+</pre>
+<p>
+Default translations for Gterm window.
+Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu)
+<p>
+default Gterm Translations
+<p>
+<pre>
+ [Btn1Down]:m_create()
+ [Btn2Down]:crosshair(on)
+ [Btn2Motion]:crosshair(on)
+ [Btn2Up]:crosshair(off)
+ ~Ctrl ~Meta [Btn3Down]:graphics-context()
+ [EnterWindow]:enter-window()
+ [LeaveWindow]:leave-window()
+ [KeyPress]:graphics-input()
+ [Motion]:track-cursor()
+</pre>
+<p>
+<p>
+<a name="6.3.1"></a>
+<h2>6.3.1 GTERM class commands</h2>
+<p>
+<h3><A NAME="setGterm">setGterm</A></h3>
+<p>
+Set the active Gterm widget. A UI can have more than one
+gterm widget, but due to restrictions on the client-server interface, it
+may be possible for only one to receive client output at any one time (any
+gterm widget can generate input to be sent to the client). If the client
+has this restriction, the client-server interface code which uses OBM can
+call the ObmPostSetGtermCallback procedure to post a function to be called
+when the UI code calls the setGterm procedure.
+<p>
+Usage:
+<p>
+<pre>
+ setGterm
+</pre>
+<p>
+<h3><A NAME="activate">activate</A></h3>
+<p>
+Activate the gterm widget. This causes the next GIN mode
+setCursorType to warp the pointer into the gterm window.
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h3><A NAME="deactivate">deactivate</A></h3>
+<p>
+Deactivate the gterm widget. If the cursor has been warped
+into the window by a previous activate/setCursorType GIN mode, this causes
+the cursor to be warped back to where it was previously.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate
+</pre>
+<p>
+<h3><A NAME="reset">reset</A></h3>
+<p>
+Reset the gterm widget. This causes a number of state variables
+affecting graphics drawing options to be set to their default values.
+<p>
+Usage:
+<p>
+<pre>
+ reset
+</pre>
+<p>
+<h3><A NAME="flush">flush</A></h3>
+<p>
+Flush any graphics output and synchronize the state of the widget
+with what is shown on the display.
+<p>
+Usage:
+<p>
+<pre>
+ flush
+</pre>
+<p>
+The gterm widget uses XLIB, which buffers graphics drawing commands and
+automatically sends them to the X server when 1) the buffer fills,
+2) input is requested from the server. Such buffering of data is necessary
+for efficient operation and it should rarely be necessary to explicitly
+flush graphics output since XLIB does this automatically in most cases.
+An example of when explicitly flushing the ouptut might be necessary is in
+cases where smooth animation is desired and drawing the graphics in batches
+could cause the display to appear "jerky".
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Post a callback for a Gterm widget event.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure-name [callback-type]
+</pre>
+<p>
+The recognized Gterm callbacks are
+<p>
+<pre>
+
+ input Called when the graphics-input action is invoked in
+ a translation table. The default Gterm translation
+ table invokes this action when a KeyPress event occurs
+ in the Gterm window.
+ Callback: widget-name input-type event-data
+
+ resize Called when the gterm window is resized.
+ Callback: widget-name width height
+
+ reset Called when the "reset" action is invoked.
+ Callback: widget-name
+
+</pre>
+<p>
+If no callback is specified the default is "input".
+<p>
+Note that in GUI code one can also use the translation table to directly
+invoke GUI procedures without need to use the Gterm input mechanism. This
+is more flexible but we support the Gterm input callback here for
+applications that use the default translations.
+<p>
+<h3><A NAME="setCursorPos">setCursorPos</A></h3>
+<p>
+Warp the cursor (pointer) to the given coordinates. This
+is a graphics drawing command and if no raster number is specified the
+current reference drawing raster, as set with setRaster, defines the
+coordinate system.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorPos x y [raster]
+</pre>
+<p>
+A raster number may optionally given to define the raster coordinate system
+to be used. raster=0 yields screen coordinates.
+<p>
+<h3><A NAME="getCursorPos">getCursorPos</A></h3>
+<p>
+Get the cursor position (raster 0 or screen coordinates).
+<p>
+Usage:
+<p>
+<pre>
+ getCursorPos x y
+</pre>
+<p>
+<h3><A NAME="setCursorType">setCursorType</A></h3>
+<p>
+Set the cursor type.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorType cursor-type
+
+ idle default cursor
+ busy busy cursor, e.g, when program is busy
+ ginMode graphics input mode cursor, set when program is
+ waiting for graphics input
+</pre>
+<p>
+<h3><A NAME="bell">bell</A></h3>
+<p>
+Gterm widget sound output.
+<p>
+Usage:
+<p>
+<pre>
+ bell
+</pre>
+<p>
+<h3><A NAME="setRaster">setRaster</A></h3>
+<p>
+Set the number of the raster to be used to define the drawing
+context (e.g. coordinate system) for graphics and text drawing functions.
+<p>
+Usage:
+<p>
+<pre>
+ setRaster raster-number
+</pre>
+<p>
+<h3><A NAME="getRaster">getRaster</A></h3>
+<p>
+Get the number of the raster which defines the drawing
+context, as set in the last setRaster call.
+<p>
+Usage:
+<p>
+<pre>
+ raster = getRaster [raster]
+</pre>
+<p>
+If the name of a variable is given the raster number will be stored
+directly in that variable.
+<p>
+<h3><A NAME="clearScreen">clearScreen</A></h3>
+<p>
+Clear the "screen", i.e., window. This action clears the
+drawing window and sets a number of drawing state variables to their default
+values.
+<p>
+Usage:
+<p>
+<pre>
+ clearScreen
+</pre>
+<p>
+<h3><A NAME="rasterInit">rasterInit</A></h3>
+<p>
+Initialize the raster subsystem, deleting all rasters and
+mappings and freeing the dynamic part of the colortable.
+<p>
+Usage:
+<p>
+<pre>
+ rasterInit
+</pre>
+<p>
+<h3><A NAME="writePixels">writePixels</A></h3>
+<p>
+Set the values of some subset of the pixels in a raster.
+If any mappings are defined on the affected region and are enabled, any
+destination rasters will be automatically updated as defined by the mapping.
+<p>
+Usage:
+<p>
+<pre>
+ writePixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be written.
+</pre>
+<p>
+Most real-world image processing applications get the Gterm widget handle
+with setGterm and pass binary data to the widget by calling GtWritePixels
+directly. This is the most efficient approach for serious image processing
+where large amounts of data are involved. However, being able to read and
+write raster pixels directly in a GUI can be useful in specialized
+applications, e.g., where the image is computed or modified by the GUI.
+<p>
+<h3><A NAME="setPixel">setPixel</A></h3>
+<p>
+Set the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ setPixel raster x y value
+
+ raster The raster number.
+ x, y The pixel to be set.
+ value The pixel value.
+</pre>
+<p>
+This routine is more efficient than writePixels for setting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be set.
+<p>
+<h3><A NAME="readPixels">readPixels</A></h3>
+<p>
+Get the values of some subset of the pixels in a raster.
+<p>
+Usage:
+<p>
+<pre>
+ readPixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be read.
+</pre>
+<p>
+Use readPixels to read a block of pixels, and getPixel to get the value
+of a single pixel.
+<p>
+<h3><A NAME="getPixel">getPixel</A></h3>
+<p>
+Get the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ getPixel raster x y
+
+ raster The raster number.
+ x, y The pixel to be set.
+</pre>
+<p>
+This routine is more efficient than readPixels for getting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be read.
+<p>
+<h3><A NAME="nextMapping">nextMapping</A></h3>
+<p>
+Return the index of the next unused mapping.
+<p>
+Usage:
+<p>
+<pre>
+ nextMapping
+</pre>
+<p>
+Returns the mapping number as the function value.
+<p>
+<h3><A NAME="getMapping">getMapping</A></h3>
+<p>
+Get a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters except the mapping number are output parameters.
+<p>
+<h3><A NAME="setMapping">setMapping</A></h3>
+<p>
+Set a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ setMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters are input parameters.
+<p>
+<h3><A NAME="loadColormap">loadColormap</A></h3>
+<p>
+Load a colormap.
+<p>
+Usage:
+<p>
+<pre>
+ loadColormap colormap [offset [scale]]
+</pre>
+<p>
+The offset and scale parameters may be used to adjust the brightness and
+contrast of the image when the colormap is loaded. The normalized colormap
+has offset=0.5, scale=1.0. Colormap zero is the hardware colormap.
+<p>
+<h3><A NAME="selectRaster">selectRaster</A></h3>
+<p>
+Given the raw screen coordinates SX,SY (or coords in
+any destination raster), determine the mapping and source raster which are
+mapped to that pixel and return the raster and mapping numbers and the
+coordinates of the same pixel in the source raster.
+<p>
+Usage:
+<p>
+<pre>
+ raster = selectRaster dras dt dx dy rt rx ry [map]
+</pre>
+<p>
+where
+<p>
+<pre>
+ dras display raster
+ dt,rt coordinate type - "pixel" or "ndc"
+ dx,dy display raster coordinates (input)
+ rx,ry source raster coordinates (output)
+ map mapping selected (output)
+</pre>
+<p>
+Note that the coordinates returned by selectRaster are measured (taking
+a line as an example) from zero at the left edge of the first pixel, to
+"width" at the right edge of the last pixel. This means that the floating
+point coordinates of the center of raster pixel N will be N + 0.5. For
+example, if we input screen coordinates (dras=0), x=117, and no mapping
+is in effect, the floating point raster coordinates returned will be 117.5.
+The difference occurs because the input coordinate is a pixel number
+(integer) while the output coordinate is a floating point coordinate
+measuring the continuously variable location a pixel. int(x) will convert
+this coordinate to a raster pixel number.
+<p>
+<h3><A NAME="unmapPixel">unmapPixel</A></h3>
+<p>
+unmapPixel is a simplified, less general version of
+selectRaster which will automatically follow graphics pipelines back to
+the original mapped raster. If desired the raster pixel value can be
+returned as well as the raster number and raster pixel coordinates
+corresponding to a screen (raster 0) pixel.
+<p>
+Usage:
+<p>
+<pre>
+ unmapPixel sx sy raster rx ry [rz]
+</pre>
+<p>
+where
+<p>
+<pre>
+ sx,sy "screen" (raster 0) coordinates
+ raster original mapped raster (output)
+ rx,ry source raster coordinates (output)
+ rz source raster pixel value (output)
+<pre>
+<p>
+By following graphics pipelines back to the original source raster we mean
+the following. If raster A is mapped to raster B which is mapped to C (the
+screen), given a screen coordinate in the mapped region unmapPixel will
+return the raster number and coordinates for raster A.
+<p>
+<h3><A NAME="flip">flip</A></h3>
+<p>
+Edit a mapping to flip the mapped subimage in X and/or Y.
+<p>
+Usage:
+<p>
+<pre>
+ flip mapping axis [axis]
+</pre>
+<p>
+where axis is "x" or "y". This is a convenience routine for changing only
+the flip portion of a mapping.
+<p>
+<h3><A NAME="markerInit">markerInit</A></h3>
+<p>
+Initialize the Marker subsystem for a Gterm widget.
+This destroys all markers and initializes the marker subsystem.
+<p>
+Usage:
+<p>
+<pre>
+ markerInit
+</pre>
+<p>
+<h3><A NAME="createMarker">createMarker</A></h3>
+<p>
+Create a new marker.
+<p>
+Usage:
+<p>
+<pre>
+ createMarker name attribute-list
+ e.g. createMarker name {attribute value [attribute value ...]}
+ or createMarker name attribute value [attribute value ...]
+<pre>
+<p>
+Any marker attribute may be assigned a value when the marker is created.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker attribute names. Often the
+the attributes "type" and "createMode" need to be specified at marker
+create time.
+<p>
+<pre>
+ type The marker type: text, rectangle, circle, etc.
+
+ createMode A marker should be created with createMode=interactive
+ if the user is expected to interactively drag out
+ the marker using the pointer and either the default
+ or an application specified translation table. A
+ marker can also be created interactively using only
+ the m_create (marker create) action, however m_create
+ does not allow the marker attributes to be set.
+<pre>
+<p>
+There are any number of ways to use a GUI to create a marker under the
+Object Manager, but an example might be using a translation to call a GUI
+procedure which issues the createMarker call. For example a pointer down
+event could translate as "call(newMarker,$name,$x,$y) m_create()" where
+newMarker is a GUI marker creation procedure which sends a createMarker
+message to the Gterm widget. The GUI procedure could set the marker
+attributes as desired, possibly using additional GUI components to define
+the marker attributes. The m_create action will notice that a
+createMarker has been executed and will merely activate the marker and
+give it the pointer focus (i.e. install the marker translations). The
+user will then use the pointer or keyboard to drag out the marker.
+<p>
+If the marker is created noninteractive the application must set the marker
+position and size using marker attributes. If the marker is sensitive
+the user can then use the marker's translations to interactively modify
+the marker (resize it, move it, etc.). All markers which are visible and
+sensitive and which have the necessary translations can be interactively
+modified by the user; the reason for creating a marker in interactive mode
+is to allow the initial marker position and size to be specified
+interactively *when* the marker is created, instead of afterwards.
+<p>
+Any number of attributes may be given when the marker is created. Most
+marker attributes can also be modified after a marker has been created
+by sending setAttribute messages to the marker.
+
+<hr noshade=5>
+
+<a name="6.4"></a>
+<h3>6.4 HTML</h3>
+
+The HTML (hypertext markup language) widget displays a block of HTML
+formatted text, the "document" to be displayed. The text consists of a
+mixture of text to be displayed and embedded formatting directives. The
+text may also contain "hot links" pointing to other HTML-formatted
+documents.
+
+<pre>
+ setText text [target [header_text [footer_text]]]
+ text = getText [format [font]]
+ retestAnchors
+
+ id = positionToId x y
+ idToPosition id x y
+ anchorToPosition name x y
+ id = anchorToId name
+ gotoId id
+
+ n = getHRefs list
+ n = getImageSrcs list
+ n = getLinks list
+
+ setSelection start end
+ text = getSelection start end
+ clearSelection
+
+ searchText pattern start end [direction [search_type]]
+
+ addCallback procedure-name [callback-type]
+ deleteCallback procedure-name [callback-type]
+</pre>
+
+The possible callback types and their callback arguments are as follows.
+
+<pre>
+ anchor widget cbtype event text href element_id
+ testAnchor widget cbtype href
+ submitForm widget cbtype event attrs href method enctype encentity
+ link widget cbtype href role
+ pointerMotion widget cbtype href
+</pre>
+
+See the comments below for further details on the callback types and their
+arguments.
+
+<p>
+<a name="6.4.1"></a>
+<h2>6.4.1 Command Summary</h2>
+<p>
+
+<hr noshade=5>
+
+<a name="6.5"></a>
+<h3>6.5 Markers</h3>
+<p>
+A marker is a graphics object implemented by the Gterm-Image widget.
+Markers are not real toolkit widgets, but they act much like widgets and
+are interfaced as an object class under the Object Manager. The Marker
+class is not a subclass, it is a base class like Widget, but Marker objects
+can exist only as children of Gterm widgets.
+<p>
+Since markers are not independent widgets but rather part of a Gterm widget
+instance, the parent Gterm widget is partially responsible for managing
+markers. The Gterm widget implements the following commands for dealing
+with markers.
+<p>
+<pre>
+ <a href="gtermclass.html#createMarker">createMarker</a> name [attribute-list]
+ <a href="gtermclass.html#markerInit">markerInit</a>
+</pre>
+<p>
+A new marker is created by sending the createMarker message to the parent
+gterm widget. This creates a marker of the given name and type.
+The markerInit command, if sent to a gterm widget, destroys any markers
+defined for that widget and reinitializes the marker facility. Markers
+may also be created by action procedures in response to user input events.
+<p>
+A marker may be destroyed by itself in response to an input event (e.g. the
+user presses the delete key), by sending the marker the destroy message
+to tell it to destroy itself, by sending a markerInit to the parent gterm
+widget, or by destroying the marker object (or any parent) with the server
+command <a href="#destroyObject">destroyObject</a>.
+<p>
+Once a marker has been created it behaves as an independent object and
+receives and executes messages, responds to events, generates callbacks,
+and so on. The marker class defines the following commands.
+<p>
+<pre>
+ <a href="#makeCopy">makeCopy</a> name
+ <a href="#addCallback">addCallback</a> procedure [event [event ...]]
+ <a href="#notify">notify</a> [event-type [param [param ...]]]
+ <a href="#destroy">destroy</a> [nocallback]
+<p>
+ <a href="#markpos">markpos</a>
+ <a href="#redraw">redraw</a> [function] [markpos|nomarkpos] [erase|noerase]
+<p>
+ <a href="#raise">raise</a> [reference-marker]
+ <a href="#lower">lower</a> [reference-marker]
+<p>
+ <a href="#move">move</a> x y
+ <a href="#resize">resize</a> width height
+ <a href="#rotate">rotate</a> angle # radians
+<p>
+ <a href="#setAttribute">set</a> attribute value # alias for setAttribute
+ value = <a href="#getAttribute">get</a> attribute # alias for getAttribute
+<p>
+ <a href="#setAttribute">setAttribute</a> attribute value
+ value = <a href="#getAttribute">getAttribute</a> attribute
+ <a href="#setAttributes">setAttributes</a> attribute-list
+ <a href="#getAttributes">getAttributes</a> attribute-list
+ <a href="#setVertices">setVertices</a> points first npts
+ <a href="#getVertices">getVertices</a> points first npts
+<p>
+ region = <a href="#getRegion">getRegion</a> [unmap] [coord-type]
+ <a href="#getRect">getRect</a> dx dy dnx dny
+</pre>
+<p>
+Marker positions and dimensions are given in window (raster 0) coordinates.
+<p>
+The operators raise, lower, move, resize, and rotate erase the marker,
+modify it as indicated, and redraw it with the new attributes. For finer
+control over marker attributes one can use [get|set]Attribute[s] and
+[get|set]Vertices to edit the markers directly. In this case an auto
+redraw is not performed (unless the autoRedraw marker attribute is set).
+The usual sequence is a markpos to record the marker position, one or more
+setAttribute calls to change marker attributes, then a redraw to erase
+the old marker and redraw the new one. Markers have many attributes which
+can be set to control things like the position and size, colors, line
+widths, fill type and style, font, rubber-band technique, and so on.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker types and attributes.
+<p>
+The marker type may be changed at runtime without destroying the marker.
+For example a circle can be changed to an ellipse or a rectangle. This
+also works for polygons (the vertex list is preserved and restored when
+the marker is changed back to a polygon).
+<p>
+The current shape of a marker may be queried with getVertices, which
+returns the polygon or polyline vertex list in window coordinates. A more
+powerful routine which does something similar is getRegion. This routine
+returns a high level description of the region outlined by the marker,
+giving the marker type (rectangle, circle, ellipse etc.), center, width
+and height, and so on. Any position or dimension information may
+optionally be transformed back to the original source raster, if the marker
+center is in a region of the window which is the destination of an active
+mapping. The unmap option will follow multiple mappings back to the
+original mapped source raster.
+<p>
+The getRect function returns the parameters of the region outlined by a
+rectangle marker in a form convenient for use in a Gterm setMapping call
+(this is used to display an image within a marker).
+<p>
+Default translations when pointer is over a marker.
+default Marker Translations
+<p>
+<pre>
+ Shift &lt;Btn1Motion&gt; m_rotateResize()
+ &lt;Btn1Motion&gt; m_moveResize()
+ Shift &lt;Btn1Down&gt; m_raise() m_markpos()
+ &lt;Btn1Down&gt; m_raise() m_markposAdd()
+ &lt;Btn1Up&gt; m_redraw() m_destroyNull()
+ &lt;Btn2Down&gt; m_lower()
+ &lt;Key&gt; BackSpace m_deleteDestroy()
+ &lt;Key&gt; Delete m_deleteDestroy()
+ &lt;KeyPress&gt; m_input()
+ &lt;Motion&gt; track-cursor()
+</pre>
+<p>
+<a name="6.5.1"></a>
+<h2>6.5.1 Command Summary</h2>
+<p>
+<h3>makeCopy</A></h3>
+<p>
+Copy a marker. The new marker is initially identical to the
+old one, and will not be distinct until, e.g., moved to a new center.
+<p>
+Usage:
+<p>
+<pre>
+ makeCopy name
+</pre>
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Post a marker callback to be called when the specified
+event or events occurs. If no events are listed a Notify callback will
+be posted.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure [event [event ...]]
+</pre>
+<p>
+<h3><A NAME="notify">notify</A></h3>
+<p>
+Generate a Marker pseudo-event, causing any posted client
+callback procedures to be called.
+<p>
+Usage:
+<p>
+<pre>
+ notify [event-type [param [param ...]]]
+</pre>
+<p>
+<h3><A NAME="destroy">destroy</A></h3>
+<p>
+Destroy a marker. Just tell the marker to destroy itself.
+All cleanup outside the marker facility relies upon the use of callbacks.
+This includes our callback markerDestroyCallback below.
+<p>
+Usage:
+<p>
+<pre>
+ destroy
+</pre>
+<p>
+<h3><A NAME="markpos">markpos</A></h3>
+<p>
+Mark the current position of a marker for a later redraw.
+<p>
+Usage:
+<p>
+<pre>
+ markpos
+</pre>
+<p>
+Markpos is used to mark the position of a marker before changing any
+marker attributes, so that a later "redraw marked" will erase the old
+marker rather than the new one. This is necessary, for example, if any
+marker attributes are changed which affect the size or position of the
+marker.
+<p>
+<h3><A NAME="redraw">redraw</A></h3>
+<p>
+Redraw a marker.
+<p>
+Usage:
+<p>
+<pre>
+ redraw [function] [erase|noerase] [markpos|nomarkpos]
+</pre>
+<p>
+By default redraw will erase the old marker at the position indicated by
+a previous call to markpos, and redraw the marker with the current
+attributes using the drawing function copy (copy source to destination).
+Hence the usual usage is "markpos ... change marker attributes ... redraw".
+Optional arguments may be given to change the drawing function, enable or
+disable erase, or force redraw to do a markpos. These arguments may be
+given in any order.
+<p>
+The drawing functions are as given in the XLIB documentation, minus the
+"GX" prefix. The most commonly used functions are "copy" and "xor".
+A normal marker redraw uses function=copy.
+<p>
+<h3><A NAME="raise">raise</A></h3>
+<p>
+Raise a marker, i.e., cause it to be drawn on top of other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ raise [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will raise itself above this
+marker, otherwise the raised marker becomes the topmost marker.
+<p>
+<h3><A NAME="lower">lower</A></h3>
+<p>
+Lower a marker, i.e., cause it to be drawn beneath other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ lower [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will lower itself beneath this
+marker, otherwise the lowered marker becomes the lowest marker.
+<p>
+<h3><A NAME="move">move</A></h3>
+<p>
+Move a marker.
+<p>
+Usage:
+<p>
+<pre>
+ move x y
+</pre>
+<p>
+Move the marker center to the indicated coordinates in the display window.
+<p>
+<h3><A NAME="resize">resize</A></h3>
+<p>
+Resize a marker.
+<p>
+Usage:
+<p>
+<pre>
+ resize width height
+</pre>
+<p>
+Resize the marker to the indicated size. By default width and height are
+given in pixels. For a text marker one can append "ch" to indicate that
+the units are chars in whatever font is in use, e.g., "40ch" or "40 chars"
+is an acceptable value for a text marker dimension.
+<p>
+<h3><A NAME="rotate">rotate</A></h3>
+<p>
+Rotate a marker.
+<p>
+Usage:
+<p>
+<pre>
+ rotate angle
+</pre>
+<p>
+Redraw a marker oriented to the given rotation angle. The angle is
+given in radians.
+<p>
+<h3><A NAME="getAttribute">getAttribute</A></h3>
+<p>
+Return the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ value = getAttribute attribute-name
+</pre>
+<p>
+<h3><A NAME="setAttribute">setAttribute</A></h3>
+<p>
+Set the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ setAttribute attribute-name value
+</pre>
+<p>
+<h3><A NAME="getAttributes">getAttributes</A></h3>
+<p>
+Return the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ getAttributes attribute-list
+ i.e. getAttributes {name value [name value ...]}
+ or getAttributes name value [name value ...]
+</pre>
+<p>
+where "value" is the name of the variable in which the attribute value
+is to be stored.
+<p>
+<h3><A NAME="setAttributes">setAttributes</A></h3>
+<p>
+Set the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ setAttributes attribute-list
+ i.e. setAttributes {name value [name value ...]}
+</pre>
+<p>
+where "value" is the new value of the associated marker attribute.
+<p>
+<h3><A NAME="getVertices">getVertices</A></h3>
+<p>
+Get some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ getVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is returned in the
+variable "points", as a string of the form { {x y} {x y} ...}. The first
+point is number zero.
+<p>
+<h3><A NAME="setVertices">setVertices</A></h3>
+<p>
+Set some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ setVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is set using the points
+passed in the "points" variable as a string of the form { {x y} {x y} ...}.
+If FIRST and NPTS are not specified first is assumed to be zero (the first
+point) and NPTS is the length of the points array.
+<p>
+<h3><A NAME="getRegion">getRegion</A></h3>
+<p>
+Return as a text string a high level description of the
+region defined by a marker.
+<p>
+Usage:
+<p>
+<pre>
+ region = getRegion [unmap] [coord-type]
+</pre>
+<p>
+The output string defines the marker type and the major marker positional
+attributes. The region description formats for the various marker types
+follow.
+<p>
+<pre>
+ text raster x y width height
+ line raster x y x y
+ polyline raster npts { {x y} {x y} ...}
+ rectangle raster x y width height rotangle
+ circle raster x y radius
+ ellipse raster x y width height rotangle
+ polygon raster npts { {x y} {x y} ...}
+</pre>
+<p>
+Here, width and height refer to the distance from the marker center to an
+edge, not to the width or height of the whole marker. This avoids
+ambiguities about where the edge of a marker is if the width is even or
+odd. Using the center to edge measurement, the edge is at x +/- width,
+y +/- height.
+<p>
+If the "unmap" flag is given getRegion will attempt to associate the
+marker with a mapped raster, reversing any mappings from the screen back
+to the original source raster, and returning the raster number and raster
+coordinates and marker sizes. If "unmap" is not given the marker
+coordinates will refer to raster 0. Either pixel ("pixel") or NDC
+("ndc") coordinates may be returned, pixel coordinates being the default.
+<p>
+<h3><A NAME="getRect">getRect</A></h3>
+<p>
+Return the region enclosed by a rectangle marker. The rect is
+returned in a form convenient for use as the destination rect in a gterm
+widget raster mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getRect dx dy dnx dny
+</pre>
+<p>
+The rect is stored in the output arguments.
+<p>
+
+<hr noshade=5>
+
+<a name="6.6"></a>
+<h3>6.6 Widget</h3>
+<p>
+The Widget class is the generic or base class for the window system
+toolkit widgets supported by the object manager. The Widget class
+supports a number of different Xt widget classes using a table driven
+approach to describe each widget. Any widget may be created, destroyed,
+and manipulated in various ways using only the generic Widget class
+procedures and Widget-specific resources. The Widget class may be
+subclassed to support complex Widgets that require custom class-specific
+commands for use by the GUI code.
+<p>
+Generic Widget-class commands:
+<p>
+<pre>
+ <a href="#set">set</a> &lt;resource-name&gt; &lt;value&gt;
+ <a href="#get">get</a> &lt;resource-name&gt;
+<p>
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt; [<callback-name>]
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#setSensitive">setSensitive</a> &lt;sensitive&gt;
+ <a href="#isSensitive">isSensitive</a>
+<p>
+ <a href="#realize">realize</a>
+ <a href="#unrealize">unrealize</a>
+ <a href="#isRealized">isRealizeed</a>
+ <a href="#map">map</a>
+ <a href="#unmap">unmap</a>
+ <a href="#manage">manage</a> child [child ...]
+ <a href="#unmanage">unmanage</a> child [child ...]
+ <a href="#popup">popup</a> [grab-kind]
+ <a href="#popdown">popdown</a>
+ <a href="#popupSpringLoaded">popupSpringLoaded</a>
+<p>
+ <a href="#move">move</a> &lt;x&gt; &lt;y&gt;
+ <a href="#resize">resize</a> &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+ <a href="#configure">configure</a> &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+The most important Widget commands are set/get resource, and the
+callbacks. The widget sensitivity can be set and queried using set/get
+resource, but special procedures are provided to make this common operation
+more convenient.
+<p>
+Class specific functions:
+<p>
+<pre>
+ <a href="#append">append</a> text # text widget
+ <a href="#setList">setList</a> list [resize] # list widget
+ value = <a href="#getItem">getItem</a> itemno
+ <a href="#highlight">highlight</a> itemno
+ <a href="#unhighlight">unhighlight</a>
+</pre>
+<p>
+Ideally the widget class should be subclassed for widgets that require
+class-specific functions, but in simple cases involving standard widgets
+the support is built into the widget class code as a special case.
+<p>
+Special actions (used in translations):
+<p>
+<pre>
+ <a href="#do_userproc">call</a> (proc [,arg, ...])
+ <a href="#do_popup">popup</a> (menu-name [xoffset [yoffset]])
+ <a href="#do_popdown">popdown</a> (menu-name)
+</pre>
+<p>
+The "call" action is a very general mechanism which allows any GUI procedure
+to be registered with any translation using the X translation table
+mechanism. The popup and popdown actions are used for popup menus. The
+menu will be popped up at the event coordinates plus the optional offsets
+if given.
+<p>
+Event handling:
+<p>
+<pre>
+ <a href="#addEventHandler">addEventHandler</a> &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+Event callback:
+<p>
+<pre>
+ <a href="#userEventHandler">userEventHandler</a> widget event-type time wx wy rx ry other
+</pre>
+<p>
+In most cases translations are preferable to events, but a GUI can capture
+raw events if it wishes by adding event handlers. Nearly all of the X
+event types are supported. The callback syntax employs a number of
+standard arguments, followed by a number of event-specific arguments.
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Add a callback procedure to the callback list for
+a widget. If no callback name is given, "callback" is assumed.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback <procedure-name> [&lt;callback-name&gt;]
+</pre>
+<p>
+Specific widgets only support certain types of callbacks. There is no
+checking that the callback type specified is supported by a widget; the
+wrong type of callback can be registered, but it will never be called.
+<p>
+<h3><A NAME="deleteCallback">deleteCallback</A></h3>
+<p>
+Delete a callback procedure previously registered
+for a widget.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h3><A NAME="do_userproc">do_userproc (call)</A></h3>
+<p>
+Translation action procedure used to call general user
+action procedures in the interpreter. The name of the user procedure to
+be called is given as the first argument in the translation. For example,
+the translation "call(foo,a,b,c)" would cause procedure foo to be called
+with the arguments (a,b,c). The following arguments are special:
+<p>
+<pre>
+ Argument Replaced by
+<p>
+ $name object name of widget
+ $time event->time
+ $x event->x
+ $y event->y
+ $x_root event->x_root
+ $y_root event->y_root
+</pre>
+<p>
+The "user procedure" can be any server procedure.
+<p>
+<h3><A NAME="do_popup">do_popup</A></h3>
+<p>
+Popup a menu (or other spring loaded popup) at the location
+of the event which triggered this action.
+<p>
+Usage:
+<p>
+<pre>
+ popup(menu-name [xoffset [yoffset]])
+</pre>
+<p>
+<h3><A NAME="do_popdown">do_popdown</A></h3>
+<p>
+Pop down a menu.
+<p>
+Usage:
+<p>
+<pre>
+ popdown(menu-name)
+</pre>
+<p>
+<h3><A NAME="set">set</A></h3>
+<p>
+Set a widget resource.
+<p>
+Usage:
+<p>
+<pre>
+ set &lt;resource-name&gt; &lt;value&gt;
+</pre>
+<p>
+<h3><A NAME="get">get</A></h3>
+<p>
+Get a widget resource value as a string.
+<p>
+Usage:
+<p>
+<pre>
+ get &lt;resource-name&gt;
+</pre>
+<p>
+<h3><A NAME="append">append</A></h3>
+<p>
+Append data to a text widget.
+<p>
+Usage:
+<p>
+<pre>
+ append &lt;text&gt;
+</pre>
+<p>
+<h3><A NAME="setList">setList</A></h3>
+<p>
+Set the item list of a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ setList list [resize]
+</pre>
+<p>
+The list is a simple list of strings, passed as a single string argument to
+setList (quotes, braces, etc. may be used to quote strings containing
+special characters).
+<p>
+<h3><A NAME="getItem">getItem</A></h3>
+<p>
+Get an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ value = getItem itemno
+</pre>
+<p>
+If ITEMNO is a number the indicated list item is returned, or the string
+"EOF" if the requested item is beyond the end of the list. Otherwise the
+currently selected item is returned, and the index of the item is returned
+in the output variable ITEMNO. If no item is currently selected ITEMNO
+will be set to "none" on output.
+<p>
+<h3><A NAME="highlight">highlight</A></h3>
+<p>
+Highlight an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ highlight itemno
+</pre>
+<p>
+The indicated item of the list is highlighted as if the item had been
+selected by the user. Any previously highlighted item is unhighlighted.
+<p>
+<h3><A NAME="unhighlight">unhighlight</A></h3>
+<p>
+Unhighlight the currently highlighted item in a
+list widget.
+<p>
+Usage:
+<p>
+<pre>
+ unhighlight
+</pre>
+<p>
+Any currently highlighted item in the list widget is unhighlighted.
+<p>
+<h3><A NAME="realize">realize</A></h3>
+<p>
+Realize a widget. This activates and assigns windows for
+a widget and all of its descendants. Realizing a widget does not in itself
+cause it to appear on the screen.
+<p>
+Usage:
+<p>
+<pre>
+ realize
+</pre>
+<p>
+<h3><A NAME="unrealize">unrealize</A></h3>
+<p>
+Unrealize a widget. This destroys the windows assigned
+to a widget and all of its descendants.
+<p>
+Usage:
+<p>
+<pre>
+ unrealize
+</pre>
+<p>
+<h3><A NAME="isRealized">isRealized</A></h3>
+<p>
+Test whether a widget is realized.
+<p>
+Usage:
+<p>
+<pre>
+ isRealized
+</pre>
+<p>
+<h3><A NAME="map">map</A></h3>
+<p>
+Map a widget.
+<p>
+Usage:
+<p>
+<pre>
+ map
+</pre>
+<p>
+<h3><A NAME="unmap">unmap</A></h3>
+<p>
+Unmap a widget.
+<p>
+Usage:
+<p>
+<pre>
+ unmap
+</pre>
+<p>
+<h3><A NAME="manage">manage</A></h3>
+<p>
+Manage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Managing the
+children makes them appear in the window, possibly causing the other
+children to be rearranged in the window.
+<p>
+Usage:
+<p>
+<pre>
+ manage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h3><A NAME="unmanage">unmanage</A></h3>
+<p>
+Unmanage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Unmanaging the
+children makes them disappear from the window and be removed from geometry
+management, possibly causing the other children to be rearranged in the
+window.
+<p>
+Usage:
+<p>
+<pre>
+ unmanage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h3><A NAME="popup">popup</A></h3>
+<p>
+Popup a shell widget. If no grab is indicated the popup
+can remain up while other windows accept input.
+<p>
+Usage:
+<p>
+<pre>
+ popup [grab-kind]
+</pre>
+<p>
+<h3><A NAME="popdown">popdown</A></h3>
+<p>
+Popdown a shell widget.
+<p>
+Usage:
+<p>
+<pre>
+ popdown
+</pre>
+<p>
+<h3><A NAME="popupSpringLoaded">popupSpringLoaded</A></h3>
+<p>
+Popup a shell widget, e.g., a popup menu.
+This implies an exclusive grab.
+<p>
+Usage:
+<p>
+<pre>
+ popupSpringLoaded
+</pre>
+<p>
+<h3><A NAME="move">move</A></h3>
+<p>
+Move a widget to the given window relative coordinates.
+<p>
+Usage:
+<p>
+<pre>
+ move &lt;x&gt; &lt;y&gt;
+</pre>
+<p>
+<h3><A NAME="resize">resize</A></h3>
+<p>
+Resize a widget.
+<p>
+Usage:
+<p>
+<pre>
+ resize &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h3><A NAME="configure">configure</A></h3>
+<p>
+Configure a widget, i.e., execute a simultaneous
+move and resize.
+<p>
+Usage:
+<p>
+<pre>
+ configure &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h3><A NAME="setSensitive">setSensitive</A></h3>
+<p>
+Set the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ setSensitive &lt;sensitive&gt;
+</pre>
+<p>
+<h3><A NAME="isSensitive">isSensitive</A></h3>
+<p>
+Test the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ isSensitive
+</pre>
+<p>
+<h3><A NAME="addEventHandler">addEventHandler</A></h3>
+<p>
+Add a custom event handler to a widget. A list
+of event masks is given to define the classes of events the user supplied
+event handling procedure is to receive.
+<p>
+Usage:
+<p>
+<pre>
+ addEventHandler &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+<h3><A NAME="removeEventHandler">removeEventHandler</A></h3>
+<p>
+Remove an event handler previously posted
+with addEventHandler, above.
+<p>
+Usage:
+<p>
+<pre>
+ removeEventHandler procname
+</pre>
+<p>
+<h3><A NAME="event">event</A></h3>
+<p>
+Generic event handler called when a widget event handler
+posted by addEventHandler is called.
+<p>
+The user event handler is called as
+<p>
+<pre>
+ userEventHandler widget event-type time wx wy rx ry other
+</pre>
+<p>
+where "other" is an event-type specific list of fields describing the
+the event.
+<hr noshade=5>
+
+<a name="6.7"></a>
+<h3>6.7 Parameter</h3>
+<p>
+The UI parameter class is used for client-UI communications. The client
+does not control the user interface directly, rather the UI defines a set
+of abstract UI parameters, and during execution the client application
+assigns values to these parameters. These UI parameters should be thought
+of as describing the runtime state of the client as viewed by the GUI.
+The GUI is free to interpret this state information in any way, including
+ignoring it. Many GUIs can be written which use the same client state
+as described by the UI parameters.
+<p>
+Assigning a value to a UI parameter causes the new value to be stored, and
+any parameter action procedures registered by the UI to be called.
+The action or actions [if any] taken when a parameter value changes are
+arbitrary, e.g. the action might be something as simple as changing a
+displayed value of a UI widget, or something more complex like displaying
+a popup.
+<p>
+<h2>UI Parameter class commands:</h2>
+<p>
+<pre>
+ <a href="#getValue">getValue</a>
+ <a href="#setValue">setValue</a> &lt;new-value&gt;
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt;
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#notify">notify</a>
+</pre>
+<p>
+The most common usage is for the GUI to post one or more callbacks for
+each UI parameter. When the UI parameter value is changed [with setValue,
+e.g. by the client] the GUI callback procedures are called with the old
+and new UI parameter values on the command line. addCallback is used to
+add a callback procedure, and deleteCallback to delete one. Multiple
+callbacks may be registered for a single UI parameter. notify is used
+to simulate a parameter value change, causing any callback procedures to
+be invoked.
+<p>
+The callback procedure is called as follows:
+<p>
+<pre>
+ user-procedure param-name {old-value} {new-value}
+</pre>
+<p>
+The important thing to note here is that the old and new value strings
+are quoted with braces. This prevents any interpretation of the string
+by Tcl when the callback is executed, which is necessary because the
+strings can contain arbitrary data. When Tcl calls the callback the
+first level of braces will be stripped off, leaving old-value and new-value
+each as a single string argument.
+<p>
+<p>
+<h2><A NAME="setValue">setValue</A></h2>
+<p>
+Set the value of a parameter, and notify all clients
+via the posted callback procedures that the parameter value has changed.
+<p>
+Usage:
+<p>
+<pre>
+ setValue &lt;new-value&gt;
+</pre>
+<p>
+<h2><A NAME="getValue">getValue</A></h2>
+<p>
+Get the value of a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ getValue
+</pre>
+<p>
+<h2><A NAME="notify">notify</A></h2>
+<p>
+Notify the registered clients of a parameter as if the
+value had changed.
+<p>
+Usage:
+<p>
+<pre>
+ notify
+</pre>
+<p>
+<h2><A NAME="addCallback">addCallback</A></h2>
+<p>
+Add a callback procedure to the callback list for
+a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h2><A NAME="deleteCallback">deleteCallback</A></h2>
+<p>
+Delete a callback procedure previously registered
+for a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<hr noshade=5>
+
+<hr noshade=5>
+</body>
+</html>
diff --git a/vendor/x11iraf/obm/docs/obm/obm.html b/vendor/x11iraf/obm/docs/obm/obm.html
new file mode 100644
index 00000000..b7e531ca
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/obm.html
@@ -0,0 +1,2515 @@
+<html>
+<body bgcolor=#FFFFFF>
+<title>IRAF Object Manager Tutorial</title>
+
+<center>
+<h1>IRAF Object Manager Tutorial</h1>
+</center>
+<hr noshade=5>
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#1">1. Introduction</a>
+<li><a href="#2">2. System Architecture</a>
+<li><a href="#3">3. The Client Process</a>
+ <ul>
+ <li><a href="#3.1">3.1 IRAF Graphics Task</a>
+ <ul>
+ <li><a href="#3.1.1">3.1.1 XGterm</a>
+ </ul>
+ <li><a href="#3.2">3.2 Standalone Task</a>
+ <li><a href="#3.3">3.3 OBM Shell</a>
+ <li><a href="#3.4">3.4 Named External Clients</a>
+ </ul>
+<li><a href="#4">4. UI Definition File</a>
+ <ul>
+ <li><a href="#4.1">4.1 Example Interface</a>
+ </ul>
+<li><a href="#5">5. Widget Toolkit</a>
+<li><a href="#6">6. Object Classes</a>
+ <ul>
+ <li><a href="#6.1">6.1 Client</a>
+ <ul>
+ <li><a href="#6.1.1">6.1.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.2">6.2 Server</a>
+ <ul>
+ <li><a href="#6.2.1">6.2.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.3">6.3 Gterm</a>
+ <ul>
+ <li><a href="#6.3.1">6.3.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.4">6.4 HTML</a>
+ <ul>
+ <li><a href="#6.4.1">6.4.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.5">6.5 Markers</a>
+ <ul>
+ <li><a href="#6.5.1">6.5.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.6">6.6 Widget</a>
+ <ul>
+ <li><a href="#6.6.1">6.6.1 Command Summary</a>
+ </ul>
+ <li><a href="#6.7">6.7 Parameter</a>
+ <ul>
+ <li><a href="#6.7.1">6.7.1 Command Summary</a>
+ </ul>
+ </ul>
+</ul>
+
+<hr noshade=5>
+
+<a name="1"></a>
+<h3>1. Introduction</h3>
+<p>
+An Object Manager (OBM) user interface (UI) consists of one or more windows
+containing an arbitrary hierarchy of widgets. These widgets and their
+runtime actions are defined by an interpreted text program uploaded
+by the client application, which does not itself deal directly with the
+window user interface. This interpreted program is currently written
+as a Tcl script.
+<p>
+The OBM provides a high level abstraction for dealing with widgets and
+other UI objects. The main function of the object manager is to deliver
+messages to UI objects. Each instance of a widget is an object in the
+interface. The UI contains other types of objects as well, including the
+client object (client application), the server object (the object manager
+itself), and the application specific UI parameters, each of which is an
+object with a callback list of procedures to be called when the parameter
+value changes. All of these UI objects can receive messages and take actions
+as a result. Messages may come from the client application, or as a result
+of actions executed by the interpreted UI code in response to graphics events.
+<hr noshade=5>
+<p>
+<a name="2"></a>
+<h3>2. System Architecture</h3>
+<p>
+For a complete description of the OBM system architecture see Tody, D,
+ADASS Proceedings 1994. A <a href="todyd.ps">postscript version of this
+paper</a> is also vailable.
+<p>
+<hr noshade=5>
+<p>
+<a name="3"></a>
+<h3>3. The Client Process</h3>
+<p>
+ The primary advantage of the OBM architecture over traditional GUI
+design is the separation of the user interface from the executable client
+code, meaning that either can be completely rewritten or developed separately
+without affecting the other so long as the messaging between the two
+remains the same. The client itself is responsible for initializing the OBM
+toolkit and uploading the UI definition file, after that it usually enters
+an event loop of some kind (e.g. an iraf graphics cursor loop, or X event
+handler) to process actions defined in the client callbacks.
+<p>
+ It's important that the client program maintain the state of the
+application rather than the UI file. For example, a text widget in the
+interface may instruct the client to load a file, however if this cannot
+be done the interface should not have independently reset labels or
+whatever assuming the action was done at all. Instead, the client program
+uses the Parameter Class objects in the interface to update the state of
+the GUI as a result of some action (whose origins may not have been in the
+GUI at all). So for example a sequence of events could be something like
+
+<ul><ul>
+<li> User selects a widget in the interface, it's callback sends a
+ message to the client directing some action be taken
+<li> Client receives the message and performs an action in the client
+<li> If action fails, (optionally) notify GUI of failure (e.g. send a
+ message to an 'alert' parameter to popup a dialog box, beep the
+ terminal, etc)
+<li> If action succeeds, notify GUI of new state (e.g. send a message
+ to the 'filename' Parameter object containing the new file name).
+<li> Callback on the 'filename' parameter then updates the status bar
+ widget with the name of the new active file.
+</ul></ul>
+
+<p>
+ The messaging between the client and UI depend on the details of how
+the client is implemented. In general any callback procedure in the UI can
+send a message to any other object in the interface, but the client should
+generally communicate only via the Parameter objects to avoid side effects
+and maintain a clear separation between the UI and the client code.
+
+<a name="3.1"></a>
+<h3>3.1 IRAF Graphics Task</h3>
+
+<a name="3.1.1"></a>
+<h3>3.1.1 XGterm</h3>
+
+<a name="3.2"></a>
+<h3>3.2 Standalone Task</h3>
+
+<a name="3.3"></a>
+<h3>3.3 OBM Shell</h3>
+<p>
+ The <i>obmsh</i> is a unix shell interpreter for GUI scripts. It is
+a minimal standalone client with a single callback to exit the application,
+otherwise it's only job is to activate the GUI file. Any messages sent to
+the client (except a 'quit') are simply absorbed by the client
+<p>
+ Despite the apparent lack of functionality this is sometimes all
+that is required for an interface that can operate independently. Remember
+that the Tcl scripting language has it's own facilities for file I/O,
+process execution, etc, all of which are still available in the GUI. In
+the case of IRAF tasks it's an interface violation to use these facilities
+directly, however they still allow for the easy creation of a GUI which
+requires no real underlying client (e.g. a tcl debug shell, a calculator
+application, task launcher, etc).
+
+<a name="3.4"></a>
+<h3>3.4 Named External Clients</h3>
+
+<p>
+<p>
+<hr noshade=5>
+<p>
+<a name="4"></a>
+<h3>4. UI Definition File</h3>
+<p>
+A UI definition consists of a sequence of commands to be executed by the
+server object using Tcl is used as an embedded interpreter within the OBM.
+The Tcl script contains several required OBM-specific functions (in
+addition to the user-defined callbacks) which is uploaded by the client
+as a message for the server object.
+<pre>
+ <a href="#resetReset">reset-server</a>
+ <a href="#appInitialize">appInitialize</a> appName appClass Resources
+ <a href="#createObjects">createObjects</a> [name]
+ <a href="#activate">activate</a>
+</pre>
+<p>
+All UI files must begin with a <b>reset-server</b> command to initialize
+the OBM. An <b>appInitialize</b> call is then made to define all of the
+widgets and resources used in the interface, initializing the interface
+used by the application. The <b>createObjects</b> function then actually
+creates the widgets in the server, more specifically it creates the widgets
+defined by the named <i>objects</i> resource. Lastly, the <b>activate</b>
+call is used to activate the interface, i.e. put it on the screen.
+
+<p>
+<a name="4.1"></a>
+<h3>4.1 Example</h3>
+A complete "hello, world" GUI definition might look something like:
+<pre>
+ 1) <b>reset-server</b>
+ 2) <b>appInitialize</b> <i>hello Hello</i> {
+ 3) *objects:\
+ 4) toplevel Form helloForm\
+ 5) helloForm Label helloLabel\
+ 6) helloForm Command quitButton
+ 7)
+ 8) *background: gray
+ 9) *helloLabel.label: Hello, world!
+ 10) *quitButton.fromHoriz: helloLabel
+ 11) *quitButton.label: Quit
+ 12) }
+ 13)
+ 14) <b>createObjects</b>
+ 15) <b>activate</b>
+ 16)
+ 17) <b>proc</b> Quit <b>args</b> {
+ 18) <b>send client gkey</b> q
+ 19) <b>deactivate unmap</b>
+ 20) } ; <b>send</b> quitButton <b>addCallback</b> Quit
+</pre>
+
+where a line-by-line analysis of the GUI shows:
+
+<dl>
+<dt>Line 1: <dd>- The <b>reset-server</b> command must be the first line in
+the UI file since it's primary purpose is to initialize the OBM (i.e. a
+call to the <i>ObmInitialize()</i> procedure). Subsequent calls (in the
+same UI file or a different UI) are effectively a no-op.
+<dt>Lines 2-12: <dd>- The <b>appInitialize</b> command defines the widgets
+and resources to be used in the interface. The first argument gives the
+name of the application, the second argument is the application class name
+for purposes of specifying resources in the environment, and the last
+argument is a Tcl list (hence the braces) of resources for the application.
+<p>
+The primary purpose of the call is to initialize the X11 part of the system
+by defining the application context and the list of fallback resources. The
+<i>objects</i> resource is a required element listing the widget hierarchy
+to be used. Remaining resources are used to specify labels, colors, layout,
+etc and serve as an app-defaults file for the GUI, interacting with the
+normal resource database in the usual way. For example, a user's .Xdefaults
+file may specify a "<b>font</b>" resource, unless this is overridden in
+some way in the UI file this is the font that will be used. Resources may
+be specified with either "loose" (i.e. the '*') or "tight" (i.e. the '.')
+bindings with as much detail as is needed.
+<dt>Line 14: <dd>- The <b>createObjects</b> command is what actually calls
+each widget's Initialize() method to create the widget in the application
+and in the X11 server.
+<p>
+With no argument, the default value used is simply
+the <b>objects</b> resource. However, it's possible to specify a named
+argument and make repeated calls to <b>createObjects</b> to build any number
+widget trees prior to activating the interface. This can be useful for
+example to specify a "main_objects" resource contains all the widgets for
+the main panel, and a "help_objects" specfiying widgets used for the UI
+help panel, which makes the definition file easier to organize. In the
+past however UI files were written with a single long list (easily many
+hundreds of lines) of objects followed by an even longer list of their
+resources under a single <b>appInitialize</b> call, creating a monolithic
+and unmanageably GUI definition file. Later on we'll see how complex GUIs
+can be divided into separate pieces making it easier to reuse code and
+manage the interface more efficiently.
+<dt>Line 15: <dd>- The <b>activate</b> command is what creates the interface
+on the screen, i.e. it calls the Realize() method for each widget to
+instantiate it in the server and draw the window.
+<dt>Lines 17-19: <dd>- Lastly we have the user-defined callback procedures.
+On line 17 we define a procedure <i>Quit</i> which we use to shut down the
+interface and client application. The body of the procedure first sends the
+client object the graphics keystroke 'q' to shut down the client, then calls
+the <b>deactivate</b> command to close the interface. On the last line
+we send a message to the <i>quitButton</i> widget telling it to add this
+procedure to it's callback list, so when the Button is selected this
+procedure will be called as a result.
+</dl>
+<p>
+<hr noshade=6>
+
+<a name="5"></a>
+<h3>5. Widget Toolkit</h3>
+<p>
+<p>
+<hr noshade=6>
+
+<a name="6"></a>
+<h3>5. Object Classes</h3>
+<p>
+The following OBM object classes are currently defined:
+<pre>
+ <a href="#6.1">Client</a> The Client application
+ <a href="#6.2">Server</a> The OBM itself
+ <a href="#6.3">Gterm</a> Gterm graphics/imaging widget class
+ <a href="#6.4">HTML</a> HTML widget class
+ <a href="#6.5">Markers</a> Gterm markers class
+ <a href="#6.6">Widget</a> General widget class
+ <a href="#6.7">Parameter</a> UI Parameter class
+<p>
+ Various Xt and Athena widgets
+ <i>{box, shell, label, command, text, list, etc.}</i>
+ Misc Other X11 Widgets
+ <i>{Layout, Tabs, ListTree, etc}</i>
+</pre>
+<p>
+OBM client applications will upload a UI during initialization to define a
+custom graphics user interface. This is done by sending a message to the
+object manager. Non-GUI applications assume a simple graphics
+terminal and do not upload a UI; instead, a default UI is created
+for the application consisting of a single top level shell containing a
+Gterm (Tek 4012 graphics/imaging) widget.
+<p>
+
+<hr noshade=5>
+
+<a name="5.1"></a>
+<h3>5.1 Client</h3>
+<p>
+The client is the client application, which provides the functionality
+underlying the UI. When a message is sent to the client object it usually
+results in a message being sent to the client *application*, usually an
+external program communicating via IPC, which has little or no knowledge
+of the UI. The client application receives and executes commands delivered
+by the UI via the client object. Output from the client may or may not
+come back to the object manager. That portion of the output which comes
+back to the object manager is in the form of assignments of string values
+to <a href="#5.7.html">UI Parameter class objects</a> (another way of thinking
+of this is that messages or events are sent to and acted upon by the parameter
+objects). Hence, the client object is output only so far as the client
+application is concerned.
+<p>
+The Client-class commands are used to send a message to the client.
+<p>
+<pre>
+ <a href="#gkey">gkey</a> &lt;key&gt;
+ <a href="#gcmd">gcmd</a> &lt;command-string&gt;
+ <a href="#literal">literal</a> &lt;command&gt;
+</pre>
+<p>
+or just &lt;command&gt;, e.g., "send client &lt;command&gt;" will work in most cases.
+<p>
+<a href="#gkey">GKEY</a> sends an IRAF graphics keystroke.
+<a href="#gcmd">GCMD</a> sends an
+IRAF graphics colon command. <a href="#literal">LITERAL</a> sends a literal
+command string to the
+client. The keyword "literal" may optionally be omitted, i.e., "send client
+foo" and "send client literal foo" are the same. The keyword "literal" may
+be used to ensure that the client command string which follows will not
+be interpreted as a Client-class command (such as gkey, gcmd, or literal).
+<p>
+<a name="5.1.1"></a>
+<h2>5.1.1 Command Summary</h2>
+<p>
+<h3><A NAME="gcmd">gcmd</A></h3>
+<p>
+Send a graphics command string to the client application.
+A graphics command string is a graphics cursor value with the key set
+to `:' and the command string given as the string part of the cursor
+value. The protocol module which posted the client output procedure is
+responsible for encoding and sending the cursor command.
+<p>
+Usage:
+<p>
+<pre>
+ gcmd &lt;command-string&gt;
+</pre>
+<p>
+<h3><A NAME="gkey">gkey</A></h3>
+<p>
+Send a graphics key event to the client application.
+A graphics key event is a graphics cursor value with the key set to some
+integer value and a null string part.
+<p>
+Usage:
+<p>
+<pre>
+gkey &lt;key&gt;
+</pre>
+<p>
+<h3><A NAME="literal">literal</A></h3>
+<p>
+Send a literal command to the client application.
+<p>
+Usage:
+<p>
+<pre>
+ literal &lt;command&gt;
+</pre>
+
+<hr noshade=5>
+
+<a name="6.2"></a>
+<h3>6.2 Server</h3>
+<p>
+The server, or object manager, is the control center of the user interface.
+The server object provides a Tcl interpreter calling custom object manager
+commands. These are used to define and initialize the user interface, and
+execute UI action procedures at runtime.
+<p>
+<pre>
+ <a href="#resetReset">reset-server</a>
+ <a href="#appInitialize">appInitialize</a> appname,appclass,resources
+ <a href="#createObjects">createObjects</a> [resource-name]
+ <a href="#destroyObject">destroyObject</a> object
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a> [unmap]
+<p>
+ value = <a href="#getResource">getResource</a> resource-name [default-value [class]]</a>
+ <a href="#getResources">getResources</a> resource-list
+<p>
+ <a href="#createMenu">createMenu</a> menu-name parent item-list
+ <a href="#createMenu">editMenu</a> menu-name parent item-list
+ <a href="#destroyMenu">destroyMenu</a> menu-name
+<p>
+ <a href="#createBitmap">createBitmap</a> name width height data
+ <a href="#createCursor">createCursor</a> name source mask fg_color bg_color x_hot y_hot
+ <a href="#createPixmap">createPixmap</a> name width height depth fg_color bg_color data
+<p>
+ <a href="#print">print</a> arg [arg ...] # debug messages
+ <a href="#send">send</a> object message
+<p>
+ <a href="#postActivateCallback">postActivateCallback</a> procedure
+id = <a href="#postTimedCallback">postTimedCallback</a> procedure msec [client-data]
+ <a href="#deleteTimedCallback">deleteTimedCallback</a> id
+ id = <a href="#postWorkCallback">postWorkCallback</a> procedure [client-data]
+ <a href="#deleteWorkCallback">deleteWorkCallback</a> id
+</pre>
+
+<a name="6.2.1"></a>
+<h2>6.2.1 Command Summary</h2>
+<p>
+<h3><A NAME="serverReset">serverReset</A></h3>
+<p>
+The "reset-server" command is implemented as a special case in ServerEvaluate.
+After doing a true reset ServerEvaluate calls Tcl_Eval to evaluate the full
+message which still contains the reset-server command. We want to ignore
+this the second time, so we treat the command here as a no-op.
+<p>
+Usage:
+<p>
+<pre>
+ reset-server
+</pre>
+<p>
+Note: for reset-server to be recognized by ServerEvaluate and really reset
+things, it must be the first command in a message to the server.
+<p>
+<h3><A NAME="appInitialize>appInitialize</A></h3>
+<p>
+TCL command to initialize the server for a new application, setting the
+application name and loading the application resources.
+<p>
+Usage:
+<p>
+<pre>
+ appInitialize appname, appclass, resources
+</pre>
+<p>
+<h3><A NAME ="createObjects">createObjects</A></h3>
+<p>
+TCL command to create the tree of UI objects comprising the user interface.
+The object tree is defined by a string valued resource. If no resource is
+named the default "objects" resource will be used.
+<p>
+Usage:
+<p>
+<pre>
+ createObjects [resource-name]
+</pre>
+<h3><A NAME="destroyObject">destroyObject</A></h3>
+<p>
+Destroy an object and all of its children.
+<p>
+Usage:
+<pre>
+ destroyObject object-name
+</pre>
+<p>
+<h3><A NAME="activate">activate</A></h3>
+Activate the user interface. When called the first time the user interface
+is created and activated, thereafter the UI is merely reactivated (e.g.
+mapped if unmapped).
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h3><A NAME="deactivate">deactivate</A></h3>
+<p>
+Deactivate the user interface. Optionally unmaps the UI and calls the Obm
+client back to let it know that the UI has been deactivated.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate [unmap]
+</pre>
+<p>
+<h3><A NAME="getResource">getResource</A></h3>
+<p>
+Get the string value of the specified application resource (window
+system parameter). This allows use of the resource mechanism to supply
+default values for GUI parameters.
+<p>
+Usage:
+<p>
+<pre>
+ value = getResource resource-name [class [default-value]]
+</pre>
+<p>
+In the simplest case one merely requests a resource by name and the
+string value is returned as the function value. If the resource has
+an entry in the fallback resources for the application (appInitialize
+resource list) then a value is guaranteed to be returned.
+<p>
+If the Class name for the resource is given then a class default value
+will be returned if no entry is found for the name resource instance. This
+is useful when there are a number of resources of the same type (same class).
+If most or all resources in the same class have the same default value one
+need only make one entry for the Class in the application defaults resource
+list. It is up to the application developer to define the class name of a
+resource - the class name can be any string. Examples are "Font", "Cursor",
+etc. By convention the first character of a class name is capitalized, while
+instance names begin with a lower case letter.
+<p>
+If there is an entry for the named resource in the resource list passed to
+appInitialize then a value string is guaranteed to be returned. This will be
+either the appInitialize default, or a value specified by the system or the
+user in an X resources file. If one is not certain a default value is defined
+somewhere, a default value should be specified in the getResource call as
+shown above.
+<p>
+See also getResources, used to get multiple resources in one call.
+<p>
+<h3><A NAME="getResources">getResources</A></h3>
+<p>
+Get the string values of a list of resources.
+<p>
+Usage:
+<p>
+<pre>
+ getResources resource-list
+</pre>
+<p>
+e.g.
+<pre>
+ getResources {
+ { resource [variable class [default-value]]] }
+ { resource [variable class [default-value]]] }
+ (etc.)
+ }
+</pre>
+<p>
+<h3><A NAME="createMenu">createMenu, editMenu</A></h3>
+<p>
+Create or modify a menu. The editMenu function is an alias for createMenu.
+<p>
+Usage:
+<pre>
+ createMenu menu-name parent item-list
+</pre>
+<p>
+e.g.,
+<pre>
+ createMenu menu-name parent {
+ { label function data [options...] }
+ { label function data [options...] }
+ (etc.)
+ }
+</pre>
+<p>
+where
+<p>
+<pre>
+ menu-name is the object name for the menu popup shell
+ parent is the parent widget of the menu shell
+ label is a menu item label
+ function is the function to be performed when the menu
+ item is selected, e.g., f.exec, f.data, f.space, or f.line.
+ data is function dependent data
+ options are option-name option-value pairs, as specified
+ below.
+</pre>
+<p>
+In the item list the fields label and option-value may be any Tcl expression.
+Expressions are evaluated in the server context. The data field is a Tcl
+script to be executed when the menu item is selected.
+<p>
+Options are specified as "option option-value". The menu item options are
+as follows.
+<p>
+<pre>
+ bitmap A bitmap to be displayed left justified in the label field
+ (e.g. to indicate a parameter setting).
+ sensitive Specifies whether the menu item is active (sensitive=true)
+ or inactive (sensitive=false, item grayed out).
+ accelerator Specifies an input translation (accelerator, e.g.,
+ keyboard event) which can be used to execute the
+ menu item.
+</pre>
+<p>
+The option-value field may be any Tcl expression.
+<p>
+Example:
+<p>
+<pre>
+ createMenu fileMenu toplevel {
+ { "File Menu" f.title}
+ { Open f.exec openFile}
+ { Save f.exec saveFile}
+ { Load f.menu loadMenu}
+ { no-label f.line }
+ { Quit f.exec "send client Quit" }
+ }
+</pre>
+<p>
+The first createMenu is called for a given menu the menu is created, added
+to the menu list, and all window system widgets are created for the menu.
+Subsequent calls will result in only the changed parts of the menu being
+altered provided the changes are not great. Hence this routine can be called
+to efficiently modify a menu when minor runtime changes occur, e.g., an
+item label or action changes, the item value changes state, and so on,
+without need for the GUI code to know how to make the necessary detailed
+changes to the widgets used to implement the menu.
+<p>
+<h3><A NAME="destroyMenu">destroyMenu</A></h3>
+<p>
+Destroy a menu. This can be used to free up the resources used by a
+menu, e.g., if the menu is not expected to be needed again for a while.
+<p>
+Usage:
+<p>
+<pre>
+ destroyMenu menu-name
+</pre>
+<p>
+<h3><A NAME="createBitmap">createBitmap</A></h3>
+<p>
+Create a named bitmap. This replaces any old bitmap of the same name. The
+new bitmap is cached in server memory; when a widget bitmap resource is set,
+the bitmap cache will be searched for the named bitmap before asking Xlib
+to find the bitmap.
+<p>
+Usage:
+<p>
+<pre>
+ createBitmap name width height data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createBitmap foo 16 16 {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+<p>
+<h3><A NAME="createCursor">createCursor</A></h3>
+<p>
+Create a cursor from bitmap data. The cursor is entered into the server's
+cursor cache and will override any existing entry of the same name.
+<p>
+Usage:
+<p>
+<pre>
+ createCursor name source mask fg_color bg_color x_hot y_hot
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createCursor foo bitmap1 bitmap2 black white 8 8
+</pre>
+<p>
+The named bitmaps must be created first with createBitmap.
+<p>
+<h3><A NAME="createPixmap">createPixmap</A></h3>
+<p>
+Create a named pixmap. This replaces any old pixmap of the same name. The
+new pixmap is cached in server memory; when a widget pixmap resource is set,
+the pixmap cache will be searched for the named pixmap before asking Xlib
+to find the pixmap.
+<p>
+Usage:
+<p>
+<pre>
+ createPixmap name width height depth fg_color bg_color data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createPixmap foo 16 16 8 black white {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+</pre>
+<p>
+<h3><A NAME="print">print</A></h3>
+<p>
+Print a string on the standard output. This is used mainly for debugging
+user interfaces.
+<p>
+Usage:
+<p>
+<pre>
+ print arg [arg ...]
+</pre>
+<p>
+<h3><A NAME="send">send</A></h3>
+<p>
+Send a message to an object. The object interprets the message and returns
+a function value as the string result of the TCL command.
+<p>
+Usage
+<p>
+<pre>
+ send &lt;object&gt; &lt;message&gt;
+</pre>
+<p>
+<h3><A NAME="postActivateCallback">postActivateCallback</A></h3>
+<p>
+Post a callback procedure to be called when the UI is activated. The UI is
+activated when it is first downloaded to server, but it may also be
+activated (reactivated) after the application has exited and is later
+restarted, or when the UI is deactivated and reactivated. Note
+that the UI state vis-a-vis the external world (client application) may
+no longer be accurate after it has been idle for a time and then reactivated.
+<p>
+Usage:
+<p>
+<pre>
+ postActivateCallback &lt;procedure&gt;
+</pre>
+<p>
+<p>
+<h3><A NAME="postTimedCallback">postTimedCallback</A></h3>
+<p>
+Post a callback to call the named procedure back after a specified delay
+in milliseconds.
+<p>
+Usage:
+<p>
+<pre>
+ id = postTimedCallback procedure msec [client-data]
+</pre>
+<p>
+After the specified delay the user callback procedure will be called with
+client_data (if given) as the single argument. Only one call will be made;
+the client must repost the callback in each call if the procedure is to be
+repeatedly executed.
+<p>
+An ID value is returned which may be passed to deleteTimedCallback to delete
+the timer.
+<p>
+<h3><A NAME="deleteTimedCallback">deleteTimedCallback</A></h3>
+<p>
+Delete a timer callback procedure. This procedure is typically used to
+break a timer loop, where the timer procedure repeatedly reposts itself at
+the end of each interval.
+<p>
+Usage:
+<p>
+<pre>
+ deleteTimedCallback id
+</pre>
+<p>
+The ID string is returned by postTimedCallback when a timer is posted.
+<p>
+<h3><A NAME="postWorkCallback">postWorkCallback</A></h3>
+<p>
+Post a callback for a procedure to be called when the server is idle.
+Work procedures are used to perform computations in the background while
+the user interface remains active and able to respond to input events.
+This works only if the user work procedure does its job in small increments,
+doing only a small amount of processing in each call. The work procedure
+will be called repeatedly until it returns a status indicating that it has
+finished its task.
+<p>
+Usage:
+<p>
+<pre>
+ id = postWorkCallback procedure [client-data]
+</pre>
+<p>
+When the server has nothing else to do the user work procedure will be
+called with client_data (if given) as the single argument. The work procedure
+should return the string "done" when all processing is finished, or any other
+string if the procedure is to be called again.
+<p>
+An ID value is returned which may be passed to deleteWorkCallback to delete
+the work procedure.
+<p>
+<h3><A NAME="deleteWorkCallback">deleteWorkCallback</A></h3>
+<p>
+Delete a work callback procedure.
+<p>
+Usage:
+<p>
+<pre>
+ deleteWorkCallback id
+</pre>
+<p>
+The ID string is returned by postWorkCallback when a work procedure is posted.
+
+<hr noshade=5>
+
+<a name="6.3"></a>
+<h3>6.3 Gterm</h3>
+<p>
+The gterm-image widget is a general 2D graphics-imaging widget providing
+a wide range of facilities for drawing graphics and text, for image
+display, and for graphics interaction. Normally the client communicates
+directly with the Gterm widget to draw graphics, download image data,
+and so on, using some communications protocol outside the domain of the
+object manager. Nonetheless so far as possible the facilities of the Gterm
+widget have also been made available to GUI code via the commands listed
+here.
+<p>
+The Gterm widget adds the following function to the OBM library.
+<p>
+<pre>
+ ObmPostSetGtermCallback (obm, &setgterm, setgterm_client_data)
+</pre>
+<p>
+This is called by a client application to post a procedure to be called
+when a gterm widget receives the setGterm command. The calling sequence
+for setGterm callback is as follows:
+<p>
+<pre>
+ setgterm (client_data, gterm_widget)
+</pre>
+<p>
+The purpose of this callback is to tell the client which gterm widget is
+the "active" gterm widget. This is used by clients which only support
+one active Gterm widget, i.e., which can only direct graphics output to
+one Gterm widget at a time.
+<p>
+The messages or commands that can be sent to the Gterm widget by GUI
+code follow.
+<p>
+General commands:
+<p>
+<pre>
+ <a href="#setGterm">setGterm</a> # make widget the active Gterm
+<p>
+ <a href="#activate">activate</a>
+ <a href="#deactivate">deactivate</a>
+ <a href="#addCallback">addCallback</a> procedure-name callback-type
+ <a href="#reset">reset</a>
+ <a href="#flush">flush</a>
+<p>
+ <a href="#setCursorPos">setCursorPos</a> x y [raster]
+ <a href="#getCursorPos">getCursorPos</a> x y
+ <a href="#setCursorType">setCursorType</a> cursortype
+ <a href="#bell">bell</a>
+</pre>
+<p>
+Graphics drawing commands:
+<p>
+<pre>
+ <a href="#setRaster">setRaster</a> raster
+ raster = <a href="#getRaster">getRaster</a> [raster]
+<p>
+ <a href="notyet.html">setLogRes</a> width height
+ <a href="notyet.html">getLogRes</a> width height
+ <a href="notyet.html">setPhysRes</a> width height
+ <a href="notyet.html">getPhysRes</a> width height
+ <a href="notyet.html">setTextRes</a> rows cols
+ <a href="notyet.html">setDataLevel</a> level
+ <a href="notyet.html">setLineWidth</a> width
+ <a href="notyet.html">setLineStyle</a> style
+ <a href="notyet.html">setColorIndex</a> index
+ <a href="notyet.html">setFillType</a> filltype
+<p>
+ <a href="#clearScreen">clearScreen</a>
+ <a href="notyet.html">drawPolyline</a> vector
+ <a href="notyet.html">drawPolymarker</a> vector
+ <a href="notyet.html">drawPolygon</a> vector
+ <a href="notyet.html">drawMarker</a> x y xsize ysize type
+<p>
+ <a href="notyet.html">drawAlphaText</a> x y text
+ <a href="notyet.html">getAlphaTextSize</a> string width height base
+ <a href="notyet.html">startDialog</a>
+ <a href="notyet.html">endDialog</a>
+ <a href="notyet.html">eraseDialog</a>
+ <a href="notyet.html">drawDialogText</a> x y text
+ <a href="notyet.html">getDialogTextSize</a> string width height base
+</pre>
+<p>
+The coordinates used in the graphics drawing commands are logical
+coordinates as defined by setLogRes, in the coordinate system of the
+reference drawing raster as defined by setRaster. The default reference
+raster is raster zero, the widget's window. Vectors are specified as
+a list of points, e.g., { {x y} {x y} ... }.
+<p>
+Imaging commands:
+<p>
+<pre>
+ <a href="#rasterInit">rasterInit</a>
+ <a href="notyet.html">assignRaster</a> raster drawable
+ <a href="notyet.html">createRaster</a> raster type width height depth
+ <a href="notyet.html">destroyRaster</a> raster
+ exists = <a href="notyet.html">queryRaster</a> raster type width height depth
+ raster = <a href="notyet.html">nextRaster</a> [raster]
+ nrasters = <a href="notyet.html">nRasters</a> [nrasters]
+<p>
+ <a href="#setPixel">setPixel</a> raster x y value
+ value = <a href="#getPixel">getPixel</a> raster x y
+ <a href="#writePixels">writePixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="#readPixels">readPixels</a> raster pixels encoding x1 y1 nx ny
+ <a href="notyet.html">refreshPixels</a> raster ct x1 y1 nx ny
+ pixmap = <a href="notyet.html">createPixmap</a> src x y width height
+ <a href="notyet.html">copyPixmap</a> pixmap dst x y width height
+<p>
+ colormap = <a href="notyet.html">nextColormap</a> [colormap]
+ <a href="notyet.html">freeColormap</a> colormap
+ <a href="notyet.html">writeColormap</a> colormap first nelem colors
+ <a href="notyet.html">readColormap</a> colormap first nelem colors
+ <a href="#loadColormap">loadColormap</a> colormap offset scale
+<p>
+ <a href="notyet.html">initMappings</a>
+ mapping = <a href="#nextMapping">nextMapping</a> [mapping]
+ <a href="notyet.html">freeMapping</a> mapping
+ <a href="notyet.html">enableMapping</a> mapping
+ <a href="notyet.html">disableMapping</a> mapping
+ active = <a href="notyet.html">activeMapping</a> mapping
+ <a href="notyet.html">refreshMapping</a> mapping
+<p>
+ raster = <a href="#selectRaster">selectRaster</a> dras dt dx dy rt rx ry [map]
+ <a href="#unmapPixel">unmapPixel</a> sx sy raster rx ry [rz]
+<p>
+ <a href="notyet.html">copyRaster</a> rop src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#setMapping">setMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+ <a href="#getMapping">getMapping</a> mapping rop
+ src st sx sy snx sny dst dt dx dy dnx dny
+<p>
+ <a href="#flip">flip</a> mapping axis [axis...]
+</pre>
+<p>
+Pixel arrays are long strings consisting either of a sequence of numeric
+pixel values separated by whitespace (space or newline), or a hex encoded
+sequence of bytes (2 hex digits per 8 bit pixel). Colors are specified
+as a list of RGB triplets, e.g., { {R G B} {R G B} ... }.
+<p>
+Refer to the documentation for the Gterm widget for a detailed description
+of rasters, mappings, and colormaps.
+<p>
+Markers:
+<p>
+<pre>
+ <a href="#createMarker">createMarker</a> name [attribute-list]
+ <a href="#markerInit">markerInit</a>
+</pre>
+<p>
+New markers may be created with createMarker. Once created, a marker
+functions under the Object Manager as a named object of class "marker".
+Refer to the marker class for a description of the commands defined for
+a marker.
+<p>
+gterm Actions List
+<p>
+<pre>
+ ignore
+ graphics-input
+ graphics-context
+ crosshair
+ track-cursor
+ enter-window
+ leave-window
+ popup-menu {not implemented}
+ reset
+ m_create
+</pre>
+<p>
+Default translations for Gterm window.
+Omitted for now: Ctrl ~Meta <Btn3Down>: popup-menu(tekMenu)
+<p>
+default Gterm Translations
+<p>
+<pre>
+ [Btn1Down]:m_create()
+ [Btn2Down]:crosshair(on)
+ [Btn2Motion]:crosshair(on)
+ [Btn2Up]:crosshair(off)
+ ~Ctrl ~Meta [Btn3Down]:graphics-context()
+ [EnterWindow]:enter-window()
+ [LeaveWindow]:leave-window()
+ [KeyPress]:graphics-input()
+ [Motion]:track-cursor()
+</pre>
+<p>
+<p>
+<a name="6.3.1"></a>
+<h2>6.3.1 GTERM class commands</h2>
+<p>
+<h3><A NAME="setGterm">setGterm</A></h3>
+<p>
+Set the active Gterm widget. A UI can have more than one
+gterm widget, but due to restrictions on the client-server interface, it
+may be possible for only one to receive client output at any one time (any
+gterm widget can generate input to be sent to the client). If the client
+has this restriction, the client-server interface code which uses OBM can
+call the ObmPostSetGtermCallback procedure to post a function to be called
+when the UI code calls the setGterm procedure.
+<p>
+Usage:
+<p>
+<pre>
+ setGterm
+</pre>
+<p>
+<h3><A NAME="activate">activate</A></h3>
+<p>
+Activate the gterm widget. This causes the next GIN mode
+setCursorType to warp the pointer into the gterm window.
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h3><A NAME="deactivate">deactivate</A></h3>
+<p>
+Deactivate the gterm widget. If the cursor has been warped
+into the window by a previous activate/setCursorType GIN mode, this causes
+the cursor to be warped back to where it was previously.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate
+</pre>
+<p>
+<h3><A NAME="reset">reset</A></h3>
+<p>
+Reset the gterm widget. This causes a number of state variables
+affecting graphics drawing options to be set to their default values.
+<p>
+Usage:
+<p>
+<pre>
+ reset
+</pre>
+<p>
+<h3><A NAME="flush">flush</A></h3>
+<p>
+Flush any graphics output and synchronize the state of the widget
+with what is shown on the display.
+<p>
+Usage:
+<p>
+<pre>
+ flush
+</pre>
+<p>
+The gterm widget uses XLIB, which buffers graphics drawing commands and
+automatically sends them to the X server when 1) the buffer fills,
+2) input is requested from the server. Such buffering of data is necessary
+for efficient operation and it should rarely be necessary to explicitly
+flush graphics output since XLIB does this automatically in most cases.
+An example of when explicitly flushing the ouptut might be necessary is in
+cases where smooth animation is desired and drawing the graphics in batches
+could cause the display to appear "jerky".
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Post a callback for a Gterm widget event.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure-name [callback-type]
+</pre>
+<p>
+The recognized Gterm callbacks are
+<p>
+<pre>
+
+ input Called when the graphics-input action is invoked in
+ a translation table. The default Gterm translation
+ table invokes this action when a KeyPress event occurs
+ in the Gterm window.
+ Callback: widget-name input-type event-data
+
+ resize Called when the gterm window is resized.
+ Callback: widget-name width height
+
+ reset Called when the "reset" action is invoked.
+ Callback: widget-name
+
+</pre>
+<p>
+If no callback is specified the default is "input".
+<p>
+Note that in GUI code one can also use the translation table to directly
+invoke GUI procedures without need to use the Gterm input mechanism. This
+is more flexible but we support the Gterm input callback here for
+applications that use the default translations.
+<p>
+<h3><A NAME="setCursorPos">setCursorPos</A></h3>
+<p>
+Warp the cursor (pointer) to the given coordinates. This
+is a graphics drawing command and if no raster number is specified the
+current reference drawing raster, as set with setRaster, defines the
+coordinate system.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorPos x y [raster]
+</pre>
+<p>
+A raster number may optionally given to define the raster coordinate system
+to be used. raster=0 yields screen coordinates.
+<p>
+<h3><A NAME="getCursorPos">getCursorPos</A></h3>
+<p>
+Get the cursor position (raster 0 or screen coordinates).
+<p>
+Usage:
+<p>
+<pre>
+ getCursorPos x y
+</pre>
+<p>
+<h3><A NAME="setCursorType">setCursorType</A></h3>
+<p>
+Set the cursor type.
+<p>
+Usage:
+<p>
+<pre>
+ setCursorType cursor-type
+
+ idle default cursor
+ busy busy cursor, e.g, when program is busy
+ ginMode graphics input mode cursor, set when program is
+ waiting for graphics input
+</pre>
+<p>
+<h3><A NAME="bell">bell</A></h3>
+<p>
+Gterm widget sound output.
+<p>
+Usage:
+<p>
+<pre>
+ bell
+</pre>
+<p>
+<h3><A NAME="setRaster">setRaster</A></h3>
+<p>
+Set the number of the raster to be used to define the drawing
+context (e.g. coordinate system) for graphics and text drawing functions.
+<p>
+Usage:
+<p>
+<pre>
+ setRaster raster-number
+</pre>
+<p>
+<h3><A NAME="getRaster">getRaster</A></h3>
+<p>
+Get the number of the raster which defines the drawing
+context, as set in the last setRaster call.
+<p>
+Usage:
+<p>
+<pre>
+ raster = getRaster [raster]
+</pre>
+<p>
+If the name of a variable is given the raster number will be stored
+directly in that variable.
+<p>
+<h3><A NAME="clearScreen">clearScreen</A></h3>
+<p>
+Clear the "screen", i.e., window. This action clears the
+drawing window and sets a number of drawing state variables to their default
+values.
+<p>
+Usage:
+<p>
+<pre>
+ clearScreen
+</pre>
+<p>
+<h3><A NAME="rasterInit">rasterInit</A></h3>
+<p>
+Initialize the raster subsystem, deleting all rasters and
+mappings and freeing the dynamic part of the colortable.
+<p>
+Usage:
+<p>
+<pre>
+ rasterInit
+</pre>
+<p>
+<h3><A NAME="writePixels">writePixels</A></h3>
+<p>
+Set the values of some subset of the pixels in a raster.
+If any mappings are defined on the affected region and are enabled, any
+destination rasters will be automatically updated as defined by the mapping.
+<p>
+Usage:
+<p>
+<pre>
+ writePixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be written.
+</pre>
+<p>
+Most real-world image processing applications get the Gterm widget handle
+with setGterm and pass binary data to the widget by calling GtWritePixels
+directly. This is the most efficient approach for serious image processing
+where large amounts of data are involved. However, being able to read and
+write raster pixels directly in a GUI can be useful in specialized
+applications, e.g., where the image is computed or modified by the GUI.
+<p>
+<h3><A NAME="setPixel">setPixel</A></h3>
+<p>
+Set the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ setPixel raster x y value
+
+ raster The raster number.
+ x, y The pixel to be set.
+ value The pixel value.
+</pre>
+<p>
+This routine is more efficient than writePixels for setting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be set.
+<p>
+<h3><A NAME="readPixels">readPixels</A></h3>
+<p>
+Get the values of some subset of the pixels in a raster.
+<p>
+Usage:
+<p>
+<pre>
+ readPixels raster pixels encoding nbits x1 y1 nx ny
+
+ raster The raster number.
+ pixels The pixel array, encoded as a string.
+ encoding The pixel encoding. "numeric" means each pixel is
+ encoded as a decimal integer delimited by whitespace.
+ "hex" means the pixel array is hex encoded, 2 bytes
+ per 8 bit pixel, as a printable text string. The
+ two bytes are defined as follows (v = pixel value):
+
+ byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ byte2 = ((v ) & 017) in hex [0-9A-F]
+
+ Whitespace in a hex encoded string is ignored.
+ Hex encoding reduces the data volume by about a factor
+ of two (compared to numeric) and is only a factor of
+ two less space efficient than binary.
+
+ nbits Number of bits per pixel - currently only 8 bit pixels
+ are supported.
+
+ x1,y1,nx,ny Region of the raster to be read.
+</pre>
+<p>
+Use readPixels to read a block of pixels, and getPixel to get the value
+of a single pixel.
+<p>
+<h3><A NAME="getPixel">getPixel</A></h3>
+<p>
+Get the value of a single pixel.
+<p>
+Usage:
+<p>
+<pre>
+ getPixel raster x y
+
+ raster The raster number.
+ x, y The pixel to be set.
+</pre>
+<p>
+This routine is more efficient than readPixels for getting the value of
+a single pixel, but is a lot less efficient if a block of pixels are to
+be read.
+<p>
+<h3><A NAME="nextMapping">nextMapping</A></h3>
+<p>
+Return the index of the next unused mapping.
+<p>
+Usage:
+<p>
+<pre>
+ nextMapping
+</pre>
+<p>
+Returns the mapping number as the function value.
+<p>
+<h3><A NAME="getMapping">getMapping</A></h3>
+<p>
+Get a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters except the mapping number are output parameters.
+<p>
+<h3><A NAME="setMapping">setMapping</A></h3>
+<p>
+Set a mapping.
+<p>
+Usage:
+<p>
+<pre>
+ setMapping mapping rop src st sx sy snx sny dst dt dx dy dnx dny
+</pre>
+<p>
+All parameters are input parameters.
+<p>
+<h3><A NAME="loadColormap">loadColormap</A></h3>
+<p>
+Load a colormap.
+<p>
+Usage:
+<p>
+<pre>
+ loadColormap colormap [offset [scale]]
+</pre>
+<p>
+The offset and scale parameters may be used to adjust the brightness and
+contrast of the image when the colormap is loaded. The normalized colormap
+has offset=0.5, scale=1.0. Colormap zero is the hardware colormap.
+<p>
+<h3><A NAME="selectRaster">selectRaster</A></h3>
+<p>
+Given the raw screen coordinates SX,SY (or coords in
+any destination raster), determine the mapping and source raster which are
+mapped to that pixel and return the raster and mapping numbers and the
+coordinates of the same pixel in the source raster.
+<p>
+Usage:
+<p>
+<pre>
+ raster = selectRaster dras dt dx dy rt rx ry [map]
+</pre>
+<p>
+where
+<p>
+<pre>
+ dras display raster
+ dt,rt coordinate type - "pixel" or "ndc"
+ dx,dy display raster coordinates (input)
+ rx,ry source raster coordinates (output)
+ map mapping selected (output)
+</pre>
+<p>
+Note that the coordinates returned by selectRaster are measured (taking
+a line as an example) from zero at the left edge of the first pixel, to
+"width" at the right edge of the last pixel. This means that the floating
+point coordinates of the center of raster pixel N will be N + 0.5. For
+example, if we input screen coordinates (dras=0), x=117, and no mapping
+is in effect, the floating point raster coordinates returned will be 117.5.
+The difference occurs because the input coordinate is a pixel number
+(integer) while the output coordinate is a floating point coordinate
+measuring the continuously variable location a pixel. int(x) will convert
+this coordinate to a raster pixel number.
+<p>
+<h3><A NAME="unmapPixel">unmapPixel</A></h3>
+<p>
+unmapPixel is a simplified, less general version of
+selectRaster which will automatically follow graphics pipelines back to
+the original mapped raster. If desired the raster pixel value can be
+returned as well as the raster number and raster pixel coordinates
+corresponding to a screen (raster 0) pixel.
+<p>
+Usage:
+<p>
+<pre>
+ unmapPixel sx sy raster rx ry [rz]
+</pre>
+<p>
+where
+<p>
+<pre>
+ sx,sy "screen" (raster 0) coordinates
+ raster original mapped raster (output)
+ rx,ry source raster coordinates (output)
+ rz source raster pixel value (output)
+<pre>
+<p>
+By following graphics pipelines back to the original source raster we mean
+the following. If raster A is mapped to raster B which is mapped to C (the
+screen), given a screen coordinate in the mapped region unmapPixel will
+return the raster number and coordinates for raster A.
+<p>
+<h3><A NAME="flip">flip</A></h3>
+<p>
+Edit a mapping to flip the mapped subimage in X and/or Y.
+<p>
+Usage:
+<p>
+<pre>
+ flip mapping axis [axis]
+</pre>
+<p>
+where axis is "x" or "y". This is a convenience routine for changing only
+the flip portion of a mapping.
+<p>
+<h3><A NAME="markerInit">markerInit</A></h3>
+<p>
+Initialize the Marker subsystem for a Gterm widget.
+This destroys all markers and initializes the marker subsystem.
+<p>
+Usage:
+<p>
+<pre>
+ markerInit
+</pre>
+<p>
+<h3><A NAME="createMarker">createMarker</A></h3>
+<p>
+Create a new marker.
+<p>
+Usage:
+<p>
+<pre>
+ createMarker name attribute-list
+ e.g. createMarker name {attribute value [attribute value ...]}
+ or createMarker name attribute value [attribute value ...]
+<pre>
+<p>
+Any marker attribute may be assigned a value when the marker is created.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker attribute names. Often the
+the attributes "type" and "createMode" need to be specified at marker
+create time.
+<p>
+<pre>
+ type The marker type: text, rectangle, circle, etc.
+
+ createMode A marker should be created with createMode=interactive
+ if the user is expected to interactively drag out
+ the marker using the pointer and either the default
+ or an application specified translation table. A
+ marker can also be created interactively using only
+ the m_create (marker create) action, however m_create
+ does not allow the marker attributes to be set.
+<pre>
+<p>
+There are any number of ways to use a GUI to create a marker under the
+Object Manager, but an example might be using a translation to call a GUI
+procedure which issues the createMarker call. For example a pointer down
+event could translate as "call(newMarker,$name,$x,$y) m_create()" where
+newMarker is a GUI marker creation procedure which sends a createMarker
+message to the Gterm widget. The GUI procedure could set the marker
+attributes as desired, possibly using additional GUI components to define
+the marker attributes. The m_create action will notice that a
+createMarker has been executed and will merely activate the marker and
+give it the pointer focus (i.e. install the marker translations). The
+user will then use the pointer or keyboard to drag out the marker.
+<p>
+If the marker is created noninteractive the application must set the marker
+position and size using marker attributes. If the marker is sensitive
+the user can then use the marker's translations to interactively modify
+the marker (resize it, move it, etc.). All markers which are visible and
+sensitive and which have the necessary translations can be interactively
+modified by the user; the reason for creating a marker in interactive mode
+is to allow the initial marker position and size to be specified
+interactively *when* the marker is created, instead of afterwards.
+<p>
+Any number of attributes may be given when the marker is created. Most
+marker attributes can also be modified after a marker has been created
+by sending setAttribute messages to the marker.
+
+<hr noshade=5>
+
+<a name="6.4"></a>
+<h3>6.4 HTML</h3>
+
+The HTML (hypertext markup language) widget displays a block of HTML
+formatted text, the "document" to be displayed. The text consists of a
+mixture of text to be displayed and embedded formatting directives. The
+text may also contain "hot links" pointing to other HTML-formatted
+documents.
+
+<pre>
+ setText text [target [header_text [footer_text]]]
+ text = getText [format [font]]
+ retestAnchors
+
+ id = positionToId x y
+ idToPosition id x y
+ anchorToPosition name x y
+ id = anchorToId name
+ gotoId id
+
+ n = getHRefs list
+ n = getImageSrcs list
+ n = getLinks list
+
+ setSelection start end
+ text = getSelection start end
+ clearSelection
+
+ searchText pattern start end [direction [search_type]]
+
+ addCallback procedure-name [callback-type]
+ deleteCallback procedure-name [callback-type]
+</pre>
+
+The possible callback types and their callback arguments are as follows.
+
+<pre>
+ anchor widget cbtype event text href element_id
+ testAnchor widget cbtype href
+ submitForm widget cbtype event attrs href method enctype encentity
+ link widget cbtype href role
+ pointerMotion widget cbtype href
+</pre>
+
+See the comments below for further details on the callback types and their
+arguments.
+
+<p>
+<a name="6.4.1"></a>
+<h2>6.4.1 Command Summary</h2>
+<p>
+
+<hr noshade=5>
+
+<a name="6.5"></a>
+<h3>6.5 Markers</h3>
+<p>
+A marker is a graphics object implemented by the Gterm-Image widget.
+Markers are not real toolkit widgets, but they act much like widgets and
+are interfaced as an object class under the Object Manager. The Marker
+class is not a subclass, it is a base class like Widget, but Marker objects
+can exist only as children of Gterm widgets.
+<p>
+Since markers are not independent widgets but rather part of a Gterm widget
+instance, the parent Gterm widget is partially responsible for managing
+markers. The Gterm widget implements the following commands for dealing
+with markers.
+<p>
+<pre>
+ <a href="gtermclass.html#createMarker">createMarker</a> name [attribute-list]
+ <a href="gtermclass.html#markerInit">markerInit</a>
+</pre>
+<p>
+A new marker is created by sending the createMarker message to the parent
+gterm widget. This creates a marker of the given name and type.
+The markerInit command, if sent to a gterm widget, destroys any markers
+defined for that widget and reinitializes the marker facility. Markers
+may also be created by action procedures in response to user input events.
+<p>
+A marker may be destroyed by itself in response to an input event (e.g. the
+user presses the delete key), by sending the marker the destroy message
+to tell it to destroy itself, by sending a markerInit to the parent gterm
+widget, or by destroying the marker object (or any parent) with the server
+command <a href="#destroyObject">destroyObject</a>.
+<p>
+Once a marker has been created it behaves as an independent object and
+receives and executes messages, responds to events, generates callbacks,
+and so on. The marker class defines the following commands.
+<p>
+<pre>
+ <a href="#makeCopy">makeCopy</a> name
+ <a href="#addCallback">addCallback</a> procedure [event [event ...]]
+ <a href="#notify">notify</a> [event-type [param [param ...]]]
+ <a href="#destroy">destroy</a> [nocallback]
+<p>
+ <a href="#markpos">markpos</a>
+ <a href="#redraw">redraw</a> [function] [markpos|nomarkpos] [erase|noerase]
+<p>
+ <a href="#raise">raise</a> [reference-marker]
+ <a href="#lower">lower</a> [reference-marker]
+<p>
+ <a href="#move">move</a> x y
+ <a href="#resize">resize</a> width height
+ <a href="#rotate">rotate</a> angle # radians
+<p>
+ <a href="#setAttribute">set</a> attribute value # alias for setAttribute
+ value = <a href="#getAttribute">get</a> attribute # alias for getAttribute
+<p>
+ <a href="#setAttribute">setAttribute</a> attribute value
+ value = <a href="#getAttribute">getAttribute</a> attribute
+ <a href="#setAttributes">setAttributes</a> attribute-list
+ <a href="#getAttributes">getAttributes</a> attribute-list
+ <a href="#setVertices">setVertices</a> points first npts
+ <a href="#getVertices">getVertices</a> points first npts
+<p>
+ region = <a href="#getRegion">getRegion</a> [unmap] [coord-type]
+ <a href="#getRect">getRect</a> dx dy dnx dny
+</pre>
+<p>
+Marker positions and dimensions are given in window (raster 0) coordinates.
+<p>
+The operators raise, lower, move, resize, and rotate erase the marker,
+modify it as indicated, and redraw it with the new attributes. For finer
+control over marker attributes one can use [get|set]Attribute[s] and
+[get|set]Vertices to edit the markers directly. In this case an auto
+redraw is not performed (unless the autoRedraw marker attribute is set).
+The usual sequence is a markpos to record the marker position, one or more
+setAttribute calls to change marker attributes, then a redraw to erase
+the old marker and redraw the new one. Markers have many attributes which
+can be set to control things like the position and size, colors, line
+widths, fill type and style, font, rubber-band technique, and so on.
+Refer to &lt;ObmW/Gterm.h&gt; for a list of marker types and attributes.
+<p>
+The marker type may be changed at runtime without destroying the marker.
+For example a circle can be changed to an ellipse or a rectangle. This
+also works for polygons (the vertex list is preserved and restored when
+the marker is changed back to a polygon).
+<p>
+The current shape of a marker may be queried with getVertices, which
+returns the polygon or polyline vertex list in window coordinates. A more
+powerful routine which does something similar is getRegion. This routine
+returns a high level description of the region outlined by the marker,
+giving the marker type (rectangle, circle, ellipse etc.), center, width
+and height, and so on. Any position or dimension information may
+optionally be transformed back to the original source raster, if the marker
+center is in a region of the window which is the destination of an active
+mapping. The unmap option will follow multiple mappings back to the
+original mapped source raster.
+<p>
+The getRect function returns the parameters of the region outlined by a
+rectangle marker in a form convenient for use in a Gterm setMapping call
+(this is used to display an image within a marker).
+<p>
+Default translations when pointer is over a marker.
+default Marker Translations
+<p>
+<pre>
+ Shift &lt;Btn1Motion&gt; m_rotateResize()
+ &lt;Btn1Motion&gt; m_moveResize()
+ Shift &lt;Btn1Down&gt; m_raise() m_markpos()
+ &lt;Btn1Down&gt; m_raise() m_markposAdd()
+ &lt;Btn1Up&gt; m_redraw() m_destroyNull()
+ &lt;Btn2Down&gt; m_lower()
+ &lt;Key&gt; BackSpace m_deleteDestroy()
+ &lt;Key&gt; Delete m_deleteDestroy()
+ &lt;KeyPress&gt; m_input()
+ &lt;Motion&gt; track-cursor()
+</pre>
+<p>
+<a name="6.5.1"></a>
+<h2>6.5.1 Command Summary</h2>
+<p>
+<h3>makeCopy</A></h3>
+<p>
+Copy a marker. The new marker is initially identical to the
+old one, and will not be distinct until, e.g., moved to a new center.
+<p>
+Usage:
+<p>
+<pre>
+ makeCopy name
+</pre>
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Post a marker callback to be called when the specified
+event or events occurs. If no events are listed a Notify callback will
+be posted.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback procedure [event [event ...]]
+</pre>
+<p>
+<h3><A NAME="notify">notify</A></h3>
+<p>
+Generate a Marker pseudo-event, causing any posted client
+callback procedures to be called.
+<p>
+Usage:
+<p>
+<pre>
+ notify [event-type [param [param ...]]]
+</pre>
+<p>
+<h3><A NAME="destroy">destroy</A></h3>
+<p>
+Destroy a marker. Just tell the marker to destroy itself.
+All cleanup outside the marker facility relies upon the use of callbacks.
+This includes our callback markerDestroyCallback below.
+<p>
+Usage:
+<p>
+<pre>
+ destroy
+</pre>
+<p>
+<h3><A NAME="markpos">markpos</A></h3>
+<p>
+Mark the current position of a marker for a later redraw.
+<p>
+Usage:
+<p>
+<pre>
+ markpos
+</pre>
+<p>
+Markpos is used to mark the position of a marker before changing any
+marker attributes, so that a later "redraw marked" will erase the old
+marker rather than the new one. This is necessary, for example, if any
+marker attributes are changed which affect the size or position of the
+marker.
+<p>
+<h3><A NAME="redraw">redraw</A></h3>
+<p>
+Redraw a marker.
+<p>
+Usage:
+<p>
+<pre>
+ redraw [function] [erase|noerase] [markpos|nomarkpos]
+</pre>
+<p>
+By default redraw will erase the old marker at the position indicated by
+a previous call to markpos, and redraw the marker with the current
+attributes using the drawing function copy (copy source to destination).
+Hence the usual usage is "markpos ... change marker attributes ... redraw".
+Optional arguments may be given to change the drawing function, enable or
+disable erase, or force redraw to do a markpos. These arguments may be
+given in any order.
+<p>
+The drawing functions are as given in the XLIB documentation, minus the
+"GX" prefix. The most commonly used functions are "copy" and "xor".
+A normal marker redraw uses function=copy.
+<p>
+<h3><A NAME="raise">raise</A></h3>
+<p>
+Raise a marker, i.e., cause it to be drawn on top of other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ raise [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will raise itself above this
+marker, otherwise the raised marker becomes the topmost marker.
+<p>
+<h3><A NAME="lower">lower</A></h3>
+<p>
+Lower a marker, i.e., cause it to be drawn beneath other
+markers when overlapping markers are drawn.
+<p>
+Usage:
+<p>
+<pre>
+ lower [reference-marker]
+</pre>
+<p>
+In a reference marker is named the marker will lower itself beneath this
+marker, otherwise the lowered marker becomes the lowest marker.
+<p>
+<h3><A NAME="move">move</A></h3>
+<p>
+Move a marker.
+<p>
+Usage:
+<p>
+<pre>
+ move x y
+</pre>
+<p>
+Move the marker center to the indicated coordinates in the display window.
+<p>
+<h3><A NAME="resize">resize</A></h3>
+<p>
+Resize a marker.
+<p>
+Usage:
+<p>
+<pre>
+ resize width height
+</pre>
+<p>
+Resize the marker to the indicated size. By default width and height are
+given in pixels. For a text marker one can append "ch" to indicate that
+the units are chars in whatever font is in use, e.g., "40ch" or "40 chars"
+is an acceptable value for a text marker dimension.
+<p>
+<h3><A NAME="rotate">rotate</A></h3>
+<p>
+Rotate a marker.
+<p>
+Usage:
+<p>
+<pre>
+ rotate angle
+</pre>
+<p>
+Redraw a marker oriented to the given rotation angle. The angle is
+given in radians.
+<p>
+<h3><A NAME="getAttribute">getAttribute</A></h3>
+<p>
+Return the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ value = getAttribute attribute-name
+</pre>
+<p>
+<h3><A NAME="setAttribute">setAttribute</A></h3>
+<p>
+Set the value of a marker attribute.
+<p>
+Usage:
+<p>
+<pre>
+ setAttribute attribute-name value
+</pre>
+<p>
+<h3><A NAME="getAttributes">getAttributes</A></h3>
+<p>
+Return the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ getAttributes attribute-list
+ i.e. getAttributes {name value [name value ...]}
+ or getAttributes name value [name value ...]
+</pre>
+<p>
+where "value" is the name of the variable in which the attribute value
+is to be stored.
+<p>
+<h3><A NAME="setAttributes">setAttributes</A></h3>
+<p>
+Set the values of a list of marker attributes.
+<p>
+Usage:
+<p>
+<pre>
+ setAttributes attribute-list
+ i.e. setAttributes {name value [name value ...]}
+</pre>
+<p>
+where "value" is the new value of the associated marker attribute.
+<p>
+<h3><A NAME="getVertices">getVertices</A></h3>
+<p>
+Get some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ getVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is returned in the
+variable "points", as a string of the form { {x y} {x y} ...}. The first
+point is number zero.
+<p>
+<h3><A NAME="setVertices">setVertices</A></h3>
+<p>
+Set some or all of the vertices making up the polygon or
+polyline representation of a marker.
+<p>
+Usage:
+<p>
+<pre>
+ setVertices points [first npts]
+</pre>
+<p>
+The polygon or polyline representation of a marker is set using the points
+passed in the "points" variable as a string of the form { {x y} {x y} ...}.
+If FIRST and NPTS are not specified first is assumed to be zero (the first
+point) and NPTS is the length of the points array.
+<p>
+<h3><A NAME="getRegion">getRegion</A></h3>
+<p>
+Return as a text string a high level description of the
+region defined by a marker.
+<p>
+Usage:
+<p>
+<pre>
+ region = getRegion [unmap] [coord-type]
+</pre>
+<p>
+The output string defines the marker type and the major marker positional
+attributes. The region description formats for the various marker types
+follow.
+<p>
+<pre>
+ text raster x y width height
+ line raster x y x y
+ polyline raster npts { {x y} {x y} ...}
+ rectangle raster x y width height rotangle
+ circle raster x y radius
+ ellipse raster x y width height rotangle
+ polygon raster npts { {x y} {x y} ...}
+</pre>
+<p>
+Here, width and height refer to the distance from the marker center to an
+edge, not to the width or height of the whole marker. This avoids
+ambiguities about where the edge of a marker is if the width is even or
+odd. Using the center to edge measurement, the edge is at x +/- width,
+y +/- height.
+<p>
+If the "unmap" flag is given getRegion will attempt to associate the
+marker with a mapped raster, reversing any mappings from the screen back
+to the original source raster, and returning the raster number and raster
+coordinates and marker sizes. If "unmap" is not given the marker
+coordinates will refer to raster 0. Either pixel ("pixel") or NDC
+("ndc") coordinates may be returned, pixel coordinates being the default.
+<p>
+<h3><A NAME="getRect">getRect</A></h3>
+<p>
+Return the region enclosed by a rectangle marker. The rect is
+returned in a form convenient for use as the destination rect in a gterm
+widget raster mapping.
+<p>
+Usage:
+<p>
+<pre>
+ getRect dx dy dnx dny
+</pre>
+<p>
+The rect is stored in the output arguments.
+<p>
+
+<hr noshade=5>
+
+<a name="6.6"></a>
+<h3>6.6 Widget</h3>
+<p>
+The Widget class is the generic or base class for the window system
+toolkit widgets supported by the object manager. The Widget class
+supports a number of different Xt widget classes using a table driven
+approach to describe each widget. Any widget may be created, destroyed,
+and manipulated in various ways using only the generic Widget class
+procedures and Widget-specific resources. The Widget class may be
+subclassed to support complex Widgets that require custom class-specific
+commands for use by the GUI code.
+<p>
+Generic Widget-class commands:
+<p>
+<pre>
+ <a href="#set">set</a> &lt;resource-name&gt; &lt;value&gt;
+ <a href="#get">get</a> &lt;resource-name&gt;
+<p>
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt; [<callback-name>]
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#setSensitive">setSensitive</a> &lt;sensitive&gt;
+ <a href="#isSensitive">isSensitive</a>
+<p>
+ <a href="#realize">realize</a>
+ <a href="#unrealize">unrealize</a>
+ <a href="#isRealized">isRealizeed</a>
+ <a href="#map">map</a>
+ <a href="#unmap">unmap</a>
+ <a href="#manage">manage</a> child [child ...]
+ <a href="#unmanage">unmanage</a> child [child ...]
+ <a href="#popup">popup</a> [grab-kind]
+ <a href="#popdown">popdown</a>
+ <a href="#popupSpringLoaded">popupSpringLoaded</a>
+<p>
+ <a href="#move">move</a> &lt;x&gt; &lt;y&gt;
+ <a href="#resize">resize</a> &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+ <a href="#configure">configure</a> &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+The most important Widget commands are set/get resource, and the
+callbacks. The widget sensitivity can be set and queried using set/get
+resource, but special procedures are provided to make this common operation
+more convenient.
+<p>
+Class specific functions:
+<p>
+<pre>
+ <a href="#append">append</a> text # text widget
+ <a href="#setList">setList</a> list [resize] # list widget
+ value = <a href="#getItem">getItem</a> itemno
+ <a href="#highlight">highlight</a> itemno
+ <a href="#unhighlight">unhighlight</a>
+</pre>
+<p>
+Ideally the widget class should be subclassed for widgets that require
+class-specific functions, but in simple cases involving standard widgets
+the support is built into the widget class code as a special case.
+<p>
+Special actions (used in translations):
+<p>
+<pre>
+ <a href="#do_userproc">call</a> (proc [,arg, ...])
+ <a href="#do_popup">popup</a> (menu-name [xoffset [yoffset]])
+ <a href="#do_popdown">popdown</a> (menu-name)
+</pre>
+<p>
+The "call" action is a very general mechanism which allows any GUI procedure
+to be registered with any translation using the X translation table
+mechanism. The popup and popdown actions are used for popup menus. The
+menu will be popped up at the event coordinates plus the optional offsets
+if given.
+<p>
+Event handling:
+<p>
+<pre>
+ <a href="#addEventHandler">addEventHandler</a> &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+Event callback:
+<p>
+<pre>
+ <a href="#userEventHandler">userEventHandler</a> widget event-type time wx wy rx ry other
+</pre>
+<p>
+In most cases translations are preferable to events, but a GUI can capture
+raw events if it wishes by adding event handlers. Nearly all of the X
+event types are supported. The callback syntax employs a number of
+standard arguments, followed by a number of event-specific arguments.
+<p>
+<h3><A NAME="addCallback">addCallback</A></h3>
+<p>
+Add a callback procedure to the callback list for
+a widget. If no callback name is given, "callback" is assumed.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback <procedure-name> [&lt;callback-name&gt;]
+</pre>
+<p>
+Specific widgets only support certain types of callbacks. There is no
+checking that the callback type specified is supported by a widget; the
+wrong type of callback can be registered, but it will never be called.
+<p>
+<h3><A NAME="deleteCallback">deleteCallback</A></h3>
+<p>
+Delete a callback procedure previously registered
+for a widget.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h3><A NAME="do_userproc">do_userproc (call)</A></h3>
+<p>
+Translation action procedure used to call general user
+action procedures in the interpreter. The name of the user procedure to
+be called is given as the first argument in the translation. For example,
+the translation "call(foo,a,b,c)" would cause procedure foo to be called
+with the arguments (a,b,c). The following arguments are special:
+<p>
+<pre>
+ Argument Replaced by
+<p>
+ $name object name of widget
+ $time event->time
+ $x event->x
+ $y event->y
+ $x_root event->x_root
+ $y_root event->y_root
+</pre>
+<p>
+The "user procedure" can be any server procedure.
+<p>
+<h3><A NAME="do_popup">do_popup</A></h3>
+<p>
+Popup a menu (or other spring loaded popup) at the location
+of the event which triggered this action.
+<p>
+Usage:
+<p>
+<pre>
+ popup(menu-name [xoffset [yoffset]])
+</pre>
+<p>
+<h3><A NAME="do_popdown">do_popdown</A></h3>
+<p>
+Pop down a menu.
+<p>
+Usage:
+<p>
+<pre>
+ popdown(menu-name)
+</pre>
+<p>
+<h3><A NAME="set">set</A></h3>
+<p>
+Set a widget resource.
+<p>
+Usage:
+<p>
+<pre>
+ set &lt;resource-name&gt; &lt;value&gt;
+</pre>
+<p>
+<h3><A NAME="get">get</A></h3>
+<p>
+Get a widget resource value as a string.
+<p>
+Usage:
+<p>
+<pre>
+ get &lt;resource-name&gt;
+</pre>
+<p>
+<h3><A NAME="append">append</A></h3>
+<p>
+Append data to a text widget.
+<p>
+Usage:
+<p>
+<pre>
+ append &lt;text&gt;
+</pre>
+<p>
+<h3><A NAME="setList">setList</A></h3>
+<p>
+Set the item list of a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ setList list [resize]
+</pre>
+<p>
+The list is a simple list of strings, passed as a single string argument to
+setList (quotes, braces, etc. may be used to quote strings containing
+special characters).
+<p>
+<h3><A NAME="getItem">getItem</A></h3>
+<p>
+Get an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ value = getItem itemno
+</pre>
+<p>
+If ITEMNO is a number the indicated list item is returned, or the string
+"EOF" if the requested item is beyond the end of the list. Otherwise the
+currently selected item is returned, and the index of the item is returned
+in the output variable ITEMNO. If no item is currently selected ITEMNO
+will be set to "none" on output.
+<p>
+<h3><A NAME="highlight">highlight</A></h3>
+<p>
+Highlight an item in a list widget.
+<p>
+Usage:
+<p>
+<pre>
+ highlight itemno
+</pre>
+<p>
+The indicated item of the list is highlighted as if the item had been
+selected by the user. Any previously highlighted item is unhighlighted.
+<p>
+<h3><A NAME="unhighlight">unhighlight</A></h3>
+<p>
+Unhighlight the currently highlighted item in a
+list widget.
+<p>
+Usage:
+<p>
+<pre>
+ unhighlight
+</pre>
+<p>
+Any currently highlighted item in the list widget is unhighlighted.
+<p>
+<h3><A NAME="realize">realize</A></h3>
+<p>
+Realize a widget. This activates and assigns windows for
+a widget and all of its descendants. Realizing a widget does not in itself
+cause it to appear on the screen.
+<p>
+Usage:
+<p>
+<pre>
+ realize
+</pre>
+<p>
+<h3><A NAME="unrealize">unrealize</A></h3>
+<p>
+Unrealize a widget. This destroys the windows assigned
+to a widget and all of its descendants.
+<p>
+Usage:
+<p>
+<pre>
+ unrealize
+</pre>
+<p>
+<h3><A NAME="isRealized">isRealized</A></h3>
+<p>
+Test whether a widget is realized.
+<p>
+Usage:
+<p>
+<pre>
+ isRealized
+</pre>
+<p>
+<h3><A NAME="map">map</A></h3>
+<p>
+Map a widget.
+<p>
+Usage:
+<p>
+<pre>
+ map
+</pre>
+<p>
+<h3><A NAME="unmap">unmap</A></h3>
+<p>
+Unmap a widget.
+<p>
+Usage:
+<p>
+<pre>
+ unmap
+</pre>
+<p>
+<h3><A NAME="manage">manage</A></h3>
+<p>
+Manage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Managing the
+children makes them appear in the window, possibly causing the other
+children to be rearranged in the window.
+<p>
+Usage:
+<p>
+<pre>
+ manage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h3><A NAME="unmanage">unmanage</A></h3>
+<p>
+Unmanage a list of child widgets. These should share the
+same common parent, a geometry widget of some sort. Unmanaging the
+children makes them disappear from the window and be removed from geometry
+management, possibly causing the other children to be rearranged in the
+window.
+<p>
+Usage:
+<p>
+<pre>
+ unmanage child [child ...]
+</pre>
+<p>
+This message should be sent to the geometry widget which is the parent
+of the children.
+<p>
+<h3><A NAME="popup">popup</A></h3>
+<p>
+Popup a shell widget. If no grab is indicated the popup
+can remain up while other windows accept input.
+<p>
+Usage:
+<p>
+<pre>
+ popup [grab-kind]
+</pre>
+<p>
+<h3><A NAME="popdown">popdown</A></h3>
+<p>
+Popdown a shell widget.
+<p>
+Usage:
+<p>
+<pre>
+ popdown
+</pre>
+<p>
+<h3><A NAME="popupSpringLoaded">popupSpringLoaded</A></h3>
+<p>
+Popup a shell widget, e.g., a popup menu.
+This implies an exclusive grab.
+<p>
+Usage:
+<p>
+<pre>
+ popupSpringLoaded
+</pre>
+<p>
+<h3><A NAME="move">move</A></h3>
+<p>
+Move a widget to the given window relative coordinates.
+<p>
+Usage:
+<p>
+<pre>
+ move &lt;x&gt; &lt;y&gt;
+</pre>
+<p>
+<h3><A NAME="resize">resize</A></h3>
+<p>
+Resize a widget.
+<p>
+Usage:
+<p>
+<pre>
+ resize &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h3><A NAME="configure">configure</A></h3>
+<p>
+Configure a widget, i.e., execute a simultaneous
+move and resize.
+<p>
+Usage:
+<p>
+<pre>
+ configure &lt;x&gt; &lt;y&gt; &lt;width&gt; &lt;height&gt; &lt;border-width&gt;
+</pre>
+<p>
+<h3><A NAME="setSensitive">setSensitive</A></h3>
+<p>
+Set the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ setSensitive &lt;sensitive&gt;
+</pre>
+<p>
+<h3><A NAME="isSensitive">isSensitive</A></h3>
+<p>
+Test the sensitivity of a widget.
+<p>
+Usage:
+<p>
+<pre>
+ isSensitive
+</pre>
+<p>
+<h3><A NAME="addEventHandler">addEventHandler</A></h3>
+<p>
+Add a custom event handler to a widget. A list
+of event masks is given to define the classes of events the user supplied
+event handling procedure is to receive.
+<p>
+Usage:
+<p>
+<pre>
+ addEventHandler &lt;procname&gt; &lt;event-mask&gt; [&lt;event-mask&gt;...]
+</pre>
+<p>
+<h3><A NAME="removeEventHandler">removeEventHandler</A></h3>
+<p>
+Remove an event handler previously posted
+with addEventHandler, above.
+<p>
+Usage:
+<p>
+<pre>
+ removeEventHandler procname
+</pre>
+<p>
+<h3><A NAME="event">event</A></h3>
+<p>
+Generic event handler called when a widget event handler
+posted by addEventHandler is called.
+<p>
+The user event handler is called as
+<p>
+<pre>
+ userEventHandler widget event-type time wx wy rx ry other
+</pre>
+<p>
+where "other" is an event-type specific list of fields describing the
+the event.
+<hr noshade=5>
+
+<a name="6.7"></a>
+<h3>6.7 Parameter</h3>
+<p>
+The UI parameter class is used for client-UI communications. The client
+does not control the user interface directly, rather the UI defines a set
+of abstract UI parameters, and during execution the client application
+assigns values to these parameters. These UI parameters should be thought
+of as describing the runtime state of the client as viewed by the GUI.
+The GUI is free to interpret this state information in any way, including
+ignoring it. Many GUIs can be written which use the same client state
+as described by the UI parameters.
+<p>
+Assigning a value to a UI parameter causes the new value to be stored, and
+any parameter action procedures registered by the UI to be called.
+The action or actions [if any] taken when a parameter value changes are
+arbitrary, e.g. the action might be something as simple as changing a
+displayed value of a UI widget, or something more complex like displaying
+a popup.
+<p>
+<h2>UI Parameter class commands:</h2>
+<p>
+<pre>
+ <a href="#getValue">getValue</a>
+ <a href="#setValue">setValue</a> &lt;new-value&gt;
+ <a href="#addCallback">addCallback</a> &lt;procedure-name&gt;
+ <a href="#deleteCallback">deleteCallback</a> &lt;procedure-name&gt;
+ <a href="#notify">notify</a>
+</pre>
+<p>
+The most common usage is for the GUI to post one or more callbacks for
+each UI parameter. When the UI parameter value is changed [with setValue,
+e.g. by the client] the GUI callback procedures are called with the old
+and new UI parameter values on the command line. addCallback is used to
+add a callback procedure, and deleteCallback to delete one. Multiple
+callbacks may be registered for a single UI parameter. notify is used
+to simulate a parameter value change, causing any callback procedures to
+be invoked.
+<p>
+The callback procedure is called as follows:
+<p>
+<pre>
+ user-procedure param-name {old-value} {new-value}
+</pre>
+<p>
+The important thing to note here is that the old and new value strings
+are quoted with braces. This prevents any interpretation of the string
+by Tcl when the callback is executed, which is necessary because the
+strings can contain arbitrary data. When Tcl calls the callback the
+first level of braces will be stripped off, leaving old-value and new-value
+each as a single string argument.
+<p>
+<p>
+<h2><A NAME="setValue">setValue</A></h2>
+<p>
+Set the value of a parameter, and notify all clients
+via the posted callback procedures that the parameter value has changed.
+<p>
+Usage:
+<p>
+<pre>
+ setValue &lt;new-value&gt;
+</pre>
+<p>
+<h2><A NAME="getValue">getValue</A></h2>
+<p>
+Get the value of a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ getValue
+</pre>
+<p>
+<h2><A NAME="notify">notify</A></h2>
+<p>
+Notify the registered clients of a parameter as if the
+value had changed.
+<p>
+Usage:
+<p>
+<pre>
+ notify
+</pre>
+<p>
+<h2><A NAME="addCallback">addCallback</A></h2>
+<p>
+Add a callback procedure to the callback list for
+a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ addCallback &lt;procedure-name&gt;
+</pre>
+<p>
+<h2><A NAME="deleteCallback">deleteCallback</A></h2>
+<p>
+Delete a callback procedure previously registered
+for a parameter.
+<p>
+Usage:
+<p>
+<pre>
+ deleteCallback &lt;procedure-name&gt;
+</pre>
+<hr noshade=5>
+
+<hr noshade=5>
+</body>
+</html>
diff --git a/vendor/x11iraf/obm/docs/obm/servercom.html b/vendor/x11iraf/obm/docs/obm/servercom.html
new file mode 100644
index 00000000..16c4c24e
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/obm/servercom.html
@@ -0,0 +1,375 @@
+<h1><A NAME="serverReset">serverReset</A></h1>
+<p>
+The "reset-server" command is implemented as a special case in ServerEvaluate.
+After doing a true reset ServerEvaluate calls Tcl_Eval to evaluate the full
+message which still contains the reset-server command. We want to ignore
+this the second time, so we treat the command here as a no-op.
+<p>
+Usage:
+<p>
+<pre>
+ reset-server
+</pre>
+<p>
+Note: for reset-server to be recognized by ServerEvaluate and really reset
+things, it must be the first command in a message to the server.
+<p>
+<h1><A NAME="appInitialize>appInitialize</A></h1>
+<p>
+TCL command to initialize the server for a new application, setting the
+application name and loading the application resources.
+<p>
+Usage:
+<p>
+<pre>
+ appInitialize appname, appclass, resources
+</pre>
+<p>
+<h1><A NAME ="createObjects">createObjects</A></h1>
+<p>
+TCL command to create the tree of UI objects comprising the user interface.
+The object tree is defined by a string valued resource. If no resource is
+named the default "objects" resource will be used.
+<p>
+Usage:
+<p>
+<pre>
+ createObjects [resource-name]
+</pre>
+<h1><A NAME="destroyObject">destroyObject</A></h1>
+<p>
+Destroy an object and all of its children.
+<p>
+Usage:
+<pre>
+ destroyObject object-name
+</pre>
+<p>
+<h1><A NAME="activate">activate</A></h1>
+Activate the user interface. When called the first time the user interface
+is created and activated, thereafter the UI is merely reactivated (e.g.
+mapped if unmapped).
+<p>
+Usage:
+<p>
+<pre>
+ activate
+</pre>
+<p>
+<h1><A NAME="deactivate">deactivate</A></h1>
+<p>
+Deactivate the user interface. Optionally unmaps the UI and calls the Obm
+client back to let it know that the UI has been deactivated.
+<p>
+Usage:
+<p>
+<pre>
+ deactivate [unmap]
+</pre>
+<p>
+<h1><A NAME="getResource">getResource</A></h1>
+<p>
+Get the string value of the specified application resource (window
+system parameter). This allows use of the resource mechanism to supply
+default values for GUI parameters.
+<p>
+Usage:
+<p>
+<pre>
+ value = getResource resource-name [class [default-value]]
+</pre>
+<p>
+In the simplest case one merely requests a resource by name and the
+string value is returned as the function value. If the resource has
+an entry in the fallback resources for the application (appInitialize
+resource list) then a value is guaranteed to be returned.
+<p>
+If the Class name for the resource is given then a class default value
+will be returned if no entry is found for the name resource instance. This
+is useful when there are a number of resources of the same type (same class).
+If most or all resources in the same class have the same default value one
+need only make one entry for the Class in the application defaults resource
+list. It is up to the application developer to define the class name of a
+resource - the class name can be any string. Examples are "Font", "Cursor",
+etc. By convention the first character of a class name is capitalized, while
+instance names begin with a lower case letter.
+<p>
+If there is an entry for the named resource in the resource list passed to
+appInitialize then a value string is guaranteed to be returned. This will be
+either the appInitialize default, or a value specified by the system or the
+user in an X resources file. If one is not certain a default value is defined
+somewhere, a default value should be specified in the getResource call as
+shown above.
+<p>
+See also getResources, used to get multiple resources in one call.
+<p>
+<h1><A NAME="getResources">getResources</A></h1>
+<p>
+Get the string values of a list of resources.
+<p>
+Usage:
+<p>
+<pre>
+ getResources resource-list
+</pre>
+<p>
+e.g.
+<pre>
+ getResources {
+ { resource [variable class [default-value]]] }
+ { resource [variable class [default-value]]] }
+ (etc.)
+ }
+</pre>
+<p>
+<h1><A NAME="createMenu">createMenu, editMenu</A></h1>
+<p>
+Create or modify a menu. The editMenu function is an alias for createMenu.
+<p>
+Usage:
+<pre>
+ createMenu menu-name parent item-list
+</pre>
+<p>
+e.g.,
+<pre>
+ createMenu menu-name parent {
+ { label function data [options...] }
+ { label function data [options...] }
+ (etc.)
+ }
+</pre>
+<p>
+where
+<p>
+<pre>
+ menu-name is the object name for the menu popup shell
+ parent is the parent widget of the menu shell
+ label is a menu item label
+ function is the function to be performed when the menu
+ item is selected, e.g., f.exec, f.data, f.space, or f.line.
+ data is function dependent data
+ options are option-name option-value pairs, as specified
+ below.
+</pre>
+<p>
+In the item list the fields label and option-value may be any Tcl expression.
+Expressions are evaluated in the server context. The data field is a Tcl
+script to be executed when the menu item is selected.
+<p>
+Options are specified as "option option-value". The menu item options are
+as follows.
+<p>
+<pre>
+ bitmap A bitmap to be displayed left justified in the label field
+ (e.g. to indicate a parameter setting).
+ sensitive Specifies whether the menu item is active (sensitive=true)
+ or inactive (sensitive=false, item grayed out).
+ accelerator Specifies an input translation (accelerator, e.g.,
+ keyboard event) which can be used to execute the
+ menu item.
+</pre>
+<p>
+The option-value field may be any Tcl expression.
+<p>
+Example:
+<p>
+<pre>
+ createMenu fileMenu toplevel {
+ { "File Menu" f.title}
+ { Open f.exec openFile}
+ { Save f.exec saveFile}
+ { Load f.menu loadMenu}
+ { no-label f.line }
+ { Quit f.exec "send client Quit" }
+ }
+</pre>
+<p>
+The first createMenu is called for a given menu the menu is created, added
+to the menu list, and all window system widgets are created for the menu.
+Subsequent calls will result in only the changed parts of the menu being
+altered provided the changes are not great. Hence this routine can be called
+to efficiently modify a menu when minor runtime changes occur, e.g., an
+item label or action changes, the item value changes state, and so on,
+without need for the GUI code to know how to make the necessary detailed
+changes to the widgets used to implement the menu.
+<p>
+<h1><A NAME="destroyMenu">destroyMenu</A></h1>
+<p>
+Destroy a menu. This can be used to free up the resources used by a
+menu, e.g., if the menu is not expected to be needed again for a while.
+<p>
+Usage:
+<p>
+<pre>
+ destroyMenu menu-name
+</pre>
+<p>
+<h1><A NAME="createBitmap">createBitmap</A></h1>
+<p>
+Create a named bitmap. This replaces any old bitmap of the same name. The
+new bitmap is cached in server memory; when a widget bitmap resource is set,
+the bitmap cache will be searched for the named bitmap before asking Xlib
+to find the bitmap.
+<p>
+Usage:
+<p>
+<pre>
+ createBitmap name width height data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createBitmap foo 16 16 {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+<p>
+<h1><A NAME="createCursor">createCursor</A></h1>
+<p>
+Create a cursor from bitmap data. The cursor is entered into the server's
+cursor cache and will override any existing entry of the same name.
+<p>
+Usage:
+<p>
+<pre>
+ createCursor name source mask fg_color bg_color x_hot y_hot
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createCursor foo bitmap1 bitmap2 black white 8 8
+</pre>
+<p>
+The named bitmaps must be created first with createBitmap.
+<p>
+<h1><A NAME="createPixmap">createPixmap</A></h1>
+<p>
+Create a named pixmap. This replaces any old pixmap of the same name. The
+new pixmap is cached in server memory; when a widget pixmap resource is set,
+the pixmap cache will be searched for the named pixmap before asking Xlib
+to find the pixmap.
+<p>
+Usage:
+<p>
+<pre>
+ createPixmap name width height depth fg_color bg_color data
+</pre>
+<p>
+e.g.,
+<p>
+<pre>
+ createPixmap foo 16 16 8 black white {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+</pre>
+<p>
+<h1><A NAME="print">print</A></h1>
+<p>
+Print a string on the standard output. This is used mainly for debugging
+user interfaces.
+<p>
+Usage:
+<p>
+<pre>
+ print arg [arg ...]
+</pre>
+<p>
+<h1><A NAME="send">send</A></h1>
+<p>
+Send a message to an object. The object interprets the message and returns
+a function value as the string result of the TCL command.
+<p>
+Usage
+<p>
+<pre>
+ send &lt;object&gt; &lt;message&gt;
+</pre>
+<p>
+<h1><A NAME="postActivateCallback">postActivateCallback</A></h1>
+<p>
+Post a callback procedure to be called when the UI is activated. The UI is
+activated when it is first downloaded to server, but it may also be
+activated (reactivated) after the application has exited and is later
+restarted, or when the UI is deactivated and reactivated. Note
+that the UI state vis-a-vis the external world (client application) may
+no longer be accurate after it has been idle for a time and then reactivated.
+<p>
+Usage:
+<p>
+<pre>
+ postActivateCallback &lt;procedure&gt;
+</pre>
+<p>
+<p>
+<h1><A NAME="postTimedCallback">postTimedCallback</A></h1>
+<p>
+Post a callback to call the named procedure back after a specified delay
+in milliseconds.
+<p>
+Usage:
+<p>
+<pre>
+ id = postTimedCallback procedure msec [client-data]
+</pre>
+<p>
+After the specified delay the user callback procedure will be called with
+client_data (if given) as the single argument. Only one call will be made;
+the client must repost the callback in each call if the procedure is to be
+repeatedly executed.
+<p>
+An ID value is returned which may be passed to deleteTimedCallback to delete
+the timer.
+<p>
+<h1><A NAME="deleteTimedCallback">deleteTimedCallback</A></h1>
+<p>
+Delete a timer callback procedure. This procedure is typically used to
+break a timer loop, where the timer procedure repeatedly reposts itself at
+the end of each interval.
+<p>
+Usage:
+<p>
+<pre>
+ deleteTimedCallback id
+</pre>
+<p>
+The ID string is returned by postTimedCallback when a timer is posted.
+<p>
+<h1><A NAME="postWorkCallback">postWorkCallback</A></h1>
+<p>
+Post a callback for a procedure to be called when the server is idle.
+Work procedures are used to perform computations in the background while
+the user interface remains active and able to respond to input events.
+This works only if the user work procedure does its job in small increments,
+doing only a small amount of processing in each call. The work procedure
+will be called repeatedly until it returns a status indicating that it has
+finished its task.
+<p>
+Usage:
+<p>
+<pre>
+ id = postWorkCallback procedure [client-data]
+</pre>
+<p>
+When the server has nothing else to do the user work procedure will be
+called with client_data (if given) as the single argument. The work procedure
+should return the string "done" when all processing is finished, or any other
+string if the procedure is to be called again.
+<p>
+An ID value is returned which may be passed to deleteWorkCallback to delete
+the work procedure.
+<p>
+<h1><A NAME="deleteWorkCallback">deleteWorkCallback</A></h1>
+<p>
+Delete a work callback procedure.
+<p>
+Usage:
+<p>
+<pre>
+ deleteWorkCallback id
+</pre>
+<p>
+The ID string is returned by postWorkCallback when a work procedure is posted.
diff --git a/vendor/x11iraf/obm/docs/tody.paper/todyd.html b/vendor/x11iraf/obm/docs/tody.paper/todyd.html
new file mode 100644
index 00000000..53705df4
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/tody.paper/todyd.html
@@ -0,0 +1,522 @@
+<HEAD>
+<TITLE> A Portable GUI Development System---The IRAF Widget Server </TITLE>
+</HEAD>
+<BODY><P>
+<h5><hr> Astronomical Data Analysis Software and Systems IV<br>ASP Conference Series, Vol. 77, 1995<br>Book Editors: R. A. Shaw, H. E. Payne, and J. J. E. Hayes<br>Electronic Editor: H. E. Payne <hr> </h5>
+<H1><A NAME=SECTION021900000000000000000> A Portable GUI Development System---The IRAF Widget Server</A></H1>
+<P>
+<P><b>D. Tody</b><br>
+National Optical Astronomy Observatories, P.O. Box 26732,
+Tucson, AZ 85726<br>
+<P>
+The National Optical Astronomy Observatories are
+operated by the Association of Universities for Research in Astronomy, Inc.
+(AURA) under cooperative agreement with the National Science Foundation.
+<P>
+<P>
+<A NAME=1229>&#160;</A>
+<A NAME=1230>&#160;</A>
+<A NAME=1231>&#160;</A><A NAME=1232>&#160;</A>
+<A NAME=1233>&#160;</A>
+<A NAME=1234>&#160;</A><A NAME=1235>&#160;</A><A NAME=1236>&#160;</A><A NAME=1237>&#160;</A>
+<A NAME=1238>&#160;</A>
+<A NAME=1239>&#160;</A>
+<A NAME=todyd>&#160;</A><H3>Abstract:</H3>
+<EM>We describe a new GUI (Graphics User Interface) development environment
+which extends the X window system and the X Toolkit (Xt) with a high-level,
+object-oriented, interpreted programming language.
+This approach will allow GUIs written
+using standard Xt-based widget sets to be constructed without requiring any
+window system programming on the part of the programmer.
+The architecture of the resulting program completely separates the GUI from
+the applications code, allowing the GUI to be developed separately and
+replaced at will without modifying the application.
+Despite the separation of the GUI from the application the two are tightly
+integrated using an asynchronous, event-driven messaging system based on
+requests and client events, with the remote client application appearing as
+just another class of object within the GUI.
+This approach maximizes window system and toolkit independence and is well
+suited to distributed applications, allowing the GUI and client application
+to be run easily on separate processors or computers.
+<P>
+</EM><P>
+<H1><A NAME=SECTION021910000000000000000> Introduction</A></H1>
+<P>
+Most window system programming today is done via one of two approaches. The
+first approach is to code directly in C or C++ at the window system toolkit
+level, usually integrating the user interface code and applications code
+within the same program. The second approach, which is really just a
+variation on the first, is to use one of the many commercial GUI builders
+available. This simplifies the programmer's task by allowing the user
+interface to be interactively designed, relying on the GUI builder to
+generate the window system code required to implement the user interface
+specified by the programmer and requiring the programmer to code only the
+application functionality. As with the direct coding approach, the
+applications code is often integrated with the GUI in the same program.
+<P>
+Recently a third approach has been used. This employs a high-level,
+interpreted language in which the programmer codes all or part of the
+application, with at least the GUI being implemented in the high-level
+interpreted language. Tcl/Tk is a recent example of this approach. Other
+examples of the high-level interpreted approach from outside the Unix/X
+world include Apple's HyperCard/HyperTalk, and the Visual Basic facility of
+Microsoft Windows.
+<P>
+This paper presents a new, high-level, interpreted window system toolkit
+which like Tcl/Tk is also based on the Tcl interpreter. Unlike Tcl/Tk,
+which is by definition Tk specific, our approach tries to maximize window
+system and window system toolkit independence to ease future upgrades to new
+window systems or toolkits. The initial implementation, which is for the X
+Window System, is based on the X Toolkit (a part of the X Consortium X11
+release) and uses standard Xt-based widgets. Support for an asynchronous,
+event-driven messaging system is an integral part of the design, allowing
+the GUI to be isolated from the functional part of an application and making
+the facility well suited to distributed applications, e.g., where a GUI
+executing locally talks to application code executing remotely, with the
+application downloading the GUI to be run at startup time. The core
+facility is implemented as a simple C-callable library which can be used to
+implement new GUI-based programs without having to write any window
+system-level code.
+<P>
+An important aspect of the facility described in this paper is that it
+represents a general user interface management system (UIMS) tailored for
+astronomical GUIs. The intent is that by providing a high-level facility
+tailored for our applications, we can simplify the task of developing GUIs
+for astronomical applications while providing a greater degree of
+consistency between applications since they will share the same GUI
+components. This is particularly important in the area of 2D graphics and
+imaging, including presentation and user interaction with such data, since
+the standard toolkits do not address this area.
+<P>
+<H1><A NAME=SECTION021920000000000000000> The Widget Server</A></H1>
+<P>
+<H2><A NAME=SECTION021921000000000000000> Overview</A></H2>
+<P>
+``Widgets'' (window objects), are the basic building blocks of graphical user
+interfaces. A window system toolkit provides a selection of widgets that
+the programmer can use to construct a user interface. Typical widgets
+include things like push buttons, scrollbars, pop-down menus, or scrolling
+text regions. The <i> widget server</i> serves up widgets to a remote client
+process in much the same way that the X display server serves up windows and
+other low-level display resources to a remote client application.
+<P>
+When a client application starts up it connects to the widget server and
+downloads its GUI. The GUI is a simple block of text which is interpreted
+and executed by the widget server. The GUI text contains a description of
+the widgets comprising the user interface, a number of interpreted action
+procedures to be called to process user interface or client events during
+execution, and any code needed to initialize the GUI.
+During execution the client application waits for and executes requests from
+the GUI, and sends messages to the GUI to inform it of any ``client events,''
+or changes in the state of the client. The conventional compiled client
+application implements all the application-specific functionality, but does
+not communicate directly with the user.
+<P>
+To the client application the GUI is merely a block of text to be passed on
+to the widget server; the client code knows nothing about the GUI other than
+the name of the GUI file to be sent to the widget server. The client knows
+only about the applications functionality which it implements, and the
+messages and requests used to communicate with the GUI. The GUI is
+completely isolated from the client application. While to the user the GUI
+appears to be an integral part of the application, the actual compiled
+client application has an interpreted command-line interface and can be
+executed stand-alone without any GUI.
+<P>
+<H2><A NAME=SECTION021922000000000000000> Widget Server Architecture</A></H2>
+<P>
+<P><A NAME=1250>&#160;</A><A NAME=todyfig1>&#160;</A><IMG ALIGN=BOTTOM ALT="" SRC="/iraf/web/projects/x11iraf/docs/todyd1.gif">
+<BR><STRONG>Figure:</STRONG> Widget Server Architecture.
+<A HREF="http://hoth.stsci.edu/adass-figs/todyd1.eps">
+ Original PostScript figure (34 kB)
+</A><P>
+
+<BR>
+<P>
+<P>
+The architecture of an application which uses the widget server is
+summarized in Figure <A HREF="todyd.html#todyfig1">1</A>.
+The typical widget server-based application consists of two processes, the
+process containing the client application, and the widget server process
+itself which executes the client's GUI. All user interface functionality
+resides in the GUI and all application-specific functionality resides in
+the client. During execution these processes communicate via an
+asynchronous object-based messaging system.
+<P>
+<H2><A NAME=SECTION021923000000000000000> Advantages of the Widget Server</A></H2>
+<P>
+The widget server architecture separates the user interface from the
+application-specific code and provides a high-level interpreted language
+for developing GUIs. This approach has significant advantages,
+including the following:
+<P>
+<OL><LI>
+The high-level, interpreted nature of the widget server makes it much
+easier to develop GUIs than is the case with toolkit-level programming or
+the conventional, compile-link approach.
+<LI>
+The use of an interpreted runtime language (Tcl) to compose the GUI is more
+powerful than the visual programming approach used in GUI builders, since
+the latter only address the appearance of the user interface.
+User interface builders can still be used with the widget server to
+interactively layout the user interface, although this is less important
+than it might be given the interpreted nature of the GUI (i.e., changes can be
+made and the GUI redisplayed very quickly).
+<LI>
+The high-level, integrated nature of the widget server-based GUI development
+environment makes it straightforward to customize the environment to support
+a particular class of application. This is important for large systems
+where GUIs are developed by many people working independently,
+to reduce the overall effort and improve consistency.
+<LI>
+The widget server isolates all window system and toolkit code into a single
+executable which can serve any number of applications. This greatly reduces
+disk space consumption in a large system that has many application GUIs.
+<LI>
+Since the widget server is a single executable it is easy to have multiple
+versions, e.g., supporting different toolkits or incorporating proprietary
+software to optimize performance for a particular class of workstation.
+<LI>
+Since all the window system code is isolated into a separate process the
+client application is completely window system independent, allowing the
+same client application to be used with a widget server GUI executing on
+any local or remote platform running any operating system.
+<LI>
+Porting a whole system full of GUIs to a new platform can be done by a
+single individual since only the widget server itself need be ported.
+<LI>
+No window system libraries, and indeed no compilation, is needed
+to develop GUIs. All that is needed is the widget server executable.
+This makes it much more feasible to use commercial or platform specific
+libraries should this be desired.
+<LI>
+The GUI is completely isolated into a small text file separate from the
+application, allowing the GUI and the application to be developed separately,
+or several alternate GUIs to be used with a single application.
+<LI>
+The widget server is well suited to distributed applications since the
+widget server can be run on the local workstation while the client
+application executes remotely. This allows the entire GUI to execute
+interactively on the local workstation, a much more efficient approach than,
+for example, running an X application over the network.
+</OL>
+<P>
+Possible disadvantages of the widget server approach are its relative
+complexity and the possibility of inefficiency when the application is
+distributed over two or more processes. For a small system where only a few
+GUI-based applications are needed many of our big-system concerns are
+unimportant and it might be simpler to program directly at the toolkit
+level, especially if a user interface builder tool is available. Efficiency
+can be a problem if the client code is required to respond in real time to
+user interface events, however this is rarely a problem in well designed
+applications since the more interactive portions of the program can be moved
+into the GUI, implemented as interpreted GUI procedures or as calls to the
+compiled functions in the widget server itself. The asynchronous nature of
+the messaging system ensures that the user interface will always be
+responsive even when the client is busy computing.
+<P>
+<P><A NAME=1259>&#160;</A><A NAME=todyfig2>&#160;</A><IMG ALIGN=BOTTOM ALT="" SRC="/iraf/web/projects/x11iraf/docs/todyd2.gif">
+<BR><STRONG>Figure 2:</STRONG> A Simple GUI: The ``Hello, world'' Application<BR>
+<P><H2><A NAME=SECTION021924000000000000000> Platform Independence</A></H2>
+<P>
+The widget server automatically provides a high degree of platform and
+window system independence since the GUI is isolated from the client
+application; in the worst case only the GUI file has to be changed to use a
+GUI-based application on a new platform. The current implementation
+provides full platform independence for platforms which run the X Window
+System since the current widget server implementation is X-based. No
+changes to the GUI files are needed for these platforms.
+<P>
+The current widget server implementation does not, however, provide full
+window system toolkit independence for window systems other than X. Ideally
+the widget server should define a virtual set of widgets which can be
+implemented on a variety of window systems and window system toolkits; not
+only X but also Windows, Windows NT, Macintosh, etc. This problem has
+partially been solved in that the language used in widget server GUIs
+isolates the widget-dependent code into a portion of the GUI which describes
+the widget hierarchy, assigning widget classes to named GUI objects. The
+runtime part of the GUI, i.e., the interpreted action or callback procedures
+called at runtime as the GUI executes, is already almost completely widget-
+and toolkit-independent. Defining a fully toolkit-independent virtual
+widget set is a future problem which cannot be attempted until we have a
+better idea what widgets are needed for our applications. Several
+commercial window system toolkits or GUI development environments exist
+which have already attempted to address this problem, at least for the
+standard toolkits.
+<P>
+The portion of the widget server which interfaces to the underlying window
+system and window system toolkit (widget set) is the <i> Object Manager</i>.
+This is discussed in the next section.
+<P>
+<H1><A NAME=SECTION021930000000000000000> The Object Manager Library</A></H1>
+<P>
+<H2><A NAME=SECTION021931000000000000000> Overview</A></H2>
+<P>
+The widget server is actually just a shell around the Object Manager library
+(OBM). The widget server extends the Object Manager by providing a way for
+external clients to connect to the Object Manager to download and execute a
+GUI. All of the real work of creating and executing the GUI is done by the
+Object Manager library. The widget server adds a client-server communications
+method.
+<P>
+The Object Manager provides services for creating, deactivating,
+reactivating, or destroying a GUI, creating or destroying objects, and
+delivering messages and events to objects within the GUI. The OBM provides
+the framework within which GUIs execute, including the interpreter,
+automatic memory allocation, and a library of runtime services.
+The Object Manager defines four main classes of objects: <i> Server</i>,
+<i> Client</i>, <i> Parameter</i> (for client events), and <i> Widget</i>, for
+the graphical elements of the interface. Within the Widget class are many
+subclasses, one for each type of widget.
+All Object Manager execution is event driven and asynchronous and is based
+on messages (requests), callbacks, and events. For example, defining a new
+GUI is done by sending a message to the server object.
+<P>
+The set of widgets implemented by the Object Manager is not fixed, i.e., new
+widgets can be added or existing widgets removed to meet the requirements of
+the applications which will be using the widget server. The base Widget
+class provides a generic set of methods usable with all widget subclasses.
+Complex widgets subclass the base Widget class to add their own methods.
+The current Object Manager provides a mixture of Xt-based widgets which
+provide a Motif-like appearance but which are publically available and
+redistributable. Source for these widgets and for all code used in the
+widget server is included in the distribution. The current widget set
+includes the base Xt widgets, the 3D Athena widgets, selected FWF (Free
+Widget Foundation) widgets, plus a few others such as the Layout widget from
+MIT, the HTML hypertext markup language widget from NCSA <i> Mosaic</i>, and
+the gterm-image widget from the IRAF project. Additional Xt-based widgets
+(including Motif, OLIT, and commercial widgets) can easily be added.
+<P>
+<H2><A NAME=SECTION021932000000000000000> The OBM Library</A></H2>
+<P>
+The main entry points of the OBM library are shown in Figure <A HREF="todyd.html#todyfig3">3</A>.
+The library is very simple since everything complicated is done by the
+interpreted GUI code. The main runtime function of the OBM library, from
+the point of view of the application which uses the library, is messaging.
+A window system application (such as the widget server) calls
+<i> ObmDeliverMsg</i> to deliver a message from the client application to a
+GUI object. A callback function is registered with the Object Manager to
+intercept client requests and pass them on to the client.
+<P>
+<P><A NAME=7268>&#160;</A><A NAME=todyfig3>&#160;</A><IMG ALIGN=BOTTOM ALT="" SRC="/iraf/web/projects/x11iraf/docs/todyd3.gif">
+<BR><STRONG>Figure 3:</STRONG> Principal routines of the Object Manager library, <i> libobm.a</i><BR>
+<P><H2><A NAME=SECTION021933000000000000000> Using the OBM Library to Build Standalone Applications</A></H2>
+<P>
+Our discussion has thus far concentrated on the widget server and
+distributed applications, because the widget server provides the best
+architecture for adding GUIs to tasks in an existing, large data processing
+system. Another important class of applications are window system
+applications, where the focus is on the window system functionality
+implemented by the application. Most conventional X window system
+applications fall into this class.
+<P>
+An important use of the Object Manager library is to implement such
+applications. A stand-alone, single-process window system application can be
+built using the OBM library. In this case the ``client'' is not a separate
+process, but an application-specific interpreter within the same process as
+the OBM library. The program could be written as a conventional window
+system program making direct calls to the underlying window system toolkit,
+but by using the OBM library virtually all window system specific code is
+eliminated and the GUI is isolated to a high-level, interpreted GUI file.
+The only compiled code required is that which implements the functionality
+of the application itself. The resulting task is almost completely window
+system independent.
+<P>
+A good example of an existing stand-alone window system task built around
+the OBM library is <i> ximtool</i>, the IRAF image display server program.
+This is a stand-alone X window system application used for image display and
+image interaction. <i> Ximtool</i> contains only about one page of C code
+which has anything to do with X. All of the remaining C code handles window
+system-independent raster image processing and the fifo or socket-based
+binary protocol used to communicate with remote clients for image display.
+The <i> ximtool</i> GUI is an interpreted GUI text file, identical to what
+one might use with a widget server-based task. The widget server itself,
+of course, is another example of a stand-alone X application based on the
+OBM library.
+<P>
+<H2><A NAME=SECTION021934000000000000000> The Object Manager Shell</A></H2>
+<P>
+Another stand-alone host application built around the Object Manager library
+is <i> obmsh</i>, the Object Manager shell. This is a Unix shell which executes
+OBM windowing scripts. It can be used to execute GUI files from the Unix
+command line, or be used in OBM-based scripts to write stand-alone Unix
+shell scripts that can be called as commands from the Unix environment.
+For example, the ``hello, world'' GUI shown in Figure <A HREF="todyd.html#todyfig2">2</A> could be
+converted to a Unix command <i> hello</i> by changing the file name to ``hello''
+and adding something like ``<code>SPM_quot</code>#!/usr/local/bin/obmsh&quot;'' to the file header.
+<P>
+<H1><A NAME=SECTION021940000000000000000> Messaging</A></H1>
+<P>
+<H2><A NAME=SECTION021941000000000000000> Messaging Fundamentals</A></H2>
+<P>
+The key to isolating the GUI from the client code of an application, while
+providing a tightly integrated, efficient application, lies with messaging.
+The messaging scheme used determines how objects within the application
+interact with each other during execution. This includes the interaction
+of the client code (client object) with the GUI. Our discussion here will
+concentrate on how messaging is used to link the client to the GUI, but it
+should be noted that the same messaging scheme is used for all object-to-object
+communications within the GUI as well.
+<P>
+Messaging as defined by the OBM consists of two parts: requests and
+client events. Requests are commands send to the client (or any other
+object). The recipient is free to modify or ignore the request as it wishes.
+Client events are messages sent to the GUI when the client state
+changes in any way. The same mechanism is also used to deliver other forms
+of client information to the GUI, e.g., in response to requests. The GUI is
+free to ignore client events. It is not unusual for a given GUI to be
+interested in only a portion of the client events generated by a client.
+<P>
+A client event is a message sent to an object of the OBM class <i> Parameter</i>.
+A parameter object is very simple, consisting of a name and a string value.
+The GUI registers callbacks with the user interface (UI) parameters, i.e.,
+client events,
+that it wishes to know about. The string value of a UI parameter can be
+anything, for example a number, a structure, a list, or a large block of text.
+It is common for multiple callbacks to be registered on a single UI parameter
+by independent elements of the GUI.
+<P>
+Messaging is fully asynchronous. Both requests and client events are queued
+and buffered, and periodically flushed to the process on the other end.
+Synchronization occurs automatically when the client waits for input from
+the server (GUI). The GUI never waits for a request to complete, nor does
+it check to see that a request has been honored. Rather, when the client
+processes the request it sends client events back to the GUI to inform the
+GUI of any actions performed by the client. The same thing happens when
+the client performs actions for any other reason, hence the GUI always
+reflects the true state of the client.
+<P>
+Client events are an important abstraction mechanism. Client events and
+messages allow the client to provide the GUI with all the information it
+needs to function, without the client code having any knowledge of the
+nature of the user interface. Yet, since requests and client events are
+decoupled, the client will function even if the client events and messages
+it sends are discarded, as when running the client code without a GUI or
+with radically different GUIs.
+<P>
+<H2><A NAME=SECTION021942000000000000000> Simple Messaging Example</A></H2>
+<P>
+Messaging is one of those things which is fundamentally simple, yet
+surprisingly hard to explain. As a simple example, consider what happens
+when the user selects a frame to be displayed in <i> ximtool</i>:
+<P>
+<OL><LI>
+The user pushes the next frame button.
+<LI>
+The callback procedure (in the GUI) for the nextFrame button sends the
+command ``nextFrame'' to the client.
+<LI>
+The client receives and processes the request, changing the frame,
+sending the new frame number to the UI parameter ``frame''.
+<LI>
+A GUI callback procedure registered on the ``frame'' parameter is called,
+updating the GUI to indicate the new display frame number.
+</OL>
+<P>
+This example simplifies things considerably but is accurate so far as it
+goes. In the real program there are a number of different ways the frame
+can be changed, e.g., by the next frame or previous frame buttons, by menu
+selection, keyboard accelerators, the blink timer, IRAF running in another
+process, and so on. All of these end up sending a request to the <i>
+ximtool</i> client which directly or indirectly results in a frame change.
+When the display frame is changed a number of client events are generated to
+inform the GUI not only of the new frame number, but also the new frame
+title, zoom, pan, and frame flip values, type of enhancement used for the
+frame, and so on. Each of these items represents a separate client event.
+Although the action of the program may be arbitrarily complex in real world
+examples, the basic messaging mechanism on which this is all based remains
+very simple.
+<P>
+<H1><A NAME=SECTION021950000000000000000> Software Products</A></H1>
+<P>
+<H2><A NAME=SECTION021951000000000000000> The X11IRAF Package</A></H2>
+<P>
+All of the software described in this paper is packaged in a single
+distribution called <i> x11iraf</i>. This includes <i> xgterm</i>, <i> ximtool</i>,
+the Object Manager library, sources for all the third party widgets used in
+OBM, and assorted demo applications. Everything needed to build the package
+is included, including compatible versions of some publically available
+libraries, e.g., Tcl and Xpm. Despite the name the software is
+not tied to IRAF in any way, other than that it is a product of the IRAF
+project and is used for IRAF GUIs.
+<P>
+<H2><A NAME=SECTION021952000000000000000> Xgterm</A></H2>
+<P>
+<i> Xgterm</i> is an upwards compatible version of the popular <i> xterm</i>
+with the <i> xterm</i> graphics ripped out and replaced with an
+OBM-based GUI which uses the gterm-image widget for graphics. The
+graphics supports a number of extensions, including full color support, an
+integrated imaging capability, dialog interaction, intelligent unconstrained
+resize, and a full crosshair cursor. Although <i> xgterm</i> is often used as
+a simple terminal emulator it is also a general widget server since it
+contains the full OBM library, and it can be used to execute
+arbitrarily complex OBM-based GUIs and manage the communications with the
+remote client. The current version of <i> xgterm</i> is based on the X11R6
+version of <i> xterm</i>.
+<P>
+<H2><A NAME=SECTION021953000000000000000> Ximtool</A></H2>
+<P>
+<i> Ximtool</i> is an image display server, used by remote client applications
+such as IRAF to display and interact with images. Several frames can be
+loaded and independently displayed in a full-frame or tiled configuration.
+Display frames can be any size. <i> Ximtool</i> is a good example of a
+conventional single process windowing application which uses the OBM library
+for the GUI and the window system interface.
+<P>
+<H2><A NAME=SECTION021954000000000000000> The Object Manager Library</A></H2>
+<P>
+The Object Manager library (OBM) is a high-level, interpreted window system
+toolkit that is used to implement arbitrary graphics user interfaces. The OBM
+library uses Tcl as the interpreter. The current version of the OBM
+library is based on the X toolkit and can be used with any Xt-based
+widget or widget set.
+<P>
+<H2><A NAME=SECTION021955000000000000000> The Gterm-Image Widget</A></H2>
+<P>
+The gterm-image widget is an X Toolkit-based widget for general
+2D graphics and image display. This is a complex widget and a full
+description of its capabilities is beyond the scope of this paper. The
+Gterm widget provides a general GKS-like vector graphics and text display
+capability. An integrated image display capability allows any number and
+size of image rasters to be created within the widget or in the X server.
+<i> Mappings</i> can be defined to map one raster to another, permitting
+general graphics pipelines involving scaling and other geometric transforms
+to be set up. Colormap support is included for grayscale and pseudocolor
+rendering of raster data. An interactive <i> graphics marker</i> facility is
+provided for interaction with the displayed graphic. The Gterm widget is
+used for all graphics and imaging in <i> xgterm</i> and <i> ximtool</i>.
+<P>
+<H1><A NAME=SECTION021960000000000000000> Adding GUIs to IRAF Applications</A></H1>
+<P>
+A major application of the widget server and the other software described
+in this paper is in adding GUIs to IRAF applications. In this case the
+IRAF task is the client: when the IRAF task starts up it downloads its GUI
+to the widget server, and during execution the IRAF task and the GUI
+communicate via the messaging facility described earlier. The changes
+required to add a GUI to an IRAF task are minor, ranging from
+changing a single line of code to cause the GUI file to be downloaded, to
+defining a set of client events and adding <i> gmsg</i> calls to allow more
+complete integration of the GUI. Adding a GUI to a task increases the
+system size by only the 10 Kb or so required for the GUI file.
+<P>
+<H1><A NAME=SECTION021970000000000000000> Availability and Further Information</A></H1>
+<P>
+Further information on the software described in this paper, including
+more detailed documentation, full sources, and executables for a variety
+of platforms can be found in
+<A HREF="/iraf/web/projects/x11iraf">the X11IRAF Web page</A>.
+Further information on IRAF itself and other IRAF products can be found in
+<A HREF="/iraf/ftp>the IRAF anonymous ftp archives</A>.
+Documentation on Tcl, Xt/XLIB and the other standard software products
+used in X11IRAF is available from many sources.
+<P>
+
+<P>
+
+<P>
+
+<P>
+<BR> <HR>
+<P><ADDRESS>
+adass4_editors@stsci.edu
+</ADDRESS>
+</BODY>
diff --git a/vendor/x11iraf/obm/docs/tody.paper/todyd1.gif b/vendor/x11iraf/obm/docs/tody.paper/todyd1.gif
new file mode 100644
index 00000000..ef206249
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/tody.paper/todyd1.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/tody.paper/todyd2.gif b/vendor/x11iraf/obm/docs/tody.paper/todyd2.gif
new file mode 100644
index 00000000..b3aea8ba
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/tody.paper/todyd2.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/docs/tody.paper/todyd3.gif b/vendor/x11iraf/obm/docs/tody.paper/todyd3.gif
new file mode 100644
index 00000000..7038a128
--- /dev/null
+++ b/vendor/x11iraf/obm/docs/tody.paper/todyd3.gif
Binary files differ
diff --git a/vendor/x11iraf/obm/geom.c b/vendor/x11iraf/obm/geom.c
new file mode 100644
index 00000000..ac5db512
--- /dev/null
+++ b/vendor/x11iraf/obm/geom.c
@@ -0,0 +1,179 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+/* Copyright 1987, Massachusetts Institute of Technology */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+
+/*
+ * GEOM.C -- Code to get geometry information for a window. This code was
+ * extracted from the xwininfo sources and hacked into the form of a library
+ * routine.
+ */
+
+#define SZ_GEOMETRY 64
+static char geometry[SZ_GEOMETRY];
+static Display *dpy;
+
+
+/* get_geometry -- Return the absolute size and position of a window. The
+ * geometry specification coresponding to the window size and position is
+ * returned as the function value.
+ */
+char *
+get_geometry (display, screen, window, origin)
+ Display *display;
+ Screen *screen;
+ Window window;
+ int origin; /* return only origin-relative coords */
+{
+ register char *op;
+ int screen_number = XScreenNumberOfScreen (screen);
+ XWindowAttributes win_attributes;
+ XVisualInfo vistemplate, *vinfo;
+ XSizeHints hints;
+
+ int dw = DisplayWidth (display, screen_number);
+ int dh = DisplayHeight (display, screen_number);
+ int showright = 0, showbelow = 0;
+ int rx, ry, xright, ybelow;
+ Status status;
+ Window wmframe;
+ long longjunk;
+ Window junkwin;
+ int junk;
+
+ if (!XGetWindowAttributes (dpy = display, window, &win_attributes))
+ return (NULL);
+ vistemplate.visualid = XVisualIDFromVisual(win_attributes.visual);
+ /* MF036
+ vinfo = XGetVisualInfo (dpy, VisualIDMask, &vistemplate, &junk);
+ */
+
+ (void) XTranslateCoordinates (dpy, window, win_attributes.root,
+ -win_attributes.border_width,
+ -win_attributes.border_width,
+ &rx, &ry, &junkwin);
+
+ xright = (dw - rx - win_attributes.border_width * 2 -
+ win_attributes.width);
+ ybelow = (dh - ry - win_attributes.border_width * 2 -
+ win_attributes.height);
+
+ /* compute size in appropriate units */
+ status = XGetWMNormalHints (dpy, window, &hints, &longjunk);
+ op = geometry;
+
+ if (status && (hints.flags & PResizeInc) &&
+ hints.width_inc != 0 && hints.height_inc != 0) {
+
+ if (hints.flags & (PBaseSize|PMinSize)) {
+ if (hints.flags & PBaseSize) {
+ win_attributes.width -= hints.base_width;
+ win_attributes.height -= hints.base_height;
+ } else {
+ /* ICCCM says MinSize is default for BaseSize */
+ win_attributes.width -= hints.min_width;
+ win_attributes.height -= hints.min_height;
+ }
+ }
+ sprintf (op, "%dx%d",
+ win_attributes.width / hints.width_inc,
+ win_attributes.height / hints.height_inc);
+ } else
+ sprintf (op, "%dx%d", win_attributes.width, win_attributes.height);
+
+ while (*op)
+ op++;
+
+ if (!(hints.flags&PWinGravity))
+ hints.win_gravity = NorthWestGravity; /* per ICCCM */
+
+ /* Find our window manager frame, if any. */
+ wmframe = window;
+ while (True) {
+ Window root, parent;
+ Window *childlist;
+ unsigned int ujunk;
+
+ status = XQueryTree (dpy, wmframe, &root, &parent, &childlist, &ujunk);
+ if (parent == root || !parent || !status)
+ break;
+ wmframe = parent;
+ if (status && childlist)
+ XFree ((char *)childlist);
+ }
+
+ if (wmframe != window) {
+ /* WM reparented, so find edges of the frame. This only works for
+ * ICCCM-compliant WMs, and then only if the window has corner gravity.
+ * We would need to know the original width of the window to correctly
+ * handle the other gravities.
+ */
+ XWindowAttributes frame_attr;
+ if (!XGetWindowAttributes (dpy, wmframe, &frame_attr))
+ return (NULL);
+
+ switch (hints.win_gravity) {
+ case NorthWestGravity:
+ case SouthWestGravity:
+ case NorthEastGravity:
+ case SouthEastGravity:
+ case WestGravity:
+ rx = frame_attr.x;
+ }
+ switch (hints.win_gravity) {
+ case NorthWestGravity:
+ case SouthWestGravity:
+ case NorthEastGravity:
+ case SouthEastGravity:
+ case EastGravity:
+ xright = dw - frame_attr.x - frame_attr.width -
+ 2 * frame_attr.border_width;
+ }
+ switch (hints.win_gravity) {
+ case NorthWestGravity: case SouthWestGravity:
+ case NorthEastGravity: case SouthEastGravity:
+ case NorthGravity:
+ ry = frame_attr.y;
+ }
+ switch (hints.win_gravity) {
+ case NorthWestGravity: case SouthWestGravity:
+ case NorthEastGravity: case SouthEastGravity:
+ case SouthGravity:
+ ybelow = dh - frame_attr.y - frame_attr.height -
+ 2 * frame_attr.border_width;
+ }
+ }
+
+ /* If edge gravity, offer a corner on that edge (because the application
+ * programmer cares about that edge), otherwise offer upper left unless
+ * some other corner is close to an edge of the screen. (For corner
+ * gravity, assume gravity was set by XWMGeometry. For CenterGravity,
+ * it doesn't matter.)
+ */
+ if (hints.win_gravity == EastGravity ||
+ (abs(xright) <= 100 && abs(xright) < abs(rx) &&
+ hints.win_gravity != WestGravity))
+ showright = 1;
+
+ if (hints.win_gravity == SouthGravity ||
+ (abs(ybelow) <= 100 && abs(ybelow) < abs(ry) &&
+ hints.win_gravity != NorthGravity))
+ showbelow = 1;
+
+ if (showright && !origin)
+ sprintf (op, "-%d", xright);
+ else
+ sprintf (op, "+%d", rx);
+ while (*op)
+ op++;
+
+ if (showbelow && !origin)
+ sprintf (op, "-%d", ybelow);
+ else
+ sprintf (op, "+%d", ry);
+
+ return (geometry);
+}
diff --git a/vendor/x11iraf/obm/gterm.c b/vendor/x11iraf/obm/gterm.c
new file mode 100644
index 00000000..71856353
--- /dev/null
+++ b/vendor/x11iraf/obm/gterm.c
@@ -0,0 +1,4407 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+#include "widget.h"
+
+/*
+ * Gterm-Image widget class (a subclass of Widget).
+ * -------------------------------------------------
+ * The gterm-image widget is a general 2D graphics-imaging widget providing
+ * a wide range of facilities for drawing graphics and text, for image
+ * display, and for graphics interaction. Normally the client communicates
+ * directly with the Gterm widget to draw graphics, download image data,
+ * and so on, using some communications protocol outside the domain of the
+ * object manager. Nonetheless so far as possible the facilities of the Gterm
+ * widget have also been made available to GUI code via the commands listed
+ * here.
+ *
+ * The gterm class uses a special OBM callback known as OBMCB_setGterm.
+ * A client application can use this to post a procedure to be called when
+ * a gterm widget receives the setGterm command. The calling sequence for
+ * the setGterm callback is as follows:
+ *
+ * setgterm (client_data, gterm_widget)
+ *
+ * The purpose of this callback is to tell the client which gterm widget is
+ * the "active" gterm widget. This is used by clients which only support
+ * one active Gterm widget, i.e., which can only direct graphics output to
+ * one Gterm widget at a time.
+ *
+ * The messages or commands that can be sent to the Gterm widget by GUI
+ * code follow.
+ *
+ * General commands:
+ *
+ * setGterm [arg [arg ...]] # make widget the active Gterm
+ *
+ * activate
+ * deactivate
+ * addCallback procedure-name callback-type
+ * deleteCallback procedure-name
+ * reset
+ * flush
+ *
+ * setCursorPos x y [raster]
+ * getCursorPos x y
+ * setCursorType cursortype
+ * bell
+ *
+ * Graphics drawing commands:
+ *
+ * setRaster raster
+ * raster = getRaster [raster]
+ *
+ * setLogRes width height
+ * getLogRes width height
+ * setPhysRes width height
+ * getPhysRes width height
+ * setTextRes rows cols
+ * setDataLevel level
+ * setLineWidth width
+ * setLineStyle style
+ * setColorIndex index
+ * setFillType filltype
+ *
+ * clearScreen
+ * drawPolyline vector
+ * drawPolymarker vector
+ * drawPolygon vector
+ * drawMarker type x y xsize ysize [rotangle]
+ *
+ * drawAlphaText x y text
+ * width = getAlphaTextSize [string [width [height [base]]]]
+ * startDialog
+ * endDialog
+ * eraseDialog
+ * drawDialogText x y text
+ *width = getDialogTextSize [string [width [height [base]]]]
+ *
+ * The coordinates used in the graphics drawing commands are logical
+ * coordinates as defined by setLogRes, in the coordinate system of the
+ * reference drawing raster as defined by setRaster. The default reference
+ * raster is raster zero, the widget's window. Vectors are specified as
+ * a list of points, e.g., { {x y} {x y} ... }.
+ *
+ * Imaging commands:
+ *
+ * rasterInit
+ * assignRaster raster drawable
+ * createRaster raster width height [type [depth]]
+ * destroyRaster raster
+ * exists = queryRaster raster [width [height [type [depth]]]]
+ * raster = nextRaster
+ * n = activeRasters
+ *
+ * setPixel raster x y value
+ * value = getPixel raster x y
+ * writePixels raster pixels encoding x1 y1 nx ny [bias]
+ * pixels = readPixels raster encoding x1 y1 nx ny [bias]
+ * refreshPixels raster ct x1 y1 nx ny
+ * setPixels raster color [ct x1 y1 nx ny [rop]]
+ * extractPixmap pixmap src [x y [width height]]
+ * insertPixmap pixmap dst [x y [width height]]
+ *
+ * colormap = nextColormap
+ * freeColormap colormap
+ * writeColormap colormap colors [offset]
+ * ncolors = readColormap colormap colors [offset [ncolors]]
+ * loadColormap colormap offset scale
+ * pixel = clientPixel gterm_pixel
+ * bias = getBias [nelem [maxelem]]
+ *
+ * initMappings
+ * mapping = nextMapping
+ * freeMapping mapping
+ * raiseMapping mapping [reference]
+ * lowerMapping mapping [reference]
+ * enableMapping mapping [refresh]
+ * disableMapping mapping [erase]
+ * active = activeMapping mapping
+ * refreshMapping mapping
+ *
+ * copyRaster rop src st sx sy snx sny dst dt dx dy dnx dny
+ * setMapping mapping rop
+ * src st sx sy snx sny dst dt dx dy dnx dny
+ * getMapping mapping rop
+ * src st sx sy snx sny dst dt dx dy dnx dny
+ *
+ * raster = selectRaster dras dt dx dy rt rx ry [map]
+ * unmapPixel sx sy raster rx ry [rz]
+ *
+ * flip mapping axis [axis...]
+ *
+ * Pixel arrays are long strings consisting either of a sequence of numeric
+ * pixel values separated by whitespace (space or newline), or a hex encoded
+ * sequence of bytes (1 or 2 hex digits per 8 bit pixel). Hex encoded pixel
+ * arrays may optionally be compressed using a simple run length encoding
+ # scheme. Colors are specified as a list of RGB triplets, e.g., { {R G B}
+ # {R G B} ... }.
+ *
+ * Refer to the documentation for the Gterm widget for a detailed description
+ * of rasters, mappings, and colormaps.
+ *
+ * Markers:
+ *
+ * createMarker name [attribute-list]
+ * markerInit
+ *
+ * New markers may be created with createMarker. Once created, a marker
+ * functions under the Object Manager as a named object of class "marker".
+ * Refer to the marker class for a description of the commands defined for
+ * a marker.
+ */
+
+#define MAX_COLORS 256
+#define MAX_POLYPTS 4096
+#define FIRST_COLOR 10
+#define CB_Input 1
+#define CB_Resize 2
+#define CB_Reset 3
+
+/* Gterm class instance descriptor. */
+struct gtermPrivate {
+ ObmCallback callback_list;
+ int colormap;
+ float offset, scale;
+};
+
+typedef struct gtermPrivate *GtermPrivate;
+
+struct gtermObject {
+ struct obmObjectCore core;
+ struct widgetPrivate widget;
+ struct gtermPrivate gterm;
+};
+
+typedef struct gtermObject *GtermObject;
+
+/* Gterm class class record private data. */
+typedef struct {
+ /* standard MsgContext fields. */
+ Tcl_Interp *tcl; /* class interpreter */
+ ObmObject object[MAX_LEVELS]; /* object which received last message */
+ int level;
+
+ /* Gterm specific fields. */
+ /* (none) */
+} gtermClassData, *GtermClassData;
+
+
+void GtermDestroy();
+void GtermClassDestroy();
+ObmObject GtermCreate();
+
+static int gtermActivate(), gtermActiveMapping(), gtermActiveRasters();
+static int gtermAddCallback(), gtermDeleteCallback();
+static int gtermAssignRaster(), gtermBell(), gtermGetBias();
+static int gtermClearScreen(), gtermClientPixel(), gtermCopyRaster();
+static int gtermCreateMarker(), gtermCreateRaster(), gtermDeactivate();
+static int gtermDestroyRaster(), gtermDisableMapping(), gtermDrawAlphaText();
+static int gtermDrawDialogText(), gtermDrawMarker(), gtermDrawPolygon();
+static int gtermDrawPolyline(), gtermDrawPolymarker(), gtermEnableMapping();
+static int gtermEndDialog(), gtermEraseDialog(), gtermExtractPixmap();
+static int gtermFlip(), gtermFlush(), gtermFreeColormap();
+static int gtermFreeMapping(), gtermRaiseMapping(), gtermLowerMapping();
+static int gtermGetAlphaTextSize(), gtermGetCursorPos();
+static int gtermGetDialogTextSize(), gtermGetLogRes(), gtermGetMapping();
+static int gtermGetPhysRes(), gtermGetPixel(), gtermGetRaster();
+static int gtermInitMappings(), gtermInsertPixmap(), gtermLoadColormap();
+static int gtermMarkerInit(), gtermNextColormap(), gtermNextMapping();
+static int gtermNextRaster(), gtermQueryRaster(), gtermRasterInit();
+static int gtermReadColormap(), gtermReadPixels(), gtermRefreshMapping();
+static int gtermRefreshPixels(), gtermReset(), gtermSelectRaster();
+static int gtermSetColorIndex(), gtermSetCursorPos(), gtermSetCursorType();
+static int gtermSetDataLevel(), gtermSetFillType(), gtermSetGterm();
+static int gtermSetLineStyle(), gtermSetLineWidth(), gtermSetLogRes();
+static int gtermSetMapping(), gtermSetPhysRes(), gtermSetPixel();
+static int gtermSetPixels(), gtermSetRaster(), gtermSetTextRes();
+static int gtermStartDialog(), gtermUnmapPixel(), gtermWriteColormap();
+static int gtermWritePixels();
+
+static void gtermInputCallback();
+static void gtermResizeCallback(), gtermResetCallback();
+static void get_mapping(), put_mapping();
+static XPoint *get_points();
+extern double strtod(), atof();
+
+
+/* GtermClassInit -- Initialize the class record for the gterm widget class.
+ */
+void
+GtermClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register GtermClassData gcd;
+ register Tcl_Interp *tcl;
+ register ClientData c_gcd;
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = GtermClassDestroy;
+ classrec->Create = (ObmFunc) GtermCreate;
+ classrec->Destroy = GtermDestroy;
+ classrec->Evaluate = WidgetEvaluate;
+
+ /* The gterm widget subclass has its own command set hence has its
+ * own interpreter. The widget will respond both to all the commands
+ * defined here, and to all the commands implemented by the base
+ * Widget class.
+ */
+ if (!classrec->class_data) {
+ gcd = (GtermClassData) XtCalloc (1, sizeof (gtermClassData));
+ gcd->tcl = tcl = Tcl_CreateInterp();
+ classrec->class_data = (XtPointer) gcd;
+ c_gcd = (ClientData)gcd;
+ gcd->level = 0;
+
+ Tcl_CreateCommand (tcl,
+ "activate", gtermActivate, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "activeMapping", gtermActiveMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "activeRasters", gtermActiveRasters, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "addCallback", gtermAddCallback, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteCallback", gtermDeleteCallback, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "assignRaster", gtermAssignRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "bell", gtermBell, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "clearScreen", gtermClearScreen, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "clientPixel", gtermClientPixel, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "copyRaster", gtermCopyRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "createMarker", gtermCreateMarker, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "createRaster", gtermCreateRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "deactivate", gtermDeactivate, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "destroyRaster", gtermDestroyRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "disableMapping", gtermDisableMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawAlphaText", gtermDrawAlphaText, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawDialogText", gtermDrawDialogText, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawMarker", gtermDrawMarker, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawPolygon", gtermDrawPolygon, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawPolyline", gtermDrawPolyline, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "drawPolymarker", gtermDrawPolymarker, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "enableMapping", gtermEnableMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "endDialog", gtermEndDialog, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "eraseDialog", gtermEraseDialog, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "extractPixmap", gtermExtractPixmap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "flip", gtermFlip, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "flush", gtermFlush, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "freeColormap", gtermFreeColormap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "freeMapping", gtermFreeMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "raiseMapping", gtermRaiseMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "lowerMapping", gtermLowerMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getAlphaTextSize", gtermGetAlphaTextSize, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getBias", gtermGetBias, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getCursorPos", gtermGetCursorPos, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getDialogTextSize", gtermGetDialogTextSize, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getLogRes", gtermGetLogRes, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getMapping", gtermGetMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getPhysRes", gtermGetPhysRes, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getPixel", gtermGetPixel, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getRaster", gtermGetRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "initMappings", gtermInitMappings, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "insertPixmap", gtermInsertPixmap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "loadColormap", gtermLoadColormap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "markerInit", gtermMarkerInit, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "nextColormap", gtermNextColormap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "nextMapping", gtermNextMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "nextRaster", gtermNextRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "queryRaster", gtermQueryRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "rasterInit", gtermRasterInit, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "readColormap", gtermReadColormap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "readPixels", gtermReadPixels, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "refreshMapping", gtermRefreshMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "refreshPixels", gtermRefreshPixels, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "reset", gtermReset, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "selectRaster", gtermSelectRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setColorIndex", gtermSetColorIndex, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setCursorPos", gtermSetCursorPos, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setCursorType", gtermSetCursorType, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setDataLevel", gtermSetDataLevel, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setFillType", gtermSetFillType, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setGterm", gtermSetGterm, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setLineStyle", gtermSetLineStyle, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setLineWidth", gtermSetLineWidth, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setLogRes", gtermSetLogRes, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setMapping", gtermSetMapping, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setPhysRes", gtermSetPhysRes, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setPixel", gtermSetPixel, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setPixels", gtermSetPixels, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setRaster", gtermSetRaster, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setTextRes", gtermSetTextRes, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "startDialog", gtermStartDialog, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "unmapPixel", gtermUnmapPixel, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "writeColormap", gtermWriteColormap, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "writePixels", gtermWritePixels, c_gcd, NULL);
+ }
+}
+
+
+/* GtermClassDestroy -- Custom destroy procedure for the widget class.
+ */
+void
+GtermClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register GtermClassData gcd = (GtermClassData) classrec->class_data;
+
+ if (gcd) {
+ if (gcd->tcl)
+ Tcl_DeleteInterp (gcd->tcl);
+ XtFree ((char *)gcd);
+ classrec->class_data = NULL;
+ }
+}
+
+
+/* GtermCreate -- Create an instance of a gterm object.
+ */
+ObmObject
+GtermCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register GtermObject obj;
+ Widget w, pw;
+
+ obj = (GtermObject) WidgetCreate (obm, name,
+ classrec, parent, args, nargs);
+ if (obj == NULL)
+ return (NULL);
+
+ obj = (GtermObject) XtRealloc ((char *)obj, sizeof(struct gtermObject));
+ if (obj == NULL)
+ return (NULL);
+
+ /* Initialize GtermPrivate instance structure. */
+ obj->gterm.callback_list = NULL;
+ obj->gterm.colormap = 0;
+ obj->gterm.offset = 0.5;
+ obj->gterm.scale = 1.0;
+
+ return ((ObmObject) obj);
+}
+
+
+/* GtermDestroy -- Destroy an instance of a gterm object.
+ */
+void
+GtermDestroy (object)
+ObmObject object;
+{
+ GtermObject obj = (GtermObject) object;
+ ObjClassRec classrec = obj->core.classrec;
+ register GtermClassData gcd = (GtermClassData) classrec->class_data;
+ register ObmCallback cb, cb_next;
+ ObmContext obm = obj->widget.obm;
+ Widget w = obj->widget.w;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ /* Invoke any posted setGterm callbacks. This is not completely
+ * correct; in principle we should call the setGterm callback only
+ * if the active gterm widget is destroyed.
+ */
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & OBMCB_setGterm) && cb->u.fcn)
+ (*cb->u.fcn) (cb->client_data, NULL);
+
+ /* Free any gterm callback descriptors. */
+ for (cb = obj->gterm.callback_list; cb; cb = cb_next) {
+ cb_next = cb->next;
+
+ /* Delete the widget level callback. */
+ switch (cb->callback_type) {
+ case CB_Input:
+ GtDeleteInputProc (w, gtermInputCallback, (XtPointer)cb);
+ break;
+ case CB_Resize:
+ GtDeleteResizeProc (w, gtermResizeCallback, (XtPointer)cb);
+ break;
+ case CB_Reset:
+ GtDeleteResetProc (w, gtermResetCallback, (XtPointer)cb);
+ break;
+ }
+
+ XtFree ((char *)cb);
+ }
+
+ WidgetDestroy (object);
+}
+
+
+/*
+ * GTERM class commands.
+ * -----------------------
+ */
+
+
+/* SetGterm -- Set the active Gterm widget. Call any OBMCB_setGterm callbacks
+ * registered by the client code, passing the client the Xt Widget handle of
+ * the active gterm widget.
+ *
+ * Usage: setGterm [arg [arg ...]]
+ *
+ * This feature may be used during GUI execution to identify the currently
+ * active gterm widget to the client, or during startup to pass the Widget id
+ * to the client code so that it can talk directly to the gterm widget.
+ */
+static int
+gtermSetGterm (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register GtermClassData gcd = (GtermClassData) msg;
+ GtermObject obj = (GtermObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmCallback cb;
+ ObmContext obm = wp->obm;
+ char *message;
+
+ message = (argc > 1) ? Tcl_Concat (argc-1, &argv[1]) : NULL;
+
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & OBMCB_setGterm) && cb->u.fcn)
+ (*cb->u.fcn) (cb->client_data, wp->w, message);
+
+ if (message)
+ free ((char *)message);
+
+ return (TCL_OK);
+}
+
+
+/* Activate -- Activate the gterm widget. This causes the next GIN mode
+ * setCursorType to warp the pointer into the gterm window.
+ *
+ * Usage: activate
+ */
+static int
+gtermActivate (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtActivate (w);
+ return (TCL_OK);
+}
+
+
+/* Deactivate -- Deactivate the gterm widget. If the cursor has been warped
+ * into the window by a previous activate/setCursorType GIN mode, this causes
+ * the cursor to be warped back to where it was previously.
+ *
+ * Usage: deactivate
+ */
+static int
+gtermDeactivate (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtDeactivate (w);
+ return (TCL_OK);
+}
+
+
+/* Reset -- Reset the gterm widget. This causes a number of state variables
+ * affecting graphics drawing options to be set to their default values.
+ *
+ * Usage: reset
+ */
+static int
+gtermReset (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtReset (w);
+ return (TCL_OK);
+}
+
+
+/* Flush -- Flush any graphics output and synchronize the state of the widget
+ * with what is shown on the display.
+ *
+ * Usage: flush
+ *
+ * The gterm widget uses XLIB, which buffers graphics drawing commands and
+ * automatically sends them to the X server when 1) the buffer fills,
+ * 2) input is requested from the server. Such buffering of data is necessary
+ * for efficient operation and it should rarely be necessary to explicitly
+ * flush graphics output since XLIB does this automatically in most cases.
+ * An example of when explicitly flushing the ouptut might be necessary is in
+ * cases where smooth animation is desired and drawing the graphics in batches
+ * could cause the display to appear "jerky".
+ */
+static int
+gtermFlush (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtFlush (w);
+ return (TCL_OK);
+}
+
+
+/* AddCallback -- Post a callback for a Gterm widget event.
+ *
+ * Usage: addCallback procedure-name [callback-type]
+ *
+ * The recognized Gterm callbacks are
+ *
+ * input Called when the graphics-input action is invoked in
+ * a translation table. The default Gterm translation
+ * table invokes this action when a KeyPress event occurs
+ * in the Gterm window.
+ *
+ * Callback: widget-name input-type event-data
+ *
+ * resize Called when the gterm window is resized.
+ *
+ * Callback: widget-name width height
+ *
+ * reset Called when the "reset" action is invoked.
+ *
+ * Callback: widget-name
+ *
+ * If no callback is specified the default is "input".
+ *
+ * Note that in GUI code one can also use the translation table to directly
+ * invoke GUI procedures without need to use the Gterm input mechanism. This
+ * is more flexible but we support the Gterm input callback here for
+ * applications that use the default translations.
+ */
+static int
+gtermAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register GtermPrivate gp = &obj->gterm;
+ register Widget w = wp->w;
+ char *userproc, *callback_type;
+ ObmCallback cb, new;
+ int type;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ userproc = argv[1];
+ callback_type = (argc > 2) ? argv[2] : "input";
+
+ if (strcmp (callback_type, "input") == 0)
+ type = CB_Input;
+ else if (strcmp (callback_type, "resize") == 0)
+ type = CB_Resize;
+ else if (strcmp (callback_type, "reset") == 0)
+ type = CB_Reset;
+ else
+ return (TCL_ERROR);
+
+ /* Initialize callback descriptor. */
+ new = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ new->u.obj = (ObmObject) obj;
+ new->callback_type = type;
+ strncpy (new->name, userproc, SZ_NAME);
+
+ /* Append descriptor to callback list for widget. */
+ for (cb = gp->callback_list; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ gp->callback_list = new;
+
+ /* Register the callback with the widget. */
+ switch (type) {
+ case CB_Input:
+ GtPostInputProc (w, gtermInputCallback, (XtPointer)new);
+ break;
+ case CB_Resize:
+ GtPostResizeProc (w, gtermResizeCallback, (XtPointer)new);
+ break;
+ case CB_Reset:
+ GtPostResetProc (w, gtermResetCallback, (XtPointer)new);
+ break;
+ }
+
+ return (TCL_OK);
+}
+
+
+/* DeleteCallback -- Delete a gterm callback.
+ *
+ * Usage: deleteCallback procedure
+ */
+static int
+gtermDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register GtermPrivate gp = &obj->gterm;
+ register ObmCallback cb, prev;
+ Widget w = obj->widget.w;
+ char *procedure;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ procedure = argv[1];
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=gp->callback_list; cb; prev=cb, cb=cb->next)
+ if (strcmp (cb->name, procedure) == 0) {
+ /* Delete the widget level callback. */
+ switch (cb->callback_type) {
+ case CB_Input:
+ GtDeleteInputProc (w, gtermInputCallback, (XtPointer)cb);
+ break;
+ case CB_Resize:
+ GtDeleteResizeProc (w, gtermResizeCallback, (XtPointer)cb);
+ break;
+ case CB_Reset:
+ GtDeleteResetProc (w, gtermResetCallback, (XtPointer)cb);
+ break;
+ }
+ if (prev)
+ prev->next = cb->next;
+ else
+ gp->callback_list = cb->next;
+ XtFree ((char *)cb);
+ break;
+ }
+
+ return (TCL_OK);
+}
+
+
+/* gtermInputCallback -- Low level callback procedure, called by the Gterm
+ * widget when an input event occurs.
+ *
+ * Callback: userproc widget-name input-type x y data
+ * Example: userproc widget-name keyPress x y {a shift}
+ *
+ * where input-type is keyPress, keyRelease, buttonPress, or buttonRelease,
+ * and data depends upon the type of input event. data is a list of strings
+ * delimited by braces. The first string is the key or button pressed and
+ * the following strings give the state of any modifier keys ("shift",
+ * "control" and so on).
+ */
+static void
+gtermInputCallback (cb, w, event)
+ObmCallback cb;
+Widget w;
+XEvent *event;
+{
+ GtermObject obj = (GtermObject) cb->u.obj;
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ char s_x[SZ_NUMBER], s_y[SZ_NUMBER];
+ char message_data[SZ_LINE];
+ char *event_type;
+ int status;
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyPressedEvent *ev = (XKeyPressedEvent *) event;
+ register char *ip, *op = message_data;
+ char buf[SZ_MESSAGE];
+ int n;
+
+ if (event->type == KeyPress)
+ event_type = "keyPress";
+ else
+ event_type = "keyRelease";
+
+ sprintf (s_x, "%d", ev->x);
+ sprintf (s_y, "%d", ev->y);
+
+ if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) {
+ for (ip=buf; --n >= 0; )
+ if (*ip <= ' ') {
+ *op++ = '^';
+ *op++ = *ip++ + 'A' - 1;
+ } else if (isprint (*ip)) {
+ *op++ = *ip++;
+ } else
+ ip++;
+ } else {
+ /* This case occurs when only a modifier is typed. */
+ for (ip = "??"; *op++ = *ip++; )
+ ;
+ }
+ *op++ = ' ';
+ op = widgetEventState (op, ev->state);
+ while (op > message_data && isspace (*(op-1)))
+ --op;
+ *op = '\0';
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonPressedEvent *ev = (XButtonPressedEvent *) event;
+ register char *op = message_data;
+
+ if (event->type == KeyPress)
+ event_type = "buttonPress";
+ else
+ event_type = "buttonRelease";
+
+ sprintf (s_x, "%d", ev->x);
+ sprintf (s_y, "%d", ev->y);
+
+ sprintf (op, "%d ", ev->button);
+ while (*op)
+ op++;
+ *op++ = ' ';
+ op = widgetEventState (op, ev->state);
+ while (op > message_data && isspace (*(op-1)))
+ --op;
+ *op = '\0';
+ }
+ break;
+
+ default:
+ strcpy (message_data, "unknown none");
+ }
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ event_type, " ",
+ s_x, " ",
+ s_y, " ",
+ "{", message_data, "}",
+ NULL);
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+}
+
+
+/* gtermResizeCallback -- Low level callback procedure, called by the Gterm
+ * widget when a resize event occurs.
+ *
+ * Callback: userproc widget-name width height
+ */
+static void
+gtermResizeCallback (cb, w)
+ObmCallback cb;
+Widget w;
+{
+ GtermObject obj = (GtermObject) cb->u.obj;
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ int rtype, width, height, depth, status;
+ char s_width[SZ_NUMBER], s_height[SZ_NUMBER];
+
+ GtQueryRaster (wp->w, 0, &rtype, &width, &height, &depth);
+ sprintf (s_width, "%d", width);
+ sprintf (s_height, "%d", height);
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ s_width, " ",
+ s_height, " ",
+ NULL);
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+}
+
+
+/* gtermResetCallback -- Low level callback procedure, called by the Gterm
+ * widget when a reset event occurs.
+ *
+ * Callback: userproc
+ */
+static void
+gtermResetCallback (cb, w)
+ObmCallback cb;
+Widget w;
+{
+ GtermObject obj = (GtermObject) cb->u.obj;
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ int status;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ NULL);
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+}
+
+
+/* SetCursorPos -- Warp the cursor (pointer) to the given coordinates. This
+ * is a graphics drawing command and if no raster number is specified the
+ * current reference drawing raster, as set with setRaster, defines the
+ * coordinate system.
+ *
+ * Usage: setCursorPos x y [raster]
+ *
+ * A raster number may optionally given to define the raster coordinate system
+ * to be used. raster=0 yields screen coordinates.
+ */
+static int
+gtermSetCursorPos (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ int raster, sv_raster, x, y;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ x = (int) atof (argv[1]);
+ y = (int) atof (argv[2]);
+ raster = (argc > 3) ? atoi (argv[3]) : -1;
+
+ if (raster >= 0) {
+ sv_raster = GtGetRaster (wp->w);
+ if (raster != sv_raster)
+ GtSetRaster (wp->w, raster);
+ }
+
+ GtSetCursorPos (wp->w, x, y);
+
+ if (raster >= 0)
+ if (raster != sv_raster)
+ GtSetRaster (wp->w, sv_raster);
+
+ return (TCL_OK);
+}
+
+
+/* GetCursorPos -- Get the cursor position (raster 0 or screen coordinates).
+ *
+ * Usage: getCursorPos x y
+ */
+static int
+gtermGetCursorPos (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ char *xout, *yout, buf[SZ_NUMBER];
+ int x, y;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ xout = argv[1];
+ yout = argv[2];
+
+ GtGetCursorPos (wp->w, &x, &y);
+ sprintf (buf, "%d", x);
+ Tcl_SetVar (obm->tcl, xout, buf, 0);
+ sprintf (buf, "%d", y);
+ Tcl_SetVar (obm->tcl, yout, buf, 0);
+
+ return (TCL_OK);
+}
+
+
+/* setCursorType -- Set the cursor type.
+ *
+ * Usage: setCursorType cursor-type
+ *
+ * idle default cursor
+ *
+ * busy busy cursor, e.g, when program is busy
+ *
+ * ginMode graphics input mode cursor, set when program is
+ * waiting for graphics input
+ */
+static int
+gtermSetCursorType (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char *cursor_type;
+ int type;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ cursor_type = argv[1];
+ if (strcmp (cursor_type, "idle") == 0)
+ type = GtIdleCursor;
+ else if (strcmp (cursor_type, "busy") == 0)
+ type = GtBusyCursor;
+ else if (strcmp (cursor_type, "ginMode") == 0)
+ type = GtGinmodeCursor;
+ else
+ return (TCL_ERROR);
+
+ GtSetCursorType (w, type);
+
+ return (TCL_OK);
+}
+
+
+/* Bell -- Gterm widget sound output.
+ *
+ * Usage: bell
+ */
+static int
+gtermBell (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtBell (w);
+ return (TCL_OK);
+}
+
+
+/* setRaster -- Set the number of the raster to be used to define the drawing
+ * context (e.g. coordinate system) for graphics and text drawing functions.
+ *
+ * Usage: setRaster raster-number
+ */
+static int
+gtermSetRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int raster;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ GtSetRaster (w, raster);
+
+ return (TCL_OK);
+}
+
+
+/* getRaster -- Get the number of the raster which defines the drawing
+ * context, as set in the last setRaster call.
+ *
+ * Usage: raster = getRaster [raster]
+ *
+ * If the name of a variable is given the raster number will be stored
+ * directly in that variable.
+ */
+static int
+gtermGetRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char buf[SZ_NUMBER], *raster_var;
+ int raster;
+
+ raster = GtGetRaster (w);
+ sprintf (buf, "%d", raster);
+
+ if (argc == 2)
+ Tcl_SetVar (obm->tcl, argv[1], buf, 0);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* setLogRes -- Set the logical resolution of the graphics drawing surface
+ * in pixels. This defines the range of coordinates in drawing commands
+ * for drawing graphics such as lines, areas, or text.
+ *
+ * Usage: setLogRes width height
+ *
+ * Note that this has nothing to do with imaging and the resolution of an
+ * image raster. The logical resolution of the graphics system is independent
+ * of the physical resolution of the drawing surface.
+ */
+static int
+gtermSetLogRes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int width, height;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ width = atoi (argv[1]);
+ height = atoi (argv[2]);
+ GtSetLogRes (w, width, height);
+
+ return (TCL_OK);
+}
+
+
+/* getLogRes -- Get the logical resolution of the graphics drawing surface
+ * in pixels.
+ *
+ * Usage: getLogRes width height
+ */
+static int
+gtermGetLogRes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char *s_width, *s_height;
+ char buf[SZ_NUMBER];
+ int width, height;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ s_width = argv[1];
+ s_height = argv[2];
+ GtGetLogRes (w, &width, &height);
+
+ sprintf (buf, "%d", width);
+ Tcl_SetVar (obm->tcl, s_width, buf, 0);
+ sprintf (buf, "%d", height);
+ Tcl_SetVar (obm->tcl, s_height, buf, 0);
+
+ return (TCL_OK);
+}
+
+
+/* setPhysRes -- Set the physical resolution of the graphics drawing surface
+ * in pixels. This represents an attempt to resize the graphics window to
+ * provide the requested resolution, i.e., to the given size width*height.
+ *
+ * Usage: setPhysRes width height [raster]
+ *
+ * This function is equivalent to a createRaster request for the indicated
+ * raster. The default raster is the current drawing raster.
+ */
+static int
+gtermSetPhysRes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int raster, width, height;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ width = atoi (argv[1]);
+ height = atoi (argv[2]);
+ raster = (argc > 3) ? atoi(argv[3]) : GtGetRaster(w);
+ GtSetPhysRes (w, raster, width, height);
+
+ return (TCL_OK);
+}
+
+
+/* getPhysRes -- Get the physical resolution of the graphics drawing surface
+ * in pixels.
+ *
+ * Usage: raster = getPhysRes width height [raster]
+ *
+ * If no raster number is specified the dimensions of the current drawing
+ * raster are returned.
+ */
+static int
+gtermGetPhysRes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char *s_width, *s_height;
+ int raster, width, height;
+ char buf[SZ_NUMBER];
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ s_width = argv[1];
+ s_height = argv[2];
+ raster = (argc > 3) ? atoi(argv[3]) : GtGetRaster(w);
+ GtGetPhysRes (w, raster, &width, &height);
+
+ sprintf (buf, "%d", width);
+ Tcl_SetVar (obm->tcl, s_width, buf, 0);
+ sprintf (buf, "%d", height);
+ Tcl_SetVar (obm->tcl, s_height, buf, 0);
+
+ sprintf (buf, "%d", raster);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* setTextRes -- Set the resolution of the graphics drawing surface in
+ * characters (e.g., 80x35).
+ *
+ * Usage: setTextRes rows cols
+ *
+ * When drawing text the widget will space characters to achieve the desired
+ * resolution. When the drawing window is resized the widget will use this
+ * number to select the best font.
+ */
+static int
+gtermSetTextRes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int rows, cols;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ rows = atoi (argv[1]);
+ cols = atoi (argv[2]);
+ GtSetTextRes (w, rows, cols);
+
+ return (TCL_OK);
+}
+
+
+/* setDataLevel -- Set the logical drawing function used when drawing graphics
+ * or text.
+ *
+ * Usage: setDataLevel level
+ *
+ * The recognized data levels for drawing are "set", "clear", and "invert".
+ * Once set the data level remains in effect until the next clearScreen or
+ * reset.
+ */
+static int
+gtermSetDataLevel (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int level;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if ((level = dataLevelType (argv[1])) < 0)
+ return (TCL_ERROR);
+ GtSetDataLevel (w, level);
+
+ return (TCL_OK);
+}
+
+
+/* setLineWidth -- Set the line width for drawing operations.
+ *
+ * Usage: setLineWidth width
+ *
+ * The line width is specified in integer pixels. The value width=0 is
+ * equivalent to width=1 but may permit faster drawing in some cases.
+ * Once set the line width remains in effect until the next clearScreen or
+ * reset.
+ */
+static int
+gtermSetLineWidth (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int width;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if ((width = atoi (argv[1])) < 0)
+ return (TCL_ERROR);
+ GtSetLineWidth (w, width);
+
+ return (TCL_OK);
+}
+
+
+/* setLineStyle -- Set the line style for drawing operations.
+ *
+ * Usage: setLineStyle style
+ *
+ * The line style determines whether a solid or dashed line is drawn. The
+ * recognized line styles are "solid", "dashed", "dotted", dashDot", and
+ * "dash3dot". Once set the line style remains in effect until the next
+ * clearScreen or reset.
+ */
+static int
+gtermSetLineStyle (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int style;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if ((style = lineStyle (argv[1])) < 0)
+ return (TCL_ERROR);
+ GtSetLineStyle (w, style);
+
+ return (TCL_OK);
+}
+
+
+/* setColorIndex -- Set the gterm widget color index for drawing graphics and
+ * text.
+ *
+ * Usage: setColorIndex index
+ *
+ * The color index is an integer in the range 0 to N, where N is the maximum
+ * number of color table entries permitted by the widget. The gterm widget
+ * implements a simple color allocation scheme: color index 0 is the background
+ * color, 1 is the foreground, 2-9 are fixed, statically allocated colors (red,
+ * green, blue, etc.) and color indices 10 and greater are dynamically
+ * allocated private colors allocated at runtime by the application.
+ *
+ * Colors may be specified by number or by one of the names "background"
+ * "foreground", "black", "white", "red", "green", "blue", "cyan", "yellow",
+ * "magenta", "user1", or "user2". These names are aliases for color indices
+ * 0-9 and the actual color may differ from the logical color associated with
+ * the given statically defined color index.
+ *
+ * Once set the drawing color remains in effect until the next clearScreen or
+ * reset.
+ */
+static int
+gtermSetColorIndex (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int color;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if ((color = colorToIndex (argv[1])) < 0)
+ return (TCL_ERROR);
+ GtSetColorIndex (w, color);
+
+ return (TCL_OK);
+}
+
+
+/* setFillType -- Set the type of fill for area-fill drawing operations.
+ *
+ * Usage: setFillType filltype
+ *
+ * The fill type may be "solid" or "outline". Once set the fill type remains
+ * in effect until the next clearScreen or reset.
+ */
+static int
+gtermSetFillType (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int filltype;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if ((filltype = fillType (argv[1])) < 0)
+ return (TCL_ERROR);
+ GtSetFillType (w, filltype);
+
+ return (TCL_OK);
+}
+
+
+/* clearScreen -- Clear the "screen", i.e., window. This action clears the
+ * drawing window and sets a number of drawing state variables to their default
+ * values.
+ *
+ * Usage: clearScreen
+ */
+static int
+gtermClearScreen (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtClearScreen (w);
+ return (TCL_OK);
+}
+
+
+/* drawPolyline -- Draw a polyline.
+ *
+ * Usage: drawPolyline points
+ *
+ * The points vector is a list of points, wherein each point is itself a list
+ * consisting of two elements, the X and Y coordinates of the point. The
+ * coordinate system is the logical coordinate system defined by setLogRes.
+ * All drawing attributes such as the line width, style, color, context raster
+ * if any, and so on will affect the drawing operation.
+ */
+static int
+gtermDrawPolyline (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+ int npoints;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if ((pv = get_points (argv[1], &npoints)) == NULL)
+ return (TCL_ERROR);
+ GtDrawPolyline (w, pv, npoints);
+
+ XtFree ((char *)pv);
+ return (TCL_OK);
+}
+
+
+/* drawPolymarker -- Draw a polymarker, or sequence of points.
+ *
+ * Usage: drawPolymarker points
+ *
+ * The points vector is a list of points, wherein each point is itself a list
+ * consisting of two elements, the X and Y coordinates of the point. The
+ * coordinate system is the logical coordinate system defined by setLogRes.
+ * All drawing attributes such as the line width, style, color, context raster
+ * if any, and so on will affect the drawing operation.
+ */
+static int
+gtermDrawPolymarker (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+ int npoints;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if ((pv = get_points (argv[1], &npoints)) == NULL)
+ return (TCL_ERROR);
+ GtDrawPolymarker (w, pv, npoints);
+
+ XtFree ((char *)pv);
+ return (TCL_OK);
+}
+
+
+/* drawPolygon -- Draw a polygon, or filled area.
+ *
+ * Usage: drawPolygon points
+ *
+ * The points vector is a list of points, wherein each point is itself a list
+ * consisting of two elements, the X and Y coordinates of the point. The
+ * coordinate system is the logical coordinate system defined by setLogRes.
+ * All drawing attributes such as the line width, style, color, context raster
+ * if any, and so on will affect the drawing operation.
+ */
+static int
+gtermDrawPolygon (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+ int npoints;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if ((pv = get_points (argv[1], &npoints)) == NULL)
+ return (TCL_ERROR);
+ GtDrawPolygon (w, pv, npoints);
+
+ XtFree ((char *)pv);
+ return (TCL_OK);
+}
+
+
+/* drawMarker -- Draw a marker.
+ *
+ * Usage: drawMarker type x y xsize ysize [rotangle]
+ *
+ * A marker of the indicated size and type is drawn at the indicated position.
+ * The marker type is one of "box", "circle", "ellipse", and so on.
+ */
+static int
+gtermDrawMarker (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ /* not yet implemented. */
+ return (TCL_ERROR);
+}
+
+
+/* drawAlphaText -- Draw a graphics text string.
+ *
+ * Usage: drawAlphaText x y text
+ *
+ * A text string is drawn at the indicated position using the current alpha
+ * text font. The font is selected based on the window size from a resource
+ * defined list of alpha fonts of different sizes. Alpha text is drawn like
+ * line graphics, i.e., the background is visible through the text. Drawing
+ * attributes such as color, data level, context raster, etc. apply to text
+ * as well as to line graphics. Rotation of text strings is not supported.
+ * The coordinaes X,Y refer to the lower left corner of the text string where
+ * "lower" refers to the baseline of the font. That is, if the text string
+ * is "E", the coordinates x,y refer to the lower left corner of the E.
+ */
+static int
+gtermDrawAlphaText (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char *text;
+ int x, y;
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ x = atoi (argv[1]);
+ y = atoi (argv[2]);
+ text = argv[3];
+ GtDrawAlphaText (w, x, y, text);
+
+ return (TCL_OK);
+}
+
+
+/* getAlphaTextSize -- Get the size in destination drawable pixels of an
+ * alpha text string in terms of the current graphics context.
+ *
+ * Usage: width = getAlphaTextSize [string [width [height [base]]]]
+ *
+ * The size in pixels of the given string is returned in the WIDTH and HEIGHT
+ * output variables. If no string or the null string is given the maximum
+ * width and height of a single character in the font are returned. If a BASE
+ * output variable is given this variable will be set to the Y offset from the
+ * top of the string to the baseline of the characters forming the string.
+ */
+static int
+gtermGetAlphaTextSize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+
+ char *s_width, *s_height, *s_base;
+ int width, height, base;
+ char buf[SZ_NUMBER];
+ char *text;
+
+ if (argc > 1 && (int)strlen(argv[1]) > 0)
+ text = argv[1];
+ else
+ text = NULL;
+
+ s_width = (argc > 2) ? argv[2] : NULL;
+ s_height = (argc > 3) ? argv[3] : NULL;
+ s_base = (argc > 4) ? argv[4] : NULL;
+
+ GtGetAlphaTextSize (w, text, &width, &height, &base);
+ if (s_width) {
+ sprintf (buf, "%d", width);
+ Tcl_SetVar (obm->tcl, s_width, buf, 0);
+ }
+ if (s_height) {
+ sprintf (buf, "%d", height);
+ Tcl_SetVar (obm->tcl, s_height, buf, 0);
+ }
+ if (s_base) {
+ sprintf (buf, "%d", base);
+ Tcl_SetVar (obm->tcl, s_base, buf, 0);
+ }
+
+ sprintf (buf, "%d", width);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* startDialog -- Activate the dialog area for dialog text drawing.
+ *
+ * Usage: startDialog
+ *
+ * Dialog text is text which is drawn into the dialog area at the bottom of
+ * the gterm window. Dialog text is transient and is not a permanent part of
+ * the graphics being drawn. Dialog text is normally used to interact with
+ * the user or to display messages during program operation, without affecting
+ * the graphics being drawn.
+ *
+ * startDialog is called to prepare the dialog area and initialize dialog
+ * text mode, prior to drawing dialog text with drawDialogText.
+ */
+static int
+gtermStartDialog (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+
+ GtStartDialog (w);
+ return (TCL_OK);
+}
+
+
+/* endDialog -- Deactivate the dialog area used for dialog text drawing.
+ *
+ * Usage: endDialog
+ *
+ * endDialog is called when one is finished drawing dialog text, erasing
+ * the dialog text area and terminating dialog text mode.
+ */
+static int
+gtermEndDialog (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+
+ GtEndDialog (w);
+ return (TCL_OK);
+}
+
+
+/* eraseDialog -- Erase the dialog text area.
+ *
+ * Usage: eraseDialog
+ *
+ * eraseDialog may be called at any time to erase the dialog text area without
+ * exiting dialog text mode.
+ */
+static int
+gtermEraseDialog (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+
+ GtEraseDialog (w);
+ return (TCL_OK);
+}
+
+
+/* drawDialogText -- Draw a dialog box text string.
+ *
+ * Usage: drawDialogText x y text
+ *
+ * A text string is drawn at the indicated position using the current dialog
+ * text font. The font is selected based on the window size from a resource
+ * defined list of dialog fonts of different sizes. The attributes of dialog
+ * text (color etc.) are determined by the widget resources and the window
+ * size and are independent of the graphics context used for alpha text and
+ * other graphics. The coordinaes X,Y refer to the lower left corner of the
+ * text string where "lower" refers to the baseline of the font. That is, if
+ * the text string is "E", the coordinates x,y refer to the lower left corner
+ * of the E.
+ */
+static int
+gtermDrawDialogText (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+ char *text;
+ int x, y;
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ x = atoi (argv[1]);
+ y = atoi (argv[2]);
+ text = argv[3];
+ GtDrawDialogText (w, x, y, text);
+
+ return (TCL_OK);
+}
+
+
+/* getDialogTextSize -- Get the size in destination drawable pixels of an
+ * dialog text string in terms of the current graphics context.
+ *
+ * Usage: width = getDialogTextSize [string [width [height [base]]]]
+ *
+ * The size in pixels of the given string is returned in the WIDTH and HEIGHT
+ * output variables. If no string or the null string is given the maximum
+ * width and height of a single character in the font are returned. If a BASE
+ * output variable is given this variable will be set to the Y offset from the
+ * top of the string to the baseline of the characters forming the string.
+ */
+static int
+gtermGetDialogTextSize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ register XPoint *pv;
+
+ char *s_width, *s_height, *s_base;
+ int width, height, base;
+ char buf[SZ_NUMBER];
+ char *text;
+
+ if (argc > 1 && (int)strlen(argv[1]) > 0)
+ text = argv[1];
+ else
+ text = NULL;
+
+ s_width = (argc > 2) ? argv[2] : NULL;
+ s_height = (argc > 3) ? argv[3] : NULL;
+ s_base = (argc > 4) ? argv[4] : NULL;
+
+ GtGetDialogTextSize (w, text, &width, &height, &base);
+ if (s_width) {
+ sprintf (buf, "%d", width);
+ Tcl_SetVar (obm->tcl, s_width, buf, 0);
+ }
+ if (s_height) {
+ sprintf (buf, "%d", height);
+ Tcl_SetVar (obm->tcl, s_height, buf, 0);
+ }
+ if (s_base) {
+ sprintf (buf, "%d", base);
+ Tcl_SetVar (obm->tcl, s_base, buf, 0);
+ }
+
+ sprintf (buf, "%d", width);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* rasterInit -- Initialize the raster subsystem, deleting all rasters and
+ * mappings and freeing the dynamic part of the colortable.
+ *
+ * Usage: rasterInit
+ */
+static int
+gtermRasterInit (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtRasterInit (w);
+ return (TCL_OK);
+}
+
+
+/* assignRaster -- Assign a raster to a preexisting, externally defined
+ * drawable (e.g. widget window or server pixmap).
+ *
+ * Usage: assignRaster raster drawable
+ *
+ * The drawable may be the name of a widget object elsewhere in the GUI,
+ * or the numeric server code for an arbitrary server pixmap or window.
+ * A special case occurs when the named widget object is another gterm
+ * widget. In this case graphics pipelines can be constructed piping data
+ * from the rasters and mappings of the first widget to those of the second,
+ * using a mapping to connect the two. When the destination raster is in
+ * another gterm widget the widget code will automatically execute any
+ * mappings defined on the affected raster when it is modified by the
+ * mapping from the first widget. This allows a raster to be mapped to
+ * and displayed in multiple destination windows.
+ */
+static int
+gtermAssignRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject gt_obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &gt_obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ XtPointer drawable;
+ ObmObject obj;
+ int raster, type;
+ char *object;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ object = argv[2];
+
+ /* Get the drawable handle and type.
+ */
+ if (isdigit (*object)) {
+ /* A server pixmap or window passed by server ID. */
+ drawable = (XtPointer) atoi(object);
+ type = GtWindow;
+
+ } else {
+ /* A named object. */
+ if ((obj = obmFindObject (obm, object)) == NULL)
+ return (TCL_ERROR);
+ if (obj->core.classrec->object_type != OtNonShell)
+ return (TCL_ERROR); /* no window */
+
+ if (obmClass (obj->core.classrec, WtGterm)) {
+ /* Gterm widget.
+ drawable = (XtPointer) widgetGetPointer (obj);
+ */
+ drawable = (XtPointer) XtWindow (widgetGetPointer(obj));
+ type = GtWidget;
+
+ } else {
+ /* Some other type of widget. */
+ drawable = (XtPointer) XtWindow (widgetGetPointer(obj));
+ type = GtWindow;
+ }
+ }
+
+ if (GtAssignRaster (w, raster, drawable, type) == OK)
+ return (TCL_OK);
+ else
+ return (TCL_ERROR);
+}
+
+
+/* createRaster -- Create a raster of the given type and size.
+ *
+ * Usage: createRaster raster width height [type [depth]]
+ *
+ * A raster number RASTER is created with the given size and type. The
+ * possible raster types are "client", and "server", the default being
+ * to create a client raster. Rasters created in client memory are the
+ * most general and are best for most applications. Server side rasters
+ * are used only in special applications; server rasters can be copied to
+ * the display window very quickly but server memory is a limited resource
+ * and a program using large amounts of server memory may not run on some
+ * servers. Mappings other than one-to-one are *less* efficient on server
+ * rasters than on client rasters.
+ *
+ * Currently only rasters of depth 8 bits are supported. A createRaster on
+ * an existing raster will destroy the old raster, along with any mappings
+ * defined on it, and create a new one.
+ *
+ * Raster number zero is the gterm widget's display window. If one attempts
+ * a createRaster on this window the widget will try to resize the window.
+ * The resize attempt may or may not succeed, depending upon the resize
+ * restrictions of the geometry or window managers in use, shell resources,
+ * and so on.
+ *
+ * There is a limit on the maximum number of rasters which can be created,
+ * set by the gterm widget resource maxRasters at widget creation.
+ */
+static int
+gtermCreateRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int raster, width, height, type, depth;
+ char *s_type;
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ width = atoi (argv[2]);
+ height = atoi (argv[3]);
+ s_type = (argc > 4) ? argv[4] : "client";
+ depth = (argc > 5) ? atoi(argv[5]) : 0;
+
+ if (strcmp (s_type, "server") == 0)
+ type = GtServer;
+ else
+ type = GtClient;
+
+ if (GtCreateRaster (w, raster, type, width, height, depth) == ERR)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* destroyRaster -- Destroy a raster.
+ *
+ * Usage: destroyRaster raster
+ *
+ * Raster number RASTER is destroyed along with all of its mappings. This is
+ * a no-op if the raster is not currently defined. Attempts to destroy raster
+ * number zero (the widget's window) are ignored.
+ */
+static int
+gtermDestroyRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int raster;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ GtDestroyRaster (w, raster);
+
+ return (TCL_OK);
+}
+
+
+/* queryRaster -- Query a raster's attributes.
+ *
+ * Usage: exists = queryRaster raster [width height [type [depth]]]
+ *
+ * The width and height, and optionally the type and depth, of raster number
+ * RASTER are returned in the named output variables. The boolean function
+ * value indicates whether or not the raster is currently defined. If the
+ * raster does not exist the output variables may be undefined after the call.
+ */
+static int
+gtermQueryRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ char *s_width, *s_height, *s_type, *s_depth;
+ int exists, raster, width, height, type, depth;
+ char buf[SZ_NUMBER], *v_type;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ s_width = (argc > 2) ? argv[2] : NULL;
+ s_height = (argc > 3) ? argv[3] : NULL;
+ s_type = (argc > 4) ? argv[4] : NULL;
+ s_depth = (argc > 5) ? argv[5] : NULL;
+
+ if (GtQueryRaster (w, raster, &type, &width, &height, &depth)) {
+ if (s_width) {
+ sprintf (buf, "%d", width);
+ Tcl_SetVar (obm->tcl, s_width, buf, 0);
+ }
+ if (s_height) {
+ sprintf (buf, "%d", height);
+ Tcl_SetVar (obm->tcl, s_height, buf, 0);
+ }
+ if (s_type) {
+ v_type = (type == GtServer) ? "server" : "client";
+ Tcl_SetVar (obm->tcl, s_type, v_type, 0);
+ }
+ if (s_depth) {
+ sprintf (buf, "%d", depth);
+ Tcl_SetVar (obm->tcl, s_depth, buf, 0);
+ }
+ Tcl_SetResult (obm->tcl, TRUESTR, TCL_STATIC);
+
+ } else {
+ Tcl_SetResult (obm->tcl, FALSESTR, TCL_STATIC);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* nextRaster -- Return the number of the next available, unused raster.
+ *
+ * Usage: raster = nextRaster
+ *
+ */
+static int
+gtermNextRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char buf[SZ_NUMBER];
+ int raster;
+
+ if ((raster = GtNextRaster (w)) < 0)
+ return (TCL_ERROR);
+ else {
+ sprintf (buf, "%d", raster);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* activeRasters -- Return the number of currently defined rasters.
+ *
+ * Usage: count = activeRasters
+ *
+ */
+static int
+gtermActiveRasters (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char buf[SZ_NUMBER];
+
+ sprintf (buf, "%d", GtNRasters(w));
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* setPixel -- Set the value of a single pixel.
+ *
+ * Usage: setPixel raster x y value
+ *
+ * raster The raster number.
+ *
+ * x, y The pixel to be set.
+ *
+ * value The pixel value.
+ *
+ * This routine is more efficient than writePixels for setting the value of
+ * a single pixel, but is a lot less efficient if a block of pixels are to
+ * be set.
+ */
+static int
+gtermSetPixel (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+ int raster, x, y;
+ uchar data[1];
+
+ if (argc < 5)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ x = atoi (argv[2]);
+ y = atoi (argv[3]);
+ data[0] = atoi (argv[4]);
+ GtWritePixels (w, raster, data, 8, x, y, 1, 1);
+
+ return (TCL_OK);
+}
+
+
+/* getPixel -- Get the value of a single pixel.
+ *
+ * Usage: getPixel raster x y
+ *
+ * raster The raster number.
+ *
+ * x, y The pixel to be set.
+ *
+ * This routine is more efficient than readPixels for getting the value of
+ * a single pixel, but is a lot less efficient if a block of pixels are to
+ * be read.
+ */
+static int
+gtermGetPixel (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+ char buf[SZ_NUMBER];
+ int raster, x, y;
+ uchar data[1];
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ x = atoi (argv[2]);
+ y = atoi (argv[3]);
+ GtReadPixels (w, raster, data, 8, x, y, 1, 1);
+
+ sprintf (buf, "%d", data[0]);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* writePixels -- Set the values of some subset of the pixels in a raster.
+ * If any mappings are defined on the affected region and are enabled, any
+ * destination rasters will be automatically updated as defined by the mapping.
+ *
+ * Usage: writePixels raster pixels encoding nbits x1 y1 nx ny [bias]
+ *
+ * raster The raster number.
+ *
+ * pixels The pixel array, encoded as a string.
+ *
+ * encoding The pixel encoding. "numeric" means each pixel is
+ * encoded as a decimal integer delimited by whitespace.
+ *
+ * "hex1" means the pixel array is hex encoded, 1 bytes
+ * per 8 bit pixel, as a printable text string. Hex1
+ * encoding can only be used for pixel values in the
+ * range 0-63. The 64 possible pixel values are encoded
+ * as follows: '0'-'9', 'A'-'Z', 'a'-'z', '$', '_'.
+ * (Since there are 26 letters this is 10+26+26+1+1=64).
+ *
+ * "hex2" means the pixel array is hex encoded, 2 bytes
+ * per 8 bit pixel, as a printable text string. The
+ * two bytes are defined as follows (v = pixel value):
+ *
+ * byte1 = ((v >> 4) & 017) in hex [0-9A-F]
+ * byte2 = ((v ) & 017) in hex [0-9A-F]
+ *
+ * Either "hex1" or "hex2" followed by "-rle", e.g.,
+ * "hex2-rle" means that the hex-encoded data is in
+ * turn run length encoded. In a run length encoded
+ * string all characters are data characters except
+ * for "@" and "%", which are repeat operators. "@" is
+ * followed by a single hex1-encoded character giving
+ * the repeat count minus one: the hex1-encoded number
+ * is decoded as N and the most recent pixel value is
+ * repeated N+1 times. "%" is similar, but is followed
+ * by a 2 character hex2-encoded repeat count.
+ *
+ * Whitespace in a hex encoded string is ignored.
+ * Hex2 encoding reduces the data volume by about a factor
+ * of two (compared to numeric) and is only a factor of
+ * two less space efficient than binary. Hex1 encoding
+ * is as space efficient as binary but pixel values larger
+ * than 63 (64 possible values) cannot be represented.
+ *
+ * nbits Number of bits per pixel - currently only 8 bit pixels
+ * are supported.
+ *
+ * x1,y1,nx,ny Region of the raster to be written to.
+ *
+ * bias If a bias value is given this value is added to the
+ * value of each input pixel.
+ *
+ * Most real-world image processing applications get the Gterm widget handle
+ * with setGterm and pass binary data to the widget by calling GtWritePixels
+ * directly. This is the most efficient approach for serious image processing
+ * where large amounts of data are involved. However, being able to read and
+ * write raster pixels directly in a GUI can be useful in specialized
+ * applications, e.g., where the image is computed or modified by the GUI.
+ */
+static int
+gtermWritePixels (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+
+ register char *ip;
+ register uchar *op;
+ register int v, i, j;
+ static uchar hex1[256], hex2[256];
+ static int have_tables = 0;
+ int raster, nbits, bias;
+ char *pixels, *encoding;
+ int x1, y1, nx, ny;
+ uchar *data, *otop;
+
+ if (argc < 9)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ pixels = argv[2];
+ encoding = argv[3];
+ nbits = atoi (argv[4]);
+ x1 = atoi (argv[5]);
+ y1 = atoi (argv[6]);
+ nx = atoi (argv[7]);
+ ny = atoi (argv[8]);
+ bias = (argc > 9) ? atoi(argv[9]) : 0;
+
+ if (nbits != 8)
+ return (TCL_ERROR);
+
+ /* Generate hex to binary lookup tables in first call. */
+ if (!have_tables) {
+ /* Generate char-to-binary table for the hex1 encoding. */
+ for (i=0; i < 256; i++)
+ hex1[i] = 0177;
+ for (i='0'; i <= '9'; i++)
+ hex1[i] = i - '0';
+ for (i='A'; i <= 'Z'; i++)
+ hex1[i] = i - 'A' + 10;
+ for (i='a'; i <= 'z'; i++)
+ hex1[i] = i - 'a' + 36;
+ hex1['$'] = 62;
+ hex1['_'] = 63;
+
+ /* Generate char-to-binary table for the hex2 encoding. */
+ for (i=0; i < 256; i++)
+ hex2[i] = 0177;
+ for (i='0'; i <= '9'; i++)
+ hex2[i] = i - '0';
+ for (i='a'; i <= 'f'; i++)
+ hex2[i] = i - 'a' + 10;
+ for (i='A'; i <= 'F'; i++)
+ hex2[i] = i - 'A' + 10;
+
+ have_tables++;
+ }
+
+ /* Decode the pixel data. */
+ if (!(data = (uchar *) XtMalloc (nx * ny)))
+ return (TCL_ERROR);
+ otop = data + nx * ny;
+
+ /* Uncompress the input if RLE compression is indicated. */
+ if (strcmp (&encoding[strlen(encoding)-4], "-rle") == 0) {
+ int buflen = nx * ny * 2;
+ char *ibuf, *op;
+ int ch;
+
+ /* Get buffer to hold the uncompressed pixel data array. */
+ if (!(ibuf = (char *) XtMalloc (buflen + 1)))
+ goto err;
+
+ /* Uncompress the pixel array. */
+ for (ip=pixels, op=ibuf; *ip; ) {
+ while (isspace (*ip))
+ ip++;
+
+ if ((ch = *ip++) == '@') {
+ if ((i = hex1[*ip++]) >= 0x7f)
+ while (*ip && ((i = hex1[*ip++]) >= 0x7f))
+ ;
+ if (op-ibuf + i + 1 > buflen)
+ goto err;
+ for (v = *(op-1), i++; --i >= 0; )
+ *op++ = v;
+
+ } else if (ch == '%') {
+ if ((i = hex2[*ip++]) >= 0x7f)
+ while (*ip && ((i = hex2[*ip++]) >= 0x7f))
+ ;
+ if ((j = hex2[*ip++]) >= 0x7f)
+ while (*ip && ((j = hex2[*ip++]) >= 0x7f))
+ ;
+ i = ((i << 4) | j) + 1;
+ if (op-ibuf + i > buflen)
+ goto err;
+ for (v = *(op-1); --i >= 0; )
+ *op++ = v;
+
+ } else
+ *op++ = ch;
+ }
+
+ *op = '\0';
+ pixels = ibuf;
+ }
+
+ /* Convert the ascii pixels array to a binary data array.
+ */
+ if (strcmp (encoding, "numeric") == 0) {
+ for (ip=pixels; isspace(*ip) || *ip == '{'; ip++)
+ ;
+ for (op=data; *ip && op < otop; ) {
+ for (v=0; isdigit(*ip); )
+ v = v * 10 + *ip++ - '0';
+ *op++ = v + bias;
+ while (isspace(*ip) || *ip == '}')
+ ip++;
+ }
+ } else if (strncmp (encoding, "hex1", 4) == 0) {
+ for (ip=pixels, op=data; *ip && op < otop; ) {
+ if ((v = hex1[*ip++]) > 0xf)
+ while (*ip && ((v = hex1[*ip++]) > 0xf))
+ ;
+ *op++ = v + bias;
+ }
+ } else if (strncmp (encoding, "hex2", 4) == 0) {
+ for (ip=pixels, op=data; *ip && op < otop; ) {
+ if ((v = hex2[*ip++]) > 0xf)
+ while (*ip && ((v = hex2[*ip++]) > 0xf))
+ ;
+ if ((i = hex2[*ip++]) > 0xf)
+ while (*ip && ((i = hex2[*ip++]) > 0xf))
+ ;
+ *op++ = ((v << 4) | i) + bias;
+ }
+ } else {
+err: XtFree ((char *)data);
+ if (pixels != argv[2])
+ XtFree (pixels);
+ return (TCL_ERROR);
+ }
+
+ /* Write the pixels. */
+ GtWritePixels (w, raster, data, nbits, x1, y1, nx, ny);
+ XtFree ((char *)data);
+ if (pixels != argv[2])
+ XtFree (pixels);
+
+ return (TCL_OK);
+}
+
+
+/* readPixels -- Get the values of some subset of the pixels in a raster.
+ *
+ * Usage: pixels = readPixels raster encoding nbits x1 y1 nx ny [bias]
+ *
+ * raster The raster number.
+ *
+ * encoding The pixel encoding. "numeric" means each pixel is
+ * encoded as a decimal integer delimited by whitespace.
+ * "hex1", hex2", and "hex1-rle or "hex2-rle" are
+ * possible encodings. See writePixels for details.
+ *
+ * nbits Number of bits per pixel - currently only 8 bit pixels
+ * are supported.
+ *
+ * x1,y1,nx,ny Region of the raster to be read.
+ *
+ * bias The bias value is subtracted from the pixel value
+ * returned by readPixels.
+ *
+ * The pixel array, encoded as a string, is returned as the function value.
+ * Use readPixels to read a block of pixels, and getPixel to get the value
+ * of a single pixel.
+ */
+static int
+gtermReadPixels (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+
+ register int v, i;
+ register uchar *ip, *op;
+ int bias, nchars, npix, n, j;
+ char *pixels, *encoding;
+ int x1, y1, nx, ny;
+ int raster, nbits;
+ uchar *data;
+ char *buf;
+
+ if (argc < 8)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ encoding = argv[2];
+ nbits = atoi (argv[3]);
+ x1 = atoi (argv[4]);
+ y1 = atoi (argv[5]);
+ nx = atoi (argv[6]);
+ ny = atoi (argv[7]);
+ bias = (argc > 8) ? atoi(argv[8]) : 0;
+ npix = nx * ny;
+
+ if (nbits != 8)
+ return (TCL_ERROR);
+
+ /* Get the pixel data. */
+ if (!(data = (uchar *) XtMalloc (npix * sizeof(uchar))))
+ return (TCL_ERROR);
+ if (GtReadPixels (w, raster, data, nbits, x1, y1, nx, ny) == ERR) {
+ XtFree ((char *)data);
+ return (TCL_ERROR);
+ }
+
+ /* Get a text buffer large enough to hold the encoded data. */
+ nchars = npix * 4 + (npix/16) * 3 + 5;
+ if (!(buf = (char *) XtMalloc (nchars))) {
+ XtFree ((char *)data);
+ return (TCL_ERROR);
+ }
+
+ /* Encode the pixel data as a printable text string using the
+ * encoding specified by the caller.
+ */
+ if (strcmp (encoding, "numeric") == 0) {
+ /* Encode the data as {ddd ddd ddd ... ddd}. */
+ op = (uchar *)buf;
+ *op++ = '{';
+ *op++ = ' ';
+
+ for (ip=data, n=npix, j=0; --n >= 0; ) {
+ v = *ip++ - bias;
+
+ i = (v / 100);
+ if (i) {
+ *op++ = i + '0';
+ v -= i * 100;
+ } else
+ *op++ = ' ';
+
+ i = (v / 10);
+ if (i) {
+ *op++ = i + '0';
+ v -= i * 10;
+ } else
+ *op++ = ' ';
+
+ *op++ = v + '0';
+ *op++ = ' ';
+
+ if (++j >= 16) {
+ *op++ = '\n';
+ *op++ = ' ';
+ *op++ = ' ';
+ j = 0;
+ }
+ }
+
+ if (j)
+ *op++ = '\n';
+ *op++ = '}';
+ *op++ = '\0';
+
+ } else if (strncmp (encoding, "hex", 3) == 0) {
+ static uchar hex1[256], hex2[256*2];
+ static int have_tables = 0;
+ uchar *obuf, *cbuf;
+
+ if (!have_tables) {
+ /* Generate binary to hex1 (64 element) lookup table. */
+ for (n=0, op=hex1; n < 256; n++) {
+ i = (n % 64);
+ if (i < 10)
+ *op++ = i + '0';
+ else if (i < 36)
+ *op++ = (i - 10) + 'A';
+ else if (i < 62)
+ *op++ = (i - 36) + 'a';
+ else if (i == 62)
+ *op++ = '$';
+ else
+ *op++ = '_';
+ }
+
+ /* Generate binary to hex2 (256 element) lookup table. */
+ for (n=0, op=hex2; n < 256; n++) {
+ i = ((n >> 4) & 017);
+ *op++ = (i < 10) ? i + '0' : (i-10) + 'A';
+ i = (n & 017);
+ *op++ = (i < 10) ? i + '0' : (i-10) + 'A';
+ }
+
+ have_tables++;
+ }
+
+ if ((obuf = (uchar *) XtMalloc (npix*2)) == NULL)
+ return (TCL_ERROR);
+
+ if (strncmp (encoding, "hex1", 4) == 0) {
+ /* Hex1 encoding uses only one character per pixel but the
+ * pixel range is restricted to 0 to 63.
+ */
+ for (j=0, ip=data, op=obuf; j < ny; j++) {
+ for (i=0; i < nx; i++)
+ *op++ = hex1[*ip++ - bias];
+ }
+ *op = '\0';
+
+ } else if (strncmp (encoding, "hex2", 4) == 0) {
+ /* Hex2 encoding uses 2 characters per pixel and supports
+ * pixel values in the range 0 to 255.
+ */
+ for (j=0, ip=data, op=obuf; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ v = (*ip++ - bias) * 2;
+ *op++ = hex2[v];
+ *op++ = hex2[v+1];
+ }
+ if (nx % 2)
+ ip++;
+ }
+ *op = '\0';
+ }
+
+ /* Run length compress the data. The compressed data stream
+ * contains a mixture of literal data codes and repeat codes.
+ * A "@" followed by a hex1-encoded number N causes the most
+ * recent pixel value to be repeated N+1 times, where N < 64.
+ * A "%" followed by a hex2-encoded number N causes the most
+ * recent pixel value to be repeated N+1 times, where N < 256.
+ */
+ if (strcmp (&encoding[strlen(encoding)-4], "-rle") == 0) {
+ if ((cbuf = (unsigned char *) XtMalloc (npix*3)) == NULL)
+ return (TCL_ERROR);
+
+ ip = obuf;
+ op = cbuf;
+ *op++ = v = *ip++;
+ while (*ip) {
+ for (n=0; n < 256 && *ip == v; ip++, n++)
+ ;
+ if (n == 0) {
+ *op++ = v = *ip++;
+ } else if (n < 3) {
+ while (--n >= 0)
+ *op++ = v;
+ } else if (n <= 64) {
+ *op++ = '@';
+ *op++ = hex1[n-1];
+ } else if (n <= 256) {
+ *op++ = '%';
+ *op++ = hex2[(n-1)*2];
+ *op++ = hex2[(n-1)*2+1];
+ }
+ }
+ *op = '\0';
+
+ XtFree ((char *)obuf);
+ obuf = cbuf;
+ }
+
+ /* Output the encoded pixel data.
+ */
+ op = (uchar *)buf;
+ *op++ = '{';
+ *op++ = ' ';
+
+ for (ip=obuf, n=1; *ip; ip++, n++) {
+ *op++ = *ip;
+ if (n && n > 72) {
+ *op++ = '\n';
+ *op++ = ' ';
+ *op++ = ' ';
+ n = 0;
+ }
+ }
+
+ if (n)
+ *op++ = '\n';
+ *op++ = '}';
+ *op++ = '\0';
+ XtFree ((char *)obuf);
+
+ } else {
+ XtFree ((char *)data);
+ return (TCL_ERROR);
+ }
+
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+ XtFree ((char *)data);
+ XtFree ((char *)buf);
+
+ return (TCL_OK);
+}
+
+
+/* refreshPixels -- Refresh any mappings the source rect of which intersects
+ * the given region of the specified raster.
+ *
+ * Usage: refreshPixels raster ctype x1 y1 nx ny
+ *
+ * Any mappings defined on the region [x1,y1,nx,ny] of the given raster are
+ * updated, redisplaying the indicated region. refreshPixels is like
+ * writePixels except that the affected pixels are redisplayed without
+ * actually having been modified. Raster coordinates may be given in either
+ * raster pixel coordinates (ctype=Pixel) or NDC coordinates (ctype=NDC)
+ * in the range 0-1 floating. The origin in the upper left for raster
+ * coordinates and in the lower left for NDC coordinates. Raster coordinates
+ * are zero indexed.
+ */
+static int
+gtermRefreshPixels (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ float x1, y1, nx, ny;
+ int raster, ctype;
+
+ if (argc < 7)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ ctype = coordType (argv[2]);
+ x1 = atof (argv[3]);
+ y1 = atof (argv[4]);
+ nx = atof (argv[5]);
+ ny = atof (argv[6]);
+
+ GtRefreshPixels (w, raster, ctype, x1, y1, nx, ny);
+
+ return (TCL_OK);
+}
+
+
+/* setPixels -- Set a region of a raster to a single color.
+ *
+ * Usage: setPixels raster [color [ctype x1 y1 nx ny [rop]]]
+ *
+ * The region [x1,y1,nx,ny] of raster RASTER, specified in the coordinate
+ * system CTYPE (Pixel or NDC) is set to the color number COLOR. If no
+ * region is specified the entire raster is assumed. The color number is
+ * specified in the color system defined by the client, which may or may not
+ * be the same as the internal gterm widget color system (the client and
+ * widget color systems are the same only if no iomap has been specified,
+ * or, equivalently, if the iomap is one-to-one). If no color is given the
+ * background color is assumed. Any mappings mapped to the affected pixels
+ * will be updated to propagate and possibly display the changes.
+ *
+ * Although this routine permits an optional rasterop argument (ROP) there
+ * is currently no support for symbolically defining the bitfields used to
+ * form this word. Most applications do not need to specify a rasterop.
+ */
+static int
+gtermSetPixels (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int color, rop, raster, ctype;
+ float x1, y1, nx, ny;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ raster = atoi (argv[1]);
+ color = (argc > 2) ? atoi(argv[2]) : GtGetClientPixel(w,0);
+
+ if (argc >= 8) {
+ ctype = coordType (argv[3]);
+ x1 = atof (argv[4]);
+ y1 = atof (argv[5]);
+ nx = atof (argv[6]);
+ ny = atof (argv[7]);
+ } else {
+ ctype = GtNDC;
+ x1 = 0;
+ y1 = 0;
+ nx = 1.0;
+ ny = 1.0;
+ }
+
+ rop = (argc > 8) ? atoi(argv[8]) : 0;
+
+ if (ctype == GtNDC) {
+ x1 *= MAXNDC; y1 *= MAXNDC;
+ nx *= MAXNDC; ny *= MAXNDC;
+ }
+
+ if (GtSetPixels (w, raster, ctype, (int)x1, (int)y1, (int)nx, (int)ny,
+ color, rop) == ERR)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* extractPixmap -- Extract a region of a raster into a pixmap.
+ *
+ * Usage: extractPixmap pixmap raster [ctype x1 y1 nx ny]
+ *
+ * The given region of raster RASTER is extracted and placed into a pixmap
+ * object with name PIXMAP. The pixmap object is created if it does not
+ * already exist. The size of the pixmap object will be the size of the
+ * extracted region. If no region is given the entire raster is assumed.
+ */
+static int
+gtermExtractPixmap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ float x1, y1, nx, ny;
+ int raster, ctype;
+ Pixmap pixmap;
+ char *s_pixmap;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ s_pixmap = argv[1];
+ raster = atoi (argv[2]);
+
+ if (argc >= 8) {
+ ctype = coordType (argv[3]);
+ x1 = atof (argv[4]);
+ y1 = atof (argv[5]);
+ nx = atof (argv[6]);
+ ny = atof (argv[7]);
+ } else {
+ ctype = GtNDC;
+ x1 = 0;
+ y1 = 0;
+ nx = 1.0;
+ ny = 1.0;
+ }
+
+ if (pixmap = GtExtractPixmap (w, raster, ctype, x1, y1, nx, ny))
+ createPixmap (obm, s_pixmap, nx, ny, 8, pixmap, NULL, 0, 0);
+ else
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* insertPixmap -- Insert a pixmap into a region of a raster.
+ *
+ * Usage: insertPixmap pixmap raster [ctype x1 y1 nx ny]
+ *
+ * The given pixmap PIXMAP is inserted to raster RASTER at the given
+ * location. If no region is given the entire raster is assumed.
+ */
+static int
+gtermInsertPixmap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ float x1, y1, nx, ny;
+ int raster, ctype;
+ Pixmap pixmap;
+ char *s_pixmap;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ s_pixmap = argv[1];
+ raster = atoi (argv[2]);
+
+ if (argc >= 8) {
+ ctype = coordType (argv[3]);
+ x1 = atof (argv[4]);
+ y1 = atof (argv[5]);
+ nx = atof (argv[6]);
+ ny = atof (argv[7]);
+ } else {
+ ctype = GtNDC;
+ x1 = 0;
+ y1 = 0;
+ nx = 1.0;
+ ny = 1.0;
+ }
+
+ if (pixmap = findPixmap (obm, s_pixmap)) {
+ if (GtInsertPixmap (w, pixmap, raster, ctype,x1,y1,nx,ny) == ERR)
+ return (TCL_ERROR);
+ } else
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* nextColormap -- Get the index of the next unused colormap.
+ *
+ * Usage: colormap = nextColormap
+ *
+ * Colormaps are dynamically allocated so there is no builtin limit on the
+ * number of colormaps.
+ */
+static int
+gtermNextColormap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char buf[SZ_NUMBER];
+
+ sprintf (buf, "%d", GtNextColormap (w));
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* freeColormap -- Free a colormap.
+ *
+ * Usage: freeColormap colormap
+ *
+ * The given colormap and all of its resources are freed. This is a no-op if
+ * the given colormap is not defined.
+ */
+static int
+gtermFreeColormap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int colormap;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ colormap = atoi (argv[1]);
+ GtFreeColormap (w, colormap);
+
+ return (TCL_OK);
+}
+
+
+/* writeColormap -- Write to a colormap.
+ *
+ * Usage: writeColormap colormap colors [offset]
+ *
+ * The given list of colors are loaded into the given colormap. If no
+ * offset is specified the offset will default to the offset of the first
+ * dynamically allocatable color cell (e.g. 10). Colormap zero is the
+ * window colormap and writing to this colormap will immediately affect
+ * the display. The nonzero colormaps are merely stored within the gterm
+ * widget and will not take effect until loaded with loadColormap.
+ *
+ * Colors are specified as a list of RGB color triplets in the range 0-255.
+ * For example, { {R G B} {R G B} ...}.
+ *
+ * The gterm widget supports both private colormaps and the default colormap.
+ * Which is used is controlled by the cmapName resource; writeColormap works
+ * the same way for both types of colormaps.
+ */
+static int
+gtermWriteColormap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ ObmContext obm = obj->widget.obm;
+ GtermPrivate gp = &obj->gterm;
+ Widget w = obj->widget.w;
+
+ register int ncolors;
+ register char *ip;
+ char *colors, *ip_save;
+ ushort r[MAX_COLORS];
+ ushort g[MAX_COLORS];
+ ushort b[MAX_COLORS];
+ int offset, colormap;
+ char *ipp;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ colormap = atoi (argv[1]);
+ colors = argv[2];
+ offset = (argc > 3) ? atoi(argv[3]) : FIRST_COLOR;
+
+ for (ncolors=0, ip=colors; *ip && ncolors < MAX_COLORS; ) {
+ while (isspace(*ip) || *ip == '{')
+ ip++;
+
+ ip_save = ip;
+ r[ncolors] = (strtol (ip, &ipp, 10)) << 8; ip = ipp;
+ g[ncolors] = (strtol (ip, &ipp, 10)) << 8; ip = ipp;
+ b[ncolors] = (strtol (ip, &ipp, 10)) << 8; ip = ipp;
+ if (ip == ip_save)
+ return (TCL_ERROR);
+
+ while (isspace(*ip) || *ip == '}')
+ ip++;
+
+ ncolors++;
+ }
+
+ if (GtWriteColormap (w, colormap, offset, ncolors, r, g, b) == ERR)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* readColormap -- Read from a colormap.
+ *
+ * Usage: ncolors = readColormap colormap colors [offset [ncolors]]
+ *
+ * The given region of the colormap is read and return in the output variable
+ * COLORS. The actual number of color values read is returned as the function
+ * value. If no offset is specified the offset will default to the offset of
+ * the first dynamically allocatable color cell (e.g. 10). If the number of
+ * colors to be read (NCOLORS) is not specified readColormap will return a
+ * list of all the allocated colors starting at the specified colortable
+ * offset.
+ *
+ * Colors are returned as a list of RGB color triplets in the range 0-255.
+ * For example, { {R G B} {R G B} ...}.
+ */
+static int
+gtermReadColormap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ ObmContext obm = obj->widget.obm;
+ GtermPrivate gp = &obj->gterm;
+ Widget w = obj->widget.w;
+
+ register int i;
+ register char *op;
+ char colors[MAX_COLORS * 3 * 20];
+ ushort r[MAX_COLORS];
+ ushort g[MAX_COLORS];
+ ushort b[MAX_COLORS];
+ int offset, colormap;
+ int ncolors, request;
+ char buf[SZ_NUMBER];
+ char *s_colors;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ colormap = atoi (argv[1]);
+ s_colors = argv[2];
+ offset = (argc > 3) ? atoi(argv[3]) : FIRST_COLOR;
+ request = (argc > 4) ? atoi(argv[4]) : MAX_COLORS;
+
+ ncolors = GtReadColormap (w, colormap, offset, request, r, g, b);
+
+ op = colors;
+ *op++ = '{';
+ *op++ = ' ';
+ for (i=0; i < ncolors; i++) {
+ sprintf (op, "{%d %d %d} ", (r[i] >> 8), (g[i] >> 8), (b[i] >> 8));
+ while (*op)
+ op++;
+ }
+ *op++ = '}';
+ *op++ = '\0';
+ Tcl_SetVar (obm->tcl, s_colors, colors, 0);
+
+ sprintf (buf, "%d", ncolors);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* loadColormap -- Load a colormap.
+ *
+ * Usage: loadColormap colormap [offset [scale]]
+ *
+ * The offset and scale parameters may be used to adjust the brightness and
+ * contrast of the image when the colormap is loaded. The normalized colormap
+ * has offset=0.5, scale=1.0. Colormap zero is the hardware colormap.
+ */
+static int
+gtermLoadColormap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ ObmContext obm = obj->widget.obm;
+ GtermPrivate gp = &obj->gterm;
+ Widget w = obj->widget.w;
+ float offset, scale;
+ int colormap;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ colormap = atoi (argv[1]);
+ offset = (argc > 2) ? atof(argv[2]) : gp->offset;
+ scale = (argc > 3) ? atof(argv[3]) : gp->scale;
+
+ GtLoadColormap (w, colormap, offset, scale);
+
+ gp->colormap = colormap;
+ gp->offset = offset;
+ gp->scale = scale;
+
+ return (TCL_OK);
+}
+
+
+/* clientPixel -- Convert a gterm pixel to a client pixel.
+ *
+ * Usage: pixel = clientPixel gterm_pixel
+ *
+ * If the client has an iomap installed, gterm i/o operations which deal
+ * with pixel values will map to and from client (external) pixels and the
+ * internal gterm widget color model. The clientPixel routine can be used to
+ * convert a pixel (i.e. color) in the gterm color model to the corresponding
+ * client pixel in the client's color model. For example "clientPixel 0"
+ * will return the client pixel corresponding to the gterm widget background
+ * color.
+ */
+static int
+gtermClientPixel (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int pixel, client_pixel;
+ char buf[SZ_NUMBER];
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ pixel = atoi (argv[1]);
+ client_pixel = GtGetClientPixel (w, pixel);
+
+ sprintf (buf, "%d", client_pixel);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* getBias -- Get the colormap bias value.
+ *
+ * Usage: bias = getBias [nelem [maxelem]]
+ *
+ * The colormap bias value is the pixel value corresponding to the first
+ * dynamically allocatable colormap cell. That is, the gterm widget
+ * defines N preallocated static colors 0 to N-1, followed by an arbitrary
+ * number of dynamically allocatable colors. The bias value is the pixel
+ * value of the first dynamically allocatable color.
+ *
+ * If the optional arguments nelem and maxelem are given then the number
+ * of currently allocated colors and the maximum number of allocatable colors
+ * are returned. The latter values do not include the N=bias static colors,
+ * i.e. nelem=0 if no dynamic colors have been allocated.
+ */
+static int
+gtermGetBias (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int first, nelem, maxelem;
+ char buf[SZ_NUMBER];
+
+ GtQueryColormap (w, 0, &first, &nelem, &maxelem);
+
+ if (argc > 1) {
+ sprintf (buf, "%d", nelem);
+ Tcl_SetVar (obm->tcl, argv[1], buf, 0);
+ }
+ if (argc > 2) {
+ sprintf (buf, "%d", maxelem);
+ Tcl_SetVar (obm->tcl, argv[2], buf, 0);
+ }
+
+ sprintf (buf, "%d", first);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* initMappings -- Initialize the mapping subsystem, deleting any existing
+ * mappings.
+ *
+ * Usage: initMappings
+ */
+static int
+gtermInitMappings (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+
+ GtInitMappings (w);
+ return (TCL_OK);
+}
+
+
+/* nextMapping -- Return the index of the next unused mapping.
+ *
+ * Usage: mapping = nextMapping
+ *
+ * Returns the mapping number as the function value.
+ */
+static int
+gtermNextMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+ char buf[SZ_NUMBER];
+ int mapping;
+
+ mapping = GtNextMapping (w);
+ sprintf (buf, "%d", mapping);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* freeMapping -- Free or delete a mapping.
+ *
+ * Usage: freeMapping mapping
+ *
+ * The given mapping descriptor is freed and any resources used by the mapping
+ * are freed.
+ */
+static int
+gtermFreeMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, erase;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ GtDisableMapping (w, mapping, erase=1);
+ GtFreeMapping (w, mapping);
+
+ return (TCL_OK);
+}
+
+
+/* lowerMapping -- Lower a mapping, i.e., change its stacking order so that
+ * it is drawn below other mappings.
+ *
+ * Usage: lowerMapping mapping [reference]
+ *
+ * If a reference mapping is named the stacking order of the target mapping
+ * will be modified to make it appear just beneath the reference mapping.
+ * If no reference mapping is given the mapping will be moved to the bottom
+ * of the mapping stacking order, making it be drawn below all other mappings.
+ */
+static int
+gtermLowerMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, reference;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ reference = (argc > 2) ? atoi(argv[2]) : 0;
+ GtLowerMapping (w, mapping, reference);
+
+ return (TCL_OK);
+}
+
+
+/* raiseMapping -- Raise a mapping, i.e., change its stacking order so that
+ * it is drawn above other mappings.
+ *
+ * Usage: raiseMapping mapping [reference]
+ *
+ * If a reference mapping is named the stacking order of the target mapping
+ * will be modified to make it appear just above the reference mapping.
+ * If no reference mapping is given the mapping will be moved to the top
+ * of the mapping stacking order, making it be drawn above all other mappings.
+ */
+static int
+gtermRaiseMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, reference;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ reference = (argc > 2) ? atoi(argv[2]) : 0;
+ GtRaiseMapping (w, mapping, reference);
+
+ return (TCL_OK);
+}
+
+
+/* enableMapping -- Reenable a mapping.
+ *
+ * Usage: enableMapping mapping [refresh]
+ *
+ * The given mapping is enabled and optionally refreshed. This is a no-op
+ * if the mapping is already enabled.
+ */
+static int
+gtermEnableMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, refresh;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ refresh = (argc > 2) ? (strcmp(argv[2],"refresh") == 0) : False;
+
+ if (GtEnableMapping (w, mapping, refresh) == ERR)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* disableMapping -- Disable a mapping.
+ *
+ * Usage: disableMapping mapping [erase]
+ *
+ * The given mapping is disabled and optionally erased. This is a no-op
+ * if the mapping is not enabled.
+ */
+static int
+gtermDisableMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, erase;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ erase = (argc > 2) ? (strcmp(argv[2],"erase") == 0) : False;
+
+ if (GtDisableMapping (w, mapping, erase) == ERR)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* activeMapping -- Test whether a given mapping is active (enabled).
+ *
+ * Usage: active = activeMapping mapping
+ *
+ * Returns True if the mapping is defined and enabled, False otherwise.
+ */
+static int
+gtermActiveMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ char buf[SZ_NUMBER];
+ int mapping, active;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ active = GtActiveMapping (w, mapping);
+
+ Tcl_SetResult (obm->tcl, active ? TRUESTR : FALSESTR, TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* refreshMapping -- Refresh a mapping.
+ *
+ * Usage: refreshMapping mapping
+ *
+ * The given mapping is unconditionally refreshed, i.e., the destination
+ * rect is repainted.
+ */
+static int
+gtermRefreshMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ GtRefreshMapping (w, mapping);
+
+ return (TCL_OK);
+}
+
+
+/* copyRaster -- Copy a region from one raster to another.
+ *
+ * Usage: copyRaster rop
+ * src st sx sy snx sny
+ * dst dt dx dy dnx dny
+ *
+ * The specified region of the source raster is scaled as necessary and
+ * written to the specified region of the destination raster. This is
+ * equivalent to defining a mapping between the source and destination,
+ * refreshing the mapping, and then freeing the mapping. Refer to setMapping
+ * for a description of the arguments.
+ *
+ * Copyraster may be used to manually display rasters (without setting up a
+ * mapping) by copying rasters to raster zero, the display window. If the
+ * source raster is a server raster and the mapping is one-to-one this can
+ * be done very quickly. For the fastest possible results the transient
+ * flag should be set in the rasterop (ROP) to prevent saving of the displayed
+ * data in an off-screen pixmap (this may prevent the window from being
+ * refreshed properly in response to window system expose events).
+ */
+static int
+gtermCopyRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int rop, src, st, dst, dt, status;
+ int sx, sy, snx, sny, dx, dy, dnx, dny;
+
+ if (argc != 14)
+ return (TCL_ERROR);
+
+ rop = atoi (argv[1]);
+ get_mapping (&argv[2],
+ &src, &st, &sx, &sy, &snx, &sny,
+ &dst, &dt, &dx, &dy, &dnx, &dny);
+
+ status = GtCopyRaster (w, rop,
+ src, st, sx, sy, snx, sny,
+ dst, dt, dx, dy, dnx, dny);
+
+ return (status == ERR ? TCL_ERROR : TCL_OK);
+}
+
+
+/* setMapping -- Set or modify a mapping.
+ *
+ * Usage: setMapping mapping rop
+ * src st sx sy snx sny
+ * dst dt dx dy dnx dny
+ *
+ * setMapping defines a new mapping function, or modifies an old one. If a new
+ * mapping is defined it is merely enabled, and no refreshing of the screen
+ * takes place until either some mapped source data is modified or the mapping
+ * is explicitly refreshed. If an existing mapping is modified the old and new
+ * mappings are examined and only those portions of the destination rect for
+ * which the mapping changed are updated. This permits minor changes to a
+ * mapping (e.g. moving an edge) without having to redraw the entire region.
+ * Regions of the destination drawable which were previously covered by the
+ * mapping but which were exposed by modifying the mapping are redrawn, in
+ * effect erasing the mapping.
+ *
+ * SetMapping optimizes the mapping operation where possible. In particular,
+ * if the mapping is one-to-one and both the source and destination rasters
+ * are server rasters, a very fast memory copy in the server is used. Other
+ * cases, for example a dezoom involving antialising, can be expensive.
+ *
+ * The mapping number is arbitrary. Mapping numbers may be preallocated by
+ * some client defined logic, or dynamically allocated with nextMapping.
+ * Most applications will want to set the rasterop (ROP) argument to zero,
+ * which causes the mapping to copy the source to the destination. For further
+ * information on the significance of the bits in the rasterop refer to the
+ * gterm widget documentation.
+ *
+ * The source and destination rects are specifed with six fields each: the
+ * raster number, coordinate type, X,Y coordinates of the rect, and the
+ * X,Y size of the rect in pixels. The coordinate type may be either "Pixel"
+ * (raster pixel coordinates) or NDC. NDC coordinates are normalized device
+ * coordinates in the range 0.0 to 1.0 in either axis. The origin is in the
+ * upper left corner for Pixel coordinates, and in the lower left corner for
+ * NDC coordinates.
+ *
+ * The source and destination rects need not be the same size. The source
+ * will be scaled as necessary to fill the destination. Scaling options,
+ * e.g. the antialiasing technique used for a dezoom, are controlled by the
+ * rasterop. If the DNX or DNY field is negative the mapping will flip the
+ * image about the corresponding axis.
+ *
+ * The source and destination rects can be any two rasters, or even the
+ * same raster. A special case is raster zero, the display window. Mapping
+ * a source raster to dst=0 is equivalent to displaying the raster. By
+ * default data mapped to raster zero will also be saved in an off-screen
+ * pixmap in the server and used to autmatically refresh the window in
+ * response to window system expose events. This feature may be disabled
+ * by setting the transient flag in the rasterop.
+ *
+ * A raster can have multiple source or destination mappings defined on it.
+ * A region of a raster may be the source for more than one mapping in which
+ * case all mappings are updated when the source region is modified. Multiple
+ * sources may be mapped to (different regions) of a destination raster to
+ * implement special effects such as split screen or picture insets. Mappings
+ * may be chained to set up graphics pipelines, where the destination of one
+ * mapping is the source of the next. Care must be taken to avoid feedback or
+ * infinite loops can result.
+ */
+static int
+gtermSetMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, rop, src, st, dst, dt, status;
+ int sx, sy, snx, sny, dx, dy, dnx, dny;
+
+ if (argc != 15)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ rop = atoi (argv[2]);
+ get_mapping (&argv[3],
+ &src, &st, &sx, &sy, &snx, &sny,
+ &dst, &dt, &dx, &dy, &dnx, &dny);
+
+ status = GtSetMapping (w, mapping, rop,
+ src, st, sx, sy, snx, sny,
+ dst, dt, dx, dy, dnx, dny);
+
+ return (status == ERR ? TCL_ERROR : TCL_OK);
+}
+
+
+/* getMapping -- Get a mapping.
+ *
+ * Usage: getMapping mapping rop
+ * src st sx sy snx sny
+ * dst dt dx dy dnx dny
+ *
+ * The given mapping is returned in the output variables. All arguments
+ * except MAPPING are output variables. It is an error if the mapping is
+ * not defined, but the mapping need not be enabled.
+ */
+static int
+gtermGetMapping (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, rop, src, st, dst, dt, status;
+ int sx, sy, snx, sny, dx, dy, dnx, dny;
+ char buf[SZ_NUMBER];
+
+ if (argc != 15)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ status = GtGetMapping (w, mapping, &rop,
+ &src, &st, &sx, &sy, &snx, &sny,
+ &dst, &dt, &dx, &dy, &dnx, &dny);
+ if (status == ERR)
+ return (TCL_ERROR);
+
+ sprintf (buf, "%d", rop);
+ Tcl_SetVar (obm->tcl, argv[2], buf, 0);
+ put_mapping (obm->tcl, &argv[3],
+ src, st, sx, sy, snx, sny,
+ dst, dt, dx, dy, dnx, dny);
+
+ return (TCL_OK);
+}
+
+
+/* SelectRaster -- Given the raw screen coordinates SX,SY (or coords in
+ * any destination raster), determine the mapping and source raster which are
+ * mapped to that pixel and return the raster and mapping numbers and the
+ * coordinates of the same pixel in the source raster.
+ *
+ * Usage: raster = selectRaster dras dt dx dy rt rx ry [map]
+ *
+ * where dras display raster
+ * dt,rt coordinate type - "pixel" or "ndc"
+ * dx,dy display raster coordinates (input)
+ * rx,ry source raster coordinates (output)
+ * map mapping selected (output)
+ *
+ * Note that the coordinates returned by selectRaster are measured (taking
+ * a line as an example) from zero at the left edge of the first pixel, to
+ * "width" at the right edge of the last pixel. This means that the floating
+ * point coordinates of the center of raster pixel N will be N + 0.5. For
+ * example, if we input screen coordinates (dras=0), x=117, and no mapping
+ * is in effect, the floating point raster coordinates returned will be 117.5.
+ * The difference occurs because the input coordinate is a pixel number
+ * (integer) while the output coordinate is a floating point coordinate
+ * measuring the continuously variable location a pixel. int(x) will convert
+ * this coordinate to a raster pixel number.
+ */
+static int
+gtermSelectRaster (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ int raster, dras, dt, dx, dy, rt, rx, ry, mp;
+ char *xout, *yout, *mpout;
+ float fx, fy;
+ char buf[64];
+
+ if (argc < 8)
+ return (TCL_ERROR);
+
+ /* Get arguments. */
+ dras = atoi (argv[1]);
+ if ((dt = coordType (argv[2])) < 0)
+ dt = GtPixel;
+ dx = (int) atof (argv[3]);
+ dy = (int) atof (argv[4]);
+ if (dt == GtNDC) {
+ dx *= MAXNDC;
+ dy *= MAXNDC;
+ }
+ if ((rt = coordType (argv[5])) < 0)
+ rt = GtPixel;
+ xout = argv[6];
+ yout = argv[7];
+ mpout = (argc > 8) ? argv[8] : NULL;
+
+ raster = GtSelectRaster (wp->w, dras, dt, dx, dy, GtNDC, &rx, &ry, &mp);
+
+ if (rt == GtNDC) {
+ /* Return coords scaled 0.0 - 1.0. */
+ fx = (float)rx / MAXNDC;
+ fy = (float)ry / MAXNDC;
+ } else {
+ /* Return raster pixel coordinates. */
+ ndcToPixel (wp->w, raster, rx, ry, &fx, &fy);
+ }
+
+ sprintf (buf, "%g", fx);
+ Tcl_SetVar (obm->tcl, xout, buf, 0);
+ sprintf (buf, "%g", fy);
+ Tcl_SetVar (obm->tcl, yout, buf, 0);
+ if (mpout) {
+ sprintf (buf, "%d", mp);
+ Tcl_SetVar (obm->tcl, mpout, buf, 0);
+ }
+
+ sprintf (buf, "%d", raster);
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* UnmapPixel -- unmapPixel is a simplified, less general version of
+ * selectRaster which will automatically follow graphics pipelines back to
+ * the original mapped raster. If desired the raster pixel value can be
+ * returned as well as the raster number and raster pixel coordinates
+ * corresponding to a screen (raster 0) pixel.
+ *
+ * Usage: unmapPixel sx sy raster rx ry [rz]
+ *
+ * where sx,sy "screen" (raster 0) coordinates
+ * raster original mapped raster (output)
+ * rx,ry source raster coordinates (output)
+ * rz source raster pixel value (output)
+ *
+ * By following graphics pipelines back to the original source raster we mean
+ * the following. If raster A is mapped to raster B which is mapped to C (the
+ * screen), given a screen coordinate in the mapped region unmapPixel will
+ * return the raster number and coordinates for raster A.
+ */
+static int
+gtermUnmapPixel (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ int dst, dx, dy, src, sx, sy, mapping;
+ char *raster_out, *x_out, *y_out, *z_out;
+ char buf[SZ_NUMBER];
+ float fx, fy;
+
+ if (argc < 6)
+ return (TCL_ERROR);
+
+ /* Get arguments. */
+ dx = (int) atof (argv[1]);
+ dy = (int) atof (argv[2]);
+ raster_out = argv[3];
+ x_out = argv[4];
+ y_out = argv[5];
+ z_out = (argc > 6) ? argv[6] : NULL;
+
+ /* Follow the pipeline back to the original mapped raster. */
+ fx = dx; fy = dy;
+ src = 0;
+
+ do {
+ src = GtSelectRaster (wp->w, dst=src,
+ GtPixel, dx, dy, GtNDC, &sx, &sy, &mapping);
+ if (src != dst) {
+ ndcToPixel (wp->w, src, sx, sy, &fx, &fy);
+ dx = (int) fx;
+ dy = (int) fy;
+ }
+ } while (dst != src);
+
+ sprintf (buf, "%d", src);
+ Tcl_SetVar (obm->tcl, raster_out, buf, 0);
+ sprintf (buf, "%g", fx);
+ Tcl_SetVar (obm->tcl, x_out, buf, 0);
+ sprintf (buf, "%g", fy);
+ Tcl_SetVar (obm->tcl, y_out, buf, 0);
+
+ if (z_out) {
+ uchar data[1];
+ GtReadPixels (wp->w, src, data, 8, dx, dy, 1, 1);
+ sprintf (buf, "%d", data[0]);
+ Tcl_SetVar (obm->tcl, z_out, buf, 0);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* flip -- Edit a mapping to flip the mapped subimage in X and/or Y.
+ *
+ * Usage: flip mapping axis [axis]
+ *
+ * where axis is "x" or "y". This is a convenience routine for changing only
+ * the flip portion of a mapping.
+ */
+static int
+gtermFlip (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register Widget w = wp->w;
+ int mapping, rop, flipX, flipY, i;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ mapping = atoi (argv[1]);
+ flipX = flipY = 0;
+ for (i=2; i < argc; i++) {
+ if (argv[i][0] == 'x')
+ flipX = !flipX;
+ else if (argv[i][0] == 'y')
+ flipY = !flipY;
+ }
+
+ if (flipX || flipY) {
+ GtGetMapping (w, mapping,
+ &rop, &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+
+ if (flipX)
+ dnx = -dnx;
+ if (flipY)
+ dny = -dny;
+
+ GtSetMapping (w, mapping,
+ rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* gtermMarkerInit -- Initialize the Marker subsystem for a Gterm widget.
+ * This destroys all markers and initializes the marker subsystem.
+ *
+ * Usage: markerInit
+ */
+static int
+gtermMarkerInit (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+
+ GtMarkerInit (wp->w);
+ return (TCL_OK);
+}
+
+
+/* gtermCreateMarker -- Create a new marker.
+ *
+ * Usage: createMarker name attribute-list
+ * e.g. createMarker name {attribute value [attribute value ...]}
+ * or createMarker name attribute value [attribute value ...]
+ *
+ * Any marker attribute may be assigned a value when the marker is created.
+ * Refer to <ObmW/Gterm.h> for a list of marker attribute names. Often the
+ * the attributes "type" and "createMode" need to be specified at marker
+ * create time.
+ *
+ * type The marker type: text, rectangle, circle, etc.
+ *
+ * createMode A marker should be created with createMode=interactive
+ * if the user is expected to interactively drag out
+ * the marker using the pointer and either the default
+ * or an application specified translation table. A
+ * marker can also be created interactively using only
+ * the m_create (marker create) action, however m_create
+ * does not allow the marker attributes to be set.
+ *
+ * There are any number of ways to use a GUI to create a marker under the
+ * Object Manager, but an example might be using a translation to call a GUI
+ * procedure which issues the createMarker call. For example a pointer down
+ * event could translate as "call(newMarker,$name,$x,$y) m_create()" where
+ * newMarker is a GUI marker creation procedure which sends a createMarker
+ * message to the Gterm widget. The GUI procedure could set the marker
+ * attributes as desired, possibly using additional GUI components to define
+ * the marker attributes. The m_create action will notice that a
+ * createMarker has been executed and will merely activate the marker and
+ * give it the pointer focus (i.e. install the marker translations). The
+ * user will then use the pointer or keyboard to drag out the marker.
+ *
+ * If the marker is created noninteractive the application must set the marker
+ * position and size using marker attributes. If the marker is sensitive
+ * the user can then use the marker's translations to interactively modify
+ * the marker (resize it, move it, etc.). All markers which are visible and
+ * sensitive and which have the necessary translations can be interactively
+ * modified by the user; the reason for creating a marker in interactive mode
+ * is to allow the initial marker position and size to be specified
+ * interactively *when* the marker is created, instead of afterwards.
+ *
+ * Any number of attributes may be given when the marker is created. Most
+ * marker attributes can also be modified after a marker has been created
+ * by sending setAttribute messages to the marker.
+ */
+static int
+gtermCreateMarker (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ GtermObject obj = (GtermObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ Arg args[MAX_ARGS];
+ int nargs, i;
+ char **items;
+ int nitems;
+ char *name;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+
+ if (argc == 3) {
+ /* Attribute list passed as a list argument. */
+ if (Tcl_SplitList (tcl, argv[2], &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+ } else if (argc > 3) {
+ /* Attribute list passed as separate arguments. */
+ nitems = argc - 2;
+ items = (char **) XtMalloc (nitems * sizeof(char *));
+ if (items == NULL)
+ return (TCL_ERROR);
+ for (i=0; i < nitems; i++)
+ items[i] = argv[i+2];
+ } else
+ return (TCL_ERROR);
+
+ if (argc > 2)
+ for (i=nargs=0; i < nitems && nargs < MAX_ARGS; i += 2) {
+ XtSetArg (args[nargs], items[i], items[i+1]);
+ nargs++;
+ }
+
+ obmNewObject (obm, name, "Marker", obj->core.name, args, nargs);
+
+ if (argc > 2)
+ free ((char *) items);
+
+ return (TCL_OK);
+}
+
+
+/*
+ * Gterm widget utility procedures.
+ * ------------------------------------------
+ */
+
+
+/* coordType -- Convert a coordinate type string "pixel" or "ndc" to an
+ * integer code.
+ */
+coordType (name)
+char *name;
+{
+ if (strcmp (name, "pixel") == 0 ||
+ strcmp (name, "Pixel") == 0 ||
+ strcmp (name, "PIXEL") == 0) {
+
+ return (GtPixel);
+
+ } else if (
+ strcmp (name, "ndc") == 0 ||
+ strcmp (name, "NDC") == 0) {
+
+ return (GtNDC);
+
+ } else
+ return (-1);
+}
+
+
+/* dataLevelType -- Convert a data level type string to an integer code.
+ */
+dataLevelType (name)
+char *name;
+{
+ if (strcmp (name, "set") == 0)
+ return (GtSet);
+ else if (strcmp (name, "clear") == 0)
+ return (GtClear);
+ else if (strcmp (name, "invert") == 0)
+ return (GtInvert);
+ else
+ return (-1);
+}
+
+
+/* lineStyle -- Convert a line style string to an integer code.
+ */
+lineStyle (name)
+char *name;
+{
+ if (strcmp (name, "solid") == 0)
+ return (GtSolid);
+ else if (strcmp (name, "dashed") == 0)
+ return (GtDashed);
+ else if (strcmp (name, "dotted") == 0)
+ return (GtDotted);
+ else if (strcmp (name, "dashDot") == 0)
+ return (GtDashDot);
+ else if (strcmp (name, "dash3Dot") == 0)
+ return (GtDash3Dot);
+ else
+ return (-1);
+}
+
+
+/* fillType -- Convert a fill type string to an integer code.
+ */
+fillType (name)
+char *name;
+{
+ if (strcmp (name, "solid") == 0)
+ return (GtSolid);
+ else if (strcmp (name, "outline") == 0)
+ return (GtOutline);
+ else
+ return (-1);
+}
+
+
+/* colorToIndex -- Convert a color name or number to a gterm widget color
+ * index.
+ */
+colorToIndex (name)
+char *name;
+{
+ if (isdigit (*name))
+ return (atoi (name));
+ else if (strcmp (name, "background") == 0)
+ return (0);
+ else if (strcmp (name, "foreground") == 0)
+ return (1);
+ else if (strcmp (name, "black") == 0)
+ return (0);
+ else if (strcmp (name, "white") == 0)
+ return (1);
+ else if (strcmp (name, "red") == 0)
+ return (2);
+ else if (strcmp (name, "green") == 0)
+ return (3);
+ else if (strcmp (name, "blue") == 0)
+ return (4);
+ else if (strcmp (name, "cyan") == 0)
+ return (5);
+ else if (strcmp (name, "magenta") == 0)
+ return (6);
+ else if (strcmp (name, "yellow") == 0)
+ return (7);
+ else if (strcmp (name, "user1") == 0)
+ return (8);
+ else if (strcmp (name, "user2") == 0)
+ return (9);
+ else
+ return (-1);
+}
+
+
+/* ncdToPixel -- Convert NDC (integer) to raster pixel (floating) coordinates.
+ */
+ndcToPixel (w, raster, nx, ny, rx, ry)
+Widget w;
+int raster;
+int nx, ny;
+float *rx, *ry;
+{
+ int rtype, width, height, depth;
+ int x2, y2;
+
+ GtQueryRaster (w, raster, &rtype, &width, &height, &depth);
+ x2 = width;
+ y2 = height;
+
+ *rx = (float)( nx) / MAXNDC * x2;
+ *ry = (float)(MAXNDC - ny) / MAXNDC * y2; /* NDC is flipped in Y */
+}
+
+static XPoint *
+get_points (points, npoints)
+char *points;
+int *npoints;
+{
+ register int i;
+ register char *ip;
+ register XPoint *pv;
+ char *ipp, *ip_save;
+ int maxpts, npts;
+
+ maxpts = MAX_POLYPTS;
+ if ((pv = (XPoint *) XtMalloc (maxpts * sizeof(XPoint))) == NULL)
+ return (NULL);
+
+ /* Get the points array. */
+ for (npts=0, ip=points; *ip; ) {
+ while (isspace(*ip) || *ip == '{')
+ ip++;
+
+ ip_save = ip;
+ pv[npts].x = (short) strtod (ip, &ipp); ip = ipp;
+ pv[npts].y = (short) strtod (ip, &ipp); ip = ipp;
+ if (ip == ip_save) {
+ XtFree ((char *) pv);
+ return (NULL);
+ }
+
+ while (isspace(*ip) || *ip == '}')
+ ip++;
+
+ if (++npts >= maxpts) {
+ maxpts *= 2;
+ if ((pv = (XPoint *) XtRealloc ((char *)pv,
+ maxpts * sizeof(XPoint))) == NULL)
+ return (NULL);
+ }
+ }
+
+ *npoints = npts;
+ return (pv);
+}
+
+
+/* get_mapping -- Read a mapping from an argument list into local variables.
+ */
+static void
+get_mapping (argv, src, st, sx,sy,snx,sny, dst, dt, dx,dy,dnx,dny)
+register char **argv; /* mapping values */
+int *src, *st;
+int *sx, *sy, *snx, *sny;
+int *dst, *dt;
+int *dx, *dy, *dnx, *dny;
+{
+ register int ndc;
+ register double v;
+
+ *src = atoi (argv[0]);
+ *st = (strcmp(argv[1],"pixel")==0 || strcmp(argv[1],"Pixel")==0) ?
+ GtPixel : GtNDC;
+ ndc = (*st == GtNDC);
+
+ v = atof(argv[2]);
+ *sx = ndc ? (v * MAXNDC) : v;
+ v = atof(argv[3]);
+ *sy = ndc ? ((1.0 - v) / 1.0 * MAXNDC) : v;
+ v = atof(argv[4]);
+ *snx = ndc ? (v * MAXNDC) : v;
+ v = atof(argv[5]);
+ *sny = ndc ? (v * MAXNDC) : v;
+
+ *dst = atoi (argv[6]);
+ *dt = (strcmp(argv[7],"pixel")==0 || strcmp(argv[7],"Pixel")==0) ?
+ GtPixel : GtNDC;
+ ndc = (*dt == GtNDC);
+
+ v = atof(argv[8]);
+ *dx = ndc ? (v * MAXNDC) : v;
+ v = atof(argv[9]);
+ *dy = ndc ? ((1.0 - v) / 1.0 * MAXNDC) : v;
+ v = atof(argv[10]);
+ *dnx = ndc ? (abs(v) * MAXNDC) : abs(v);
+ if (v < 0)
+ *dnx = -(*dnx);
+ v = atof(argv[11]);
+ *dny = ndc ? (abs(v) * MAXNDC) : abs(v);
+ if (v < 0)
+ *dny = -(*dny);
+}
+
+
+/* put_mapping -- Output a mapping from local variables to a list of output
+ * variables.
+ */
+static void
+put_mapping (tcl, argv, src, st, sx,sy,snx,sny, dst, dt, dx,dy,dnx,dny)
+register Tcl_Interp *tcl;
+register char **argv; /* mapping variables */
+int src, st;
+int sx, sy, snx, sny;
+int dst, dt;
+int dx, dy, dnx, dny;
+{
+ register int ndc;
+ char buf[SZ_NUMBER];
+
+ sprintf (buf, "%d", src);
+ Tcl_SetVar (tcl, argv[0], buf, 0);
+ Tcl_SetVar (tcl, argv[1], st == GtPixel ? "Pixel" : "NDC", 0);
+ ndc = (st == GtNDC);
+
+ sprintf (buf, "%g", ndc ? (float)sx / MAXNDC : (float)sx);
+ Tcl_SetVar (tcl, argv[2], buf, 0);
+ sprintf (buf, "%g",
+ ndc ? (1.0 - ((float)sy / MAXNDC)) : (float)sy);
+ Tcl_SetVar (tcl, argv[3], buf, 0);
+ sprintf (buf, "%g", ndc ? (float)snx / MAXNDC : (float)snx);
+ Tcl_SetVar (tcl, argv[4], buf, 0);
+ sprintf (buf, "%g", ndc ? (float)sny / MAXNDC : (float)sny);
+ Tcl_SetVar (tcl, argv[5], buf, 0);
+
+ sprintf (buf, "%d", src);
+ Tcl_SetVar (tcl, argv[6], buf, 0);
+ Tcl_SetVar (tcl, argv[7], st == GtPixel ? "Pixel" : "NDC", 0);
+ ndc = (st == GtNDC);
+
+ sprintf (buf, "%g", ndc ? (float)dx / MAXNDC : (float)dx);
+ Tcl_SetVar (tcl, argv[8], buf, 0);
+ sprintf (buf, "%g",
+ ndc ? (1.0 - ((float)dy / MAXNDC)) : (float)dy);
+ Tcl_SetVar (tcl, argv[9], buf, 0);
+ sprintf (buf, "%g", ndc ? (float)dnx / MAXNDC : (float)dnx);
+ Tcl_SetVar (tcl, argv[10], buf, 0);
+ sprintf (buf, "%g", ndc ? (float)dny / MAXNDC : (float)dny);
+ Tcl_SetVar (tcl, argv[11], buf, 0);
+}
diff --git a/vendor/x11iraf/obm/html.c b/vendor/x11iraf/obm/html.c
new file mode 100644
index 00000000..3679a7a9
--- /dev/null
+++ b/vendor/x11iraf/obm/html.c
@@ -0,0 +1,1534 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+#include "widget.h"
+
+/*
+ * HTML widget class (a subclass of Widget).
+ * -------------------------------------------------------------------------
+ * The HTML (hypertext markup language) widget displays a block of HTML
+ * formatted text, the "document" to be displayed. The text consists of a
+ * mixture of text to be displayed and embedded formatting directives. The
+ * text may also contain "hot links" pointing to other HTML-formatted
+ * documents.
+ *
+ * setText text [target [header_text [footer_text]]]
+ * text = getText [format [font]]
+ * retestAnchors
+ *
+ * id = positionToId x y
+ * idToPosition id x y
+ * anchorToPosition name x y
+ * id = anchorToId name
+ * gotoId id
+ *
+ * n = getHRefs list
+ * n = getImageSrcs list
+ * n = getLinks list
+ *
+ * setSelection start end
+ * text = getSelection start end
+ * clearSelection
+ *
+ * searchText pattern start end [direction [search_type]]
+ *
+ * addCallback procedure-name [callback-type]
+ * deleteCallback procedure-name [callback-type]
+ *
+ * The possible callback types and their callback arguments are as follows.
+ *
+ * anchor widget cbtype event text href element_id
+ * testAnchor widget cbtype href
+ * submitForm widget cbtype event attrs href method enctype encentity
+ * link widget cbtype href role
+ * pointerMotion widget cbtype href
+ *
+ * See the comments below for further details on the callback types and their
+ * arguments.
+ *
+ * All a "hot link" is to the HTML widget is a document object containing a
+ * HREF which causes a callback when selected by the user viewing the document.
+ * It is up to the application using the HTML widget to define what the meaning
+ * of an HREF is.
+ *
+ * This version of the HTML widget binding does not yet support inline images.
+ */
+
+#define CB_Anchor 1
+#define CB_TestAnchor 2
+#define CB_PointerMotion 3
+#define CB_SubmitForm 4
+#define CB_Link 5
+
+/* HTML class instance descriptor. */
+struct htmlPrivate {
+ ObmCallback callback_list;
+};
+
+typedef struct htmlPrivate *HTMLPrivate;
+
+struct htmlObject {
+ struct obmObjectCore core;
+ struct widgetPrivate widget;
+ struct htmlPrivate html;
+};
+
+typedef struct htmlObject *HTMLObject;
+
+/* HTML class class record private data. */
+typedef struct {
+ /* standard MsgContext fields. */
+ Tcl_Interp *tcl; /* class interpreter */
+ ObmObject object[MAX_LEVELS]; /* object which received last message */
+ int level;
+
+ /* HTML specific fields. */
+ /* (none) */
+} htmlClassData, *HTMLClassData;
+
+
+void HTMLDestroy();
+void HTMLClassDestroy();
+ObmObject HTMLCreate();
+
+static int htmlSetText(), htmlGetText(), htmlGetHRefs();
+static int htmlGetImageSrcs(), htmlGetLinks();
+static int htmlRetestAnchors(), htmlPositionToId(), htmlIdToPosition();
+static int htmlAnchorToPosition(), htmlAnchorToId();
+static int htmlGotoId(), htmlAddCallback(), htmlDeleteCallback();
+static int htmlSetSelection(), htmlGetSelection(), htmlClearSelection();
+static int htmlSearchText();
+
+static void anchorCallback(), pointerMotionCallback();
+static void submitFormCallback(), linkCallback();
+static char *cb_encode(), *makeList();
+static int testAnchorCallback();
+static void cb_error();
+static int cb_decode();
+extern long strtol();
+
+
+/* HTMLClassInit -- Initialize the class record for the HTML widget class.
+ */
+void
+HTMLClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register HTMLClassData gcd;
+ register Tcl_Interp *tcl;
+ register ClientData c_gcd;
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = HTMLClassDestroy;
+ classrec->Create = (ObmFunc) HTMLCreate;
+ classrec->Destroy = HTMLDestroy;
+ classrec->Evaluate = WidgetEvaluate;
+
+ /* The HTML widget subclass has its own command set hence has its
+ * own interpreter. The widget will respond both to all the commands
+ * defined here, and to all the commands implemented by the base
+ * Widget class.
+ */
+ if (!classrec->class_data) {
+ gcd = (HTMLClassData) XtCalloc (1, sizeof (htmlClassData));
+ gcd->tcl = tcl = Tcl_CreateInterp();
+ classrec->class_data = (XtPointer) gcd;
+ c_gcd = (ClientData)gcd;
+ gcd->level = 0;
+
+ Tcl_CreateCommand (tcl,
+ "addCallback", htmlAddCallback, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteCallback", htmlDeleteCallback, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setText", htmlSetText, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getText", htmlGetText, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "positionToId", htmlPositionToId, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "idToPosition", htmlIdToPosition, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "anchorToPosition", htmlAnchorToPosition, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "anchorToId", htmlAnchorToId, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "gotoId", htmlGotoId, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getHRefs", htmlGetHRefs, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getImageSrcs", htmlGetImageSrcs, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getLinks", htmlGetLinks, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "retestAnchors", htmlRetestAnchors, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "setSelection", htmlSetSelection, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "getSelection", htmlGetSelection, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "clearSelection", htmlClearSelection, c_gcd, NULL);
+ Tcl_CreateCommand (tcl,
+ "searchText", htmlSearchText, c_gcd, NULL);
+ }
+}
+
+
+/* HTMLClassDestroy -- Custom destroy procedure for the HTML class.
+ */
+void
+HTMLClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register HTMLClassData gcd = (HTMLClassData) classrec->class_data;
+
+ if (gcd) {
+ if (gcd->tcl)
+ Tcl_DeleteInterp (gcd->tcl);
+ XtFree ((char *)gcd);
+ classrec->class_data = NULL;
+ }
+}
+
+
+/* HTMLCreate -- Create an instance of a HTML object.
+ */
+ObmObject
+HTMLCreate (obm, name, classrec, parent, a_args, a_nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList a_args;
+int a_nargs;
+{
+ register HTMLObject obj;
+ register Widget w;
+ Arg args[128];
+ int nargs = 0;
+
+ for (nargs = 0; nargs < a_nargs; nargs++)
+ args[nargs] = a_args[nargs];
+
+ XtSetArg (args[nargs], WbNpreviouslyVisitedTestFunction,
+ (long)testAnchorCallback); nargs++;
+ XtSetArg (args[nargs], WbNpointerMotionCallback,
+ (long)pointerMotionCallback); nargs++;
+
+ obj = (HTMLObject) WidgetCreate (obm, name,classrec,parent,args,nargs);
+ if (obj == NULL)
+ return (NULL);
+ obj = (HTMLObject) XtRealloc ((char *)obj, sizeof(struct htmlObject));
+ if (obj == NULL)
+ return (NULL);
+
+ w = obj->widget.w;
+ /* register_image_resolution_function (w); */
+ XtAddCallback (w, WbNanchorCallback, anchorCallback, (XtPointer)obj);
+ XtAddCallback (w, WbNlinkCallback, linkCallback, (XtPointer)obj);
+ XtAddCallback (w, WbNsubmitFormCallback, submitFormCallback,
+ (XtPointer)obj);
+
+ XtSetArg (args[0], WbNpreviouslyVisitedTestData, obj);
+ XtSetArg (args[1], WbNpointerMotionData, obj);
+ XtSetValues (w, args, 2);
+
+ /* Initialize HTMLPrivate instance structure. */
+ obj->html.callback_list = NULL;
+
+ return ((ObmObject) obj);
+}
+
+
+/* HTMLDestroy -- Destroy an instance of a HTML object.
+ */
+void
+HTMLDestroy (object)
+ObmObject object;
+{
+ HTMLObject obj = (HTMLObject) object;
+ ObjClassRec classrec = obj->core.classrec;
+ register HTMLClassData gcd = (HTMLClassData) classrec->class_data;
+ register ObmCallback cb, cb_next;
+ ObmContext obm = obj->widget.obm;
+ Widget w = obj->widget.w;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ /* Free any HTML callback descriptors. */
+ for (cb = obj->html.callback_list; cb; cb = cb_next) {
+ cb_next = cb->next;
+
+ XtFree ((char *)cb);
+ }
+
+ WidgetDestroy (object);
+}
+
+
+/*
+ * HTML class functions.
+ * -----------------------
+ */
+
+
+/* setText -- Set the text to be displayed in the HTML widget.
+ *
+ * Usage: setText text [target [header_text [footer_text]]]
+ *
+ * If a target anchor is given the text will be positioned to view the
+ * given anchor. The target anchor may be specified either by name or by
+ * its element_id (tag number within the document, e.g. as returned in the
+ * anchor callback). If any HTML-formatted header or footer text is given
+ * this will be displayed before or after the document passed in as "text".
+ */
+static int
+htmlSetText (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *text, *target_anchor;
+ char *header_text, *footer_text;
+ int element_id;
+
+ text = (argc > 1) ? argv[1] : NULL;
+ target_anchor = (argc > 2) ? argv[2] : NULL;
+ header_text = (argc > 3) ? argv[3] : NULL;
+ footer_text = (argc > 4) ? argv[4] : NULL;
+ element_id = target_anchor ? atoi (target_anchor) : 0;
+
+ HTMLSetText (wp->w, text,
+ header_text, footer_text, element_id, target_anchor, NULL);
+
+ return (TCL_OK);
+}
+
+
+/* getText -- Get the text of the document currently being displayed.
+ *
+ * Usage: text = getText [format [font]]
+ *
+ * The optional format argument determines the type of text to be returned.
+ * The possible values are as follows.
+ *
+ * simple No formatting other than indents.
+ * pretty Simple formatting.
+ * postscript Return formatted Postscript.
+ *
+ * The default output format is simple. If Postscript output is selected
+ * the font can be selected from one of the following:
+ *
+ * times Times
+ * helvetica Helvetica
+ * schoolbook New century schoolbook
+ * lucida Lucida Bright
+ *
+ * The default Postscript font is Times.
+ */
+static int
+htmlGetText (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ char *text, *format, *font;
+ int pretty = 0;
+
+ format = (argc > 1) ? argv[1] : "simple";
+ font = (argc > 2) ? argv[2] : "times";
+
+ if (strcmp (format, "simple") == 0)
+ pretty = 0;
+ else if (strcmp (format, "pretty") == 0)
+ pretty = 1;
+ else if (strcmp (format, "postscript") == 0) {
+ if (strcmp (font, "times") == 0)
+ pretty = 2;
+ else if (strcmp (font, "helvetica") == 0)
+ pretty = 3;
+ else if (strcmp (font, "schoolbook") == 0)
+ pretty = 4;
+ else if (strcmp (font, "lucida") == 0)
+ pretty = 5;
+ else
+ pretty = 2;
+ }
+
+ if (text = HTMLGetText (wp->w, pretty)) {
+ Tcl_SetResult (wp->obm->tcl, text, TCL_VOLATILE);
+ free (text);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* positionToId -- Return the element id of the HTML element nearest to the
+ * given position x,y.
+ *
+ * Usage: id = positionToId x y
+ *
+ * If there is no element at the given position the first element in the
+ * current line is returned. If we are not positioned to a line, either the
+ * beginning or the end of the document is returned.
+ */
+static int
+htmlPositionToId (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ int element_id, x, y;
+ char buf[SZ_NUMBER];
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ x = atoi (argv[1]);
+ y = atoi (argv[2]);
+ element_id = HTMLPositionToId (wp->w, x, y);
+
+ sprintf (buf, "%d", element_id);
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* idToPosition -- Return the position of an HTML element given its
+ * element id.
+ *
+ * Usage: idToPosition id x y
+ *
+ * If there is no element with the given element id false is returned and
+ * the coordinates x,y are undefined.
+ */
+static int
+htmlIdToPosition (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ int status, element_id, x, y;
+ char buf[SZ_NUMBER];
+ char *s_x, *s_y;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ element_id = atoi (argv[1]);
+ s_x = (argc > 2) ? argv[2] : NULL;
+ s_y = (argc > 3) ? argv[3] : NULL;
+ status = HTMLIdToPosition (wp->w, element_id, &x, &y);
+
+ if (status < 0)
+ Tcl_SetResult (obm->tcl, FALSESTR, TCL_STATIC);
+ else {
+ if (s_x) {
+ sprintf (buf, "%d", x);
+ if ((Tcl_SetVar (obm->tcl, s_x, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ }
+ if (s_y) {
+ sprintf (buf, "%d", y);
+ if ((Tcl_SetVar (obm->tcl, s_y, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ }
+ Tcl_SetResult (obm->tcl, TRUESTR, TCL_STATIC);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* anchorToPosition -- Return the position of the named anchor.
+ *
+ * Usage: bool = anchorToPosition anchor [x y]
+ *
+ * If there is no anchor with the given name false is returned and the
+ * coordinates x,y are undefined.
+ */
+static int
+htmlAnchorToPosition (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ char *anchor, *s_x, *s_y;
+ char buf[SZ_NUMBER];
+ int status, x, y;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ anchor = argv[1];
+ s_x = (argc > 2) ? argv[2] : NULL;
+ s_y = (argc > 3) ? argv[3] : NULL;
+ status = HTMLAnchorToPosition (wp->w, anchor, &x, &y);
+
+ if (status < 0)
+ Tcl_SetResult (obm->tcl, FALSESTR, TCL_STATIC);
+ else {
+ if (s_x) {
+ sprintf (buf, "%d", x);
+ if ((Tcl_SetVar (obm->tcl, s_x, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ }
+ if (s_y) {
+ sprintf (buf, "%d", y);
+ if ((Tcl_SetVar (obm->tcl, s_y, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ }
+ Tcl_SetResult (obm->tcl, TRUESTR, TCL_STATIC);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* anchorToId -- Return the element id of the named anchor.
+ *
+ * Usage: id = anchorToId anchor
+ *
+ * If there is no anchor with the given name false is returned.
+ */
+static int
+htmlAnchorToId (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ char buf[SZ_NUMBER];
+ int element_id;
+ char *anchor;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ anchor = argv[1];
+ element_id = HTMLAnchorToId (wp->w, anchor);
+
+ sprintf (buf, "%d", element_id);
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* gotoId -- Position to the given element given its element id.
+ *
+ * Usage: gotoId element_id
+ *
+ * An id of zero means go to the top of the document.
+ */
+static int
+htmlGotoId (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ int element_id;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ element_id = atoi (argv[1]);
+ HTMLGotoId (wp->w, element_id);
+
+ return (TCL_OK);
+}
+
+
+/* getHRefs -- Get a list of the HREFs of all the active anchors in the
+ * document being displayed.
+ *
+ * Usage: n = getHRefs list
+ *
+ * The number of HREFs is returned as the function value; zero is returned
+ * if there are no HREFs, in which case "list" is undefined. If the document
+ * has HREFs on output list will contain a list of HREFs in the form { {HREF1}
+ * {HREF2} ... {HREFn} }.
+ *
+ * An HREF is a hypertext reference, i.e. hot-link or hypertext link to
+ * some other hypertext document that can be referenced by clicking on an
+ * anchor in the document being displayed.
+ */
+static int
+htmlGetHRefs (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ char *a_list, *lbuf, **list;
+ char buf[SZ_NUMBER];
+ int n;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ else
+ a_list = argv[1];
+
+ if (list = HTMLGetHRefs (wp->w, &n)) {
+ if (!(lbuf = makeList (list, n))) {
+ free ((char *)list);
+ return (TCL_ERROR);
+ }
+
+ if ((Tcl_SetVar (obm->tcl, a_list, lbuf, 0)) == NULL) { /* MF024 */
+ free ((char *)list);
+ XtFree (lbuf);
+ return (TCL_ERROR);
+ }
+
+ free ((char *)list);
+ XtFree (lbuf);
+ } else
+ n = 0;
+
+ sprintf (buf, "%d", n);
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* getImageSrcs -- Get a list of the image sources (SRC=) for all the
+ * inline images referenced by the document being displayed.
+ *
+ * Usage: n = getImageSrcs list
+ *
+ * The number of SRCs is returned as the function value; zero is returned
+ * if there are no SRCs, in which case "list" is undefined. If the document
+ * has SRCs on output the list will contain a list of SRCs in the form
+ * { {SRC1} {SRC2} ... {SRCn} }.
+ *
+ * A SRC is a HREF pointing to an image file.
+ */
+static int
+htmlGetImageSrcs (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ char *a_list, *lbuf, **list;
+ char buf[SZ_NUMBER];
+ int n;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ else
+ a_list = argv[1];
+
+ if (list = HTMLGetImageSrcs (wp->w, &n)) {
+ if (!(lbuf = makeList (list, n))) {
+ free ((char *)list);
+ return (TCL_ERROR);
+ }
+
+ if ((Tcl_SetVar (obm->tcl, a_list, lbuf, 0)) == NULL) { /* MF024 */
+ free ((char *)list);
+ XtFree (lbuf);
+ return (TCL_ERROR);
+ }
+
+ free ((char *)list);
+ XtFree (lbuf);
+ } else
+ n = 0;
+
+ sprintf (buf, "%d", n);
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* getLinks -- Get a list of the link tags (<LINK>) referenced by the
+ * document being displayed.
+ *
+ * Usage: n = getLinks list
+ *
+ * The number of links is returned as the function value; zero is returned
+ * if there are no links, in which case "list" is undefined. If there are
+ * any links the returned list will have the format { {{href} {role}} ...}
+ * where the structure {{href} {role}} describes each link.
+ */
+static int
+htmlGetLinks (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ char *a_list, *lbuf;
+ char buf[SZ_NUMBER];
+ LinkInfo *list;
+ int nchars, n;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ else
+ a_list = argv[1];
+
+ if (list = HTMLGetLinks (wp->w, &n)) {
+ register char *ip, *op;
+ register int i;
+
+ /* Determine how much storage we need for the list. */
+ for (i=0, nchars=0; i < n; i++) {
+ nchars += strlen (list[i].href) + 4;
+ nchars += strlen (list[i].role) + 4;
+ }
+ nchars += 5;
+
+ /* Get the storage. */
+ if (!(lbuf = op = XtMalloc (nchars))) {
+ free ((char *)list);
+ return (TCL_ERROR);
+ }
+
+ /* Encode the list as a Tcl list of lists. */
+ *op++ = '{'; *op++ = ' ';
+ for (i=0; i < n; i++) {
+ *op++ = '{';
+ *op++ = '{';
+ for (ip=list[i].href; ip && *ip; )
+ *op++ = *ip++;
+ *op++ = '}'; *op++ = ' ';
+ *op++ = '{';
+ for (ip=list[i].role; ip && *ip; )
+ *op++ = *ip++;
+ *op++ = '}';
+ *op++ = '}'; *op++ = ' ';
+ }
+ *op++ = '}';
+ *op++ = '\0';
+
+ if ((Tcl_SetVar (obm->tcl, a_list, lbuf, 0)) == NULL) { /* MF024 */
+ free ((char *)list);
+ XtFree (lbuf);
+ return (TCL_ERROR);
+ }
+
+ free ((char *)list);
+ XtFree (lbuf);
+ } else
+ n = 0;
+
+ sprintf (buf, "%d", n);
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* makeList -- Take a list of NULL terminated strings and turn it into a
+ * Tcl list of strings.
+ */
+static char *
+makeList (list, n)
+char **list;
+int n;
+{
+ register char *ip, *op;
+ register int i;
+ int nchars;
+ char *buf;
+
+ /* Determine how much storage we need for the list. */
+ for (i=0, nchars=0; i < n; i++)
+ nchars += strlen (list[i]) + 4;
+ nchars += 5;
+
+ /* Get the storage. */
+ if (!(buf = op = XtMalloc (nchars))) {
+ free ((char *)list);
+ return (NULL);
+ }
+
+ /* Encode the list as a Tcl list of strings. */
+ *op++ = '{'; *op++ = ' ';
+ for (i=0; i < n; i++) {
+ *op++ = '{';
+ for (ip=list[i]; ip && *ip; )
+ *op++ = *ip++;
+ *op++ = '}'; *op++ = ' ';
+ }
+ *op++ = '}';
+ *op++ = '\0';
+
+ return (buf);
+}
+
+
+/* retestAnchors -- Test each anchor and update the display to indicate
+ * the current status of the anchor.
+ *
+ * Usage: retestAnchors
+ *
+ * retestAnchors should be called after loading new text into a widget,
+ * or when the status of one or more anchors has changed, e.g. after a
+ * given URL has been visited.
+ */
+static int
+htmlRetestAnchors (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+
+ HTMLRetestAnchors (wp->w, NULL, 0);
+ return (TCL_OK);
+}
+
+
+/* setSelection -- Set the current text selection to the text bracketed by
+ * the input start and end element refs.
+ *
+ * Usage: setSelection start end
+ *
+ * "start" and "end" are elements refs such as returned by searchText.
+ * An element ref is a structure of the form {element_id offset} specifying
+ * the element id within the document, and the character offset within
+ * that element.
+ */
+static int
+htmlSetSelection (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ ElementRef start, end;
+ char *ip = (char *)NULL;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ ip = (char *)NULL;
+ start.id = strtol (&argv[1][1], &ip, 0);
+ start.pos = strtol (ip, &ip, 0);
+ if (ip == argv[1])
+ return (TCL_ERROR);
+
+ ip = (char *)NULL;
+ end.id = strtol (&argv[2][1], &ip, 0);
+ end.pos = strtol (ip, &ip, 0);
+ if (ip == argv[2])
+ return (TCL_ERROR);
+
+ HTMLSetSelection (wp->w, &start, &end);
+ return (TCL_OK);
+}
+
+
+/* getSelection -- Get the selected text, if any.
+ *
+ * Usage: text = getSelection
+ *
+ * An empty string is returned if there is no current text selection.
+ */
+static int
+htmlGetSelection (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ char *text, *start, *end, *insert;
+
+ text = HTMLGetTextAndSelection (wp->w, &start, &end, &insert);
+ if (text && start) {
+ int nchars = end - start + 1;
+ start[nchars] = '\0';
+ Tcl_SetResult (wp->obm->tcl, start, TCL_VOLATILE);
+ }
+
+ if (text)
+ free (text);
+ return (TCL_OK);
+}
+
+
+/* clearSelection -- Clear the current selection, if any.
+ *
+ * Usage: clearSelection
+ */
+static int
+htmlClearSelection (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+
+ HTMLClearSelection (wp->w);
+ return (TCL_OK);
+}
+
+
+/* searchText -- Search the document for the given pattern.
+ *
+ * Usage: bool = searchText pattern start end [direction [search_type]]
+ *
+ * direction "forward" or "backward"
+ * search_type "caseSensitive" or "caseless"
+ *
+ * If the search is successful start and end are set to the element refs
+ * of the matched region and the function returns a true (nonzero) value.
+ * False is returned if the search fails. An element ref is a structure of
+ * the form {element_id offset} specifying the element id within the document,
+ * and the character offset within that element. The search will automatically
+ * wrap around the page if not found initially.
+ *
+ */
+static int
+htmlSearchText (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register HTMLClassData gcd = (HTMLClassData) msg;
+ HTMLObject obj = (HTMLObject) gcd->object[gcd->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmContext obm = obj->widget.obm;
+ char *pattern, *a_start, *a_end;
+ int backward = 0, caseless = 1;
+ static ElementRef start, end;
+ static char patstr[64];
+ int status, again = 1;
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ pattern = argv[1];
+ a_start = argv[2];
+ a_end = argv[3];
+ backward = 0;
+ if (argc > 4)
+ backward = (strcmp (argv[4], "backward") == 0);
+ caseless = 0;
+ if (argc > 5)
+ caseless = (strcmp (argv[5], "caseless") == 0);
+
+ /* See whether the pattern has changed and we need to reset the
+ * start and end element refs.
+ */
+ if (strcmp (pattern, patstr) != 0) {
+retry: start.id = start.pos = 0;
+ end.id = end.pos = 0;
+ strcpy (patstr, "");
+ again = 0;
+ }
+
+ /* Do the search. */
+ status = HTMLSearchText (wp->w, pattern,
+ &start, &end, backward, caseless);
+
+ if (status == 1) {
+ char buf[SZ_LINE];
+ sprintf (buf, "{%d %d}", start.id, start.pos);
+ if ((Tcl_SetVar (obm->tcl, a_start, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ sprintf (buf, "{%d %d}", end.id, end.pos);
+ if ((Tcl_SetVar (obm->tcl, a_end, buf, 0)) == NULL) /* MF024 */
+ return (TCL_ERROR);
+ Tcl_SetResult (wp->obm->tcl, TRUESTR, TCL_STATIC);
+ } else {
+ if (again == 1)
+ goto retry;
+ Tcl_SetResult (wp->obm->tcl, FALSESTR, TCL_STATIC);
+ }
+
+ /* Save the pattern string so we can reset later if it changes. */
+ strcpy (patstr, pattern);
+
+ return (TCL_OK);
+}
+
+
+/* AddCallback -- Post a callback for a HTML widget event.
+ *
+ * Usage: addCallback procedure-name [callback-type]
+ *
+ * The recognized HTML callbacks are
+ *
+ * anchor Called to load a new URL.
+ *
+ * testAnchor Called to test whether a given URL has
+ * been previously visited.
+ *
+ * pointerMotion Called when the pointer enters an object
+ * which has a URL.
+ *
+ * submitForm Called when a form is submitted from within
+ * the document being viewed.
+ *
+ * link Called when a <LINK> tag is encountered
+ * while loading text.
+ *
+ * The default callback type is "anchor", which is called when the user
+ * selects a new URL while viewing a document.
+ */
+static int
+htmlAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ HTMLObject obj = (HTMLObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register HTMLPrivate hp = &obj->html;
+ register Widget w = wp->w;
+ char *userproc, *callback_type;
+ ObmCallback cb, new;
+ int type;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ userproc = argv[1];
+ callback_type = (argc > 2) ? argv[2] : "anchor";
+ if (!(type = cb_decode (callback_type)))
+ return (TCL_ERROR);
+
+ /* Initialize callback descriptor. */
+ new = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ new->u.obj = (ObmObject) obj;
+ new->callback_type = type;
+ strncpy (new->name, userproc, SZ_NAME);
+
+ /* Append descriptor to callback list for widget. */
+ for (cb = hp->callback_list; cb && cb->next; cb = cb->next)
+ ;
+ if (cb)
+ cb->next = new;
+ else
+ hp->callback_list = new;
+
+ return (TCL_OK);
+}
+
+
+/* DeleteCallback -- Delete a HTML callback.
+ *
+ * Usage: deleteCallback procedure [callback_type]
+ *
+ * If a callback type is specified all entries of type callback_type for
+ * the named procedure are deleted, else all entries of any type for the
+ * named procedure are deleted.
+ */
+static int
+htmlDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ HTMLObject obj = (HTMLObject) msg->object[msg->level];
+ register HTMLPrivate hp = &obj->html;
+ register ObmCallback cb, prev, next;
+ char *procedure, *callback_type;
+ int type;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ procedure = argv[1];
+ callback_type = (argc > 2) ? argv[2] : NULL;
+ type = callback_type ? cb_decode(callback_type) : 0;
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=hp->callback_list; cb; prev=cb, cb=next) {
+ next = cb->next;
+ if (strcmp (cb->name, procedure) == 0 &&
+ (!type || cb->callback_type == type)) {
+ if (prev)
+ prev->next = next;
+ else
+ hp->callback_list = next;
+ XtFree ((char *)cb);
+ }
+ }
+
+ return (TCL_OK);
+}
+
+
+/* anchorCallback -- Callback procedure called by the HTML widget when an
+ * anchor (URL) is selected.
+ *
+ * Calling sequence:
+ *
+ * userproc widget cbtype event text href element_id
+ *
+ * All callbacks registered with the current widget for the anchor callback
+ * are called in the order in which they were registered.
+ */
+static void
+anchorCallback (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+ register char *ip, *op;
+ register ObmCallback cb;
+ register WbAnchorCallbackData *ap = (WbAnchorCallbackData *)call_data;
+ HTMLObject obj = (HTMLObject) client_data;
+ ObmContext obm = obj->widget.obm;
+ char *text, *href, *none = "none";
+ char event_type[SZ_LINE];
+ char element_id[SZ_NUMBER];
+ int status;
+
+ text = ap->text ? ap->text : none;
+ href = ap->href ? ap->href : none;
+ sprintf (element_id, "%d", ap->element_id);
+ op = event_type;
+
+ /* Compose the event type information. This is the name of the
+ * key typed, or "Button1", "Button2", etc. for the mouse buttons.
+ */
+ switch (ap->event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyPressedEvent *ev = (XKeyPressedEvent *) ap->event;
+ char buf[20];
+ int n;
+
+ if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) {
+ for (ip=buf; --n >= 0; )
+ if (*ip <= ' ') {
+ *op++ = '^';
+ *op++ = *ip++ + 'A' - 1;
+ } else if (isprint (*ip)) {
+ *op++ = *ip++;
+ } else
+ ip++;
+ } else {
+ /* This case occurs when only a modifier is typed. */
+ for (ip = "??"; *op++ = *ip++; )
+ ;
+ }
+ *op = '\0';
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonPressedEvent *ev = (XButtonPressedEvent *) ap->event;
+ sprintf (op, "Button%d", ev->button);
+ }
+ break;
+ default:
+ strcpy (event_type, "unknown");
+ }
+
+ /* Call any registered callback functions. */
+ for (cb = obj->html.callback_list; cb; cb = cb->next) {
+ if (cb->callback_type != CB_Anchor)
+ continue;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ cb_encode(cb->callback_type), " ",
+ event_type, " ",
+ "{", text, "} ",
+ "{", href, "} ",
+ element_id,
+ NULL);
+
+ if (status != TCL_OK)
+ cb_error (obm, cb);
+ }
+}
+
+
+/* testAnchorCallback -- Callback procedure called by the HTML widget to
+ * test whether a given anchor (URL) has been previously visited.
+ *
+ * Calling sequence:
+ *
+ * userproc widget cbtype href
+ *
+ * A nonzero value should be returned by the userproc if the given anchor
+ * has been visited previously, otherwise a zero should be returned.
+ */
+static int
+testAnchorCallback (w, client_data, href)
+Widget w;
+XtPointer client_data;
+char *href;
+{
+ register ObmCallback cb;
+ register HTMLObject obj = (HTMLObject) client_data;
+ register ObmContext obm = obj->widget.obm;
+ int status, retval = 0;
+
+ /* Call any registered callback functions. */
+ for (cb = obj->html.callback_list; cb; cb = cb->next) {
+ if (cb->callback_type != CB_TestAnchor)
+ continue;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ cb_encode(cb->callback_type), " ",
+ "{", href, "} ",
+ NULL);
+
+ if (status != TCL_OK)
+ cb_error (obm, cb);
+ else if (atoi (obm->tcl->result))
+ retval = 1;
+ }
+
+ return (retval);
+}
+
+
+/* submitFormCallback -- Callback procedure called by the HTML widget when
+ * a form is submitted from the document.
+ *
+ * Calling sequence:
+ *
+ * userproc widget cbtype event attrs href method enctype encentity
+ *
+ * "widget" is the name of the HTML widget which generated the callback.
+ * "cbtype" is the type of callback, i.e., "submitForm". "event" is the
+ * key/button event which triggered the callback, e.g. "Button1".
+ *
+ * "attrs" is a list of attribute-value pairs defining the contents of the
+ * form. That is, a list of the form { {attr1 value1} {attr2 value2} ... }.
+ *
+ * The final block of arguments deal with how to process or deliver the form.
+ * "href", "method", "enctype", and "encentity" are strings defined by the
+ * HTML form. The application is free to use these as it wishes, except for
+ * an HTML form query where the meaning of these fields is well defined.
+ * The "href" field is normally the URL to which the form is to be submitted,
+ * while "method" is the method to be used to submit the form.
+ */
+static void
+submitFormCallback (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+ register char *ip, *op;
+ register ObmCallback cb;
+ register WbFormCallbackData *fp = (WbFormCallbackData *)call_data;
+ HTMLObject obj = (HTMLObject) client_data;
+ ObmContext obm = obj->widget.obm;
+
+ char *href, *method, *enctype, *encentity;
+ char *abuf, event_type[SZ_LINE];
+ char *none = "none";
+ int status, i, n;
+
+ href = fp->href ? fp->href : none;
+ method = fp->method ? fp->method : none;
+ enctype = fp->enctype ? fp->enctype : none;
+ encentity = fp->enc_entity ? fp->enc_entity : none;
+ op = event_type;
+
+ /* Compose the event type information. This is the name of the
+ * key typed, or "Button1", "Button2", etc. for the mouse buttons.
+ */
+ switch (fp->event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyPressedEvent *ev = (XKeyPressedEvent *) fp->event;
+ char buf[20];
+ int n;
+
+ if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) {
+ for (ip=buf; --n >= 0; )
+ if (*ip <= ' ') {
+ *op++ = '^';
+ *op++ = *ip++ + 'A' - 1;
+ } else if (isprint (*ip)) {
+ *op++ = *ip++;
+ } else
+ ip++;
+ } else {
+ /* This case occurs when only a modifier is typed. */
+ for (ip = "??"; *op++ = *ip++; )
+ ;
+ }
+ *op = '\0';
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonPressedEvent *ev = (XButtonPressedEvent *) fp->event;
+ sprintf (op, "Button%d", ev->button);
+ }
+ break;
+ default:
+ strcpy (event_type, "unknown");
+ }
+
+ /* Get storage for the attribute list. */
+ for (i=0, n=0; i < fp->attribute_count; i++) {
+ n += strlen (fp->attribute_names[i]);
+ n += strlen (fp->attribute_values[i]);
+ n += 10;
+ }
+ if (!(abuf = XtMalloc (n)))
+ return;
+
+ /* Construct the attribute list.
+ */
+ for (i=0, op=abuf; i < fp->attribute_count; i++) {
+ *op++ = '{';
+
+ *op++ = '{';
+ for (ip = fp->attribute_names[i]; ip && *ip; )
+ *op++ = *ip++;
+ *op++ = '}'; *op++ = ' ';
+
+ *op++ = '{';
+ for (ip = fp->attribute_values[i]; ip && *ip; )
+ *op++ = *ip++;
+ *op++ = '}';
+
+ *op++ = '}'; *op++ = ' ';
+ }
+ *op = '\0';
+
+ /* Call any registered callback functions. */
+ for (cb = obj->html.callback_list; cb; cb = cb->next) {
+ if (cb->callback_type != CB_SubmitForm)
+ continue;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ cb_encode(cb->callback_type), " ",
+ event_type, " ",
+ "{ ", abuf, "} ",
+ href, " ",
+ method, " ",
+ enctype, " ",
+ encentity, " ",
+ NULL);
+
+ if (status != TCL_OK)
+ cb_error (obm, cb);
+ }
+
+ XtFree (abuf);
+}
+
+
+/* linkCallback -- Callback procedure called by the HTML widget when
+ * a <LINK> directive is encountered while loading text into the widget.
+ *
+ * Calling sequence:
+ *
+ * userproc widget cbtype href role
+ *
+ * All callbacks registered with the current widget for the callback
+ * are called in the order in which they were registered.
+ */
+static void
+linkCallback (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+ register char *ip, *op;
+ register ObmCallback cb;
+ LinkInfo *l_info = (LinkInfo *) call_data;
+ HTMLObject obj = (HTMLObject) client_data;
+ ObmContext obm = obj->widget.obm;
+ char *href, *role, *none = "none";
+ int status;
+
+ href = l_info->href ? l_info->href : none;
+ role = l_info->role ? l_info->role : none;
+
+ /* Call any registered callback functions. */
+ for (cb = obj->html.callback_list; cb; cb = cb->next) {
+ if (cb->callback_type != CB_Link)
+ continue;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ cb_encode(cb->callback_type), " ",
+ href, " ",
+ role, " ",
+ NULL);
+
+ if (status != TCL_OK)
+ cb_error (obm, cb);
+ }
+}
+
+
+/* pointerMotionCallback -- Callback procedure called by the HTML widget when
+ * the pointer enters an anchor.
+ *
+ * Calling sequence:
+ *
+ * userproc widget cbtype href
+ */
+static void
+pointerMotionCallback (w, client_data, href)
+Widget w;
+XtPointer client_data;
+char *href;
+{
+ register ObmCallback cb;
+ register HTMLObject obj = (HTMLObject) client_data;
+ register ObmContext obm = obj->widget.obm;
+ int status;
+
+ /* Call any registered callback functions. */
+ for (cb = obj->html.callback_list; cb; cb = cb->next) {
+ if (cb->callback_type != CB_PointerMotion)
+ continue;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ cb_encode(cb->callback_type), " ",
+ "{", href, "} ",
+ NULL);
+
+ if (status != TCL_OK)
+ cb_error (obm, cb);
+ }
+}
+
+
+/* cb_error -- Convenience routine to return an error from a callback.
+ */
+static void
+cb_error (obm, cb)
+register ObmContext obm;
+register ObmCallback cb;
+{
+ register Tcl_Interp *tcl = obm->tcl;
+ char *errstr = Tcl_GetVar (tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ tcl->errorLine, cb->name,
+ errstr ? errstr : tcl->result);
+}
+
+/* cb_decode -- Convert a callback_type string to a callback type code.
+ */
+static int
+cb_decode (callback_type)
+register char *callback_type;
+{
+ register int type = 0;
+
+ if (strcmp (callback_type, "anchor") == 0)
+ type = CB_Anchor;
+ else if (strcmp (callback_type, "testAnchor") == 0)
+ type = CB_TestAnchor;
+ else if (strcmp (callback_type, "pointerMotion") == 0)
+ type = CB_PointerMotion;
+ else if (strcmp (callback_type, "submitForm") == 0)
+ type = CB_SubmitForm;
+ else if (strcmp (callback_type, "link") == 0)
+ type = CB_Link;
+
+ return (type);
+}
+
+/* cb_encode -- Convert a callback_type string to a callback type code.
+ */
+static char *
+cb_encode (callback_type)
+int callback_type;
+{
+ register char *type = "unknown";
+
+ switch (callback_type) {
+ case CB_Anchor:
+ type = "anchor";
+ break;
+ case CB_TestAnchor:
+ type = "testAnchor";
+ break;
+ case CB_PointerMotion:
+ type = "pointerMotion";
+ break;
+ case CB_SubmitForm:
+ type = "submitForm";
+ break;
+ case CB_Link:
+ type = "link";
+ break;
+ }
+
+ return (type);
+}
diff --git a/vendor/x11iraf/obm/listres/AllWidgets.c b/vendor/x11iraf/obm/listres/AllWidgets.c
new file mode 100644
index 00000000..7de2cf94
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/AllWidgets.c
@@ -0,0 +1,151 @@
+/*
+ * This file is generated by the genlist.sh script and contains an array of
+ * all the widgets in Athena widget set.
+ *
+ * $XConsortium: AllWidgets.c,v 1.4 90/03/02 15:34:13 jim Exp $
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/Xmu/WidgetNode.h>
+
+extern WidgetClass applicationShellWidgetClass;
+extern WidgetClass asciiSinkObjectClass;
+extern WidgetClass asciiSrcObjectClass;
+extern WidgetClass asciiTextWidgetClass;
+extern WidgetClass boxWidgetClass;
+extern WidgetClass commandWidgetClass;
+extern WidgetClass compositeWidgetClass;
+extern WidgetClass constraintWidgetClass;
+extern WidgetClass coreWidgetClass;
+extern WidgetClass dialogWidgetClass;
+extern WidgetClass formWidgetClass;
+extern WidgetClass gripWidgetClass;
+extern WidgetClass htmlWidgetClass;
+extern WidgetClass labelWidgetClass;
+extern WidgetClass layoutWidgetClass;
+extern WidgetClass listWidgetClass;
+extern WidgetClass menuButtonWidgetClass;
+extern WidgetClass objectClass;
+extern WidgetClass overrideShellWidgetClass;
+extern WidgetClass panedWidgetClass;
+extern WidgetClass pannerWidgetClass;
+extern WidgetClass portholeWidgetClass;
+extern WidgetClass rectObjClass;
+extern WidgetClass repeaterWidgetClass;
+extern WidgetClass scrollbarWidgetClass;
+extern WidgetClass shellWidgetClass;
+extern WidgetClass simpleMenuWidgetClass;
+extern WidgetClass simpleWidgetClass;
+extern WidgetClass smeBSBObjectClass;
+extern WidgetClass smeLineObjectClass;
+extern WidgetClass smeObjectClass;
+extern WidgetClass smeThreeDObjectClass;
+extern WidgetClass stripChartWidgetClass;
+extern WidgetClass textSinkObjectClass;
+extern WidgetClass textSrcObjectClass;
+extern WidgetClass textWidgetClass;
+extern WidgetClass threeDWidgetClass;
+extern WidgetClass toggleWidgetClass;
+extern WidgetClass topLevelShellWidgetClass;
+extern WidgetClass transientShellWidgetClass;
+extern WidgetClass treeWidgetClass;
+extern WidgetClass vendorShellWidgetClass;
+extern WidgetClass viewportWidgetClass;
+extern WidgetClass wmShellWidgetClass;
+
+extern WidgetClass gtermWidgetClass;
+extern WidgetClass xfwfArrowWidgetClass;
+extern WidgetClass xfwfBoardWidgetClass;
+extern WidgetClass xfwfButtonWidgetClass;
+extern WidgetClass xfwfCommonWidgetClass;
+extern WidgetClass xfwfFrameWidgetClass;
+extern WidgetClass xfwfGroupWidgetClass;
+extern WidgetClass xfwfIconWidgetClass;
+extern WidgetClass xfwfLabelWidgetClass;
+extern WidgetClass xfwfMenuBarWidgetClass;
+extern WidgetClass xfwfMultiListWidgetClass;
+extern WidgetClass xfwfRadioGroupWidgetClass;
+extern WidgetClass xfwfRowColWidgetClass;
+extern WidgetClass xfwfScrollbarWidgetClass;
+extern WidgetClass xfwfSlider2WidgetClass;
+extern WidgetClass xfwfToggleWidgetClass;
+extern WidgetClass tabsWidgetClass;
+extern WidgetClass listtreeWidgetClass;
+extern WidgetClass separatorWidgetClass;
+extern WidgetClass tableWidgetClass;
+/*
+extern WidgetClass scrolledTableWidgetClass;
+*/
+
+XmuWidgetNode XawWidgetArray[] = {
+{ "applicationShell", &applicationShellWidgetClass },
+{ "asciiSink", &asciiSinkObjectClass },
+{ "asciiSink", &asciiSinkObjectClass },
+{ "asciiSrc", &asciiSrcObjectClass },
+{ "asciiText", &asciiTextWidgetClass },
+{ "box", &boxWidgetClass },
+{ "command", &commandWidgetClass },
+{ "composite", &compositeWidgetClass },
+{ "constraint", &constraintWidgetClass },
+{ "core", &coreWidgetClass },
+{ "dialog", &dialogWidgetClass },
+{ "form", &formWidgetClass },
+{ "grip", &gripWidgetClass },
+{ "label", &labelWidgetClass },
+{ "list", &listWidgetClass },
+{ "menuButton", &menuButtonWidgetClass },
+{ "object", &objectClass },
+{ "overrideShell", &overrideShellWidgetClass },
+{ "paned", &panedWidgetClass },
+{ "panner", &pannerWidgetClass },
+{ "porthole", &portholeWidgetClass },
+{ "rect", &rectObjClass },
+{ "repeater", &repeaterWidgetClass },
+{ "scrollbar", &scrollbarWidgetClass },
+{ "shell", &shellWidgetClass },
+{ "simpleMenu", &simpleMenuWidgetClass },
+{ "simple", &simpleWidgetClass },
+{ "smeBSB", &smeBSBObjectClass },
+{ "smeLine", &smeLineObjectClass },
+{ "smeThreeD", &smeThreeDObjectClass },
+{ "sme", &smeObjectClass },
+{ "stripChart", &stripChartWidgetClass },
+{ "textSink", &textSinkObjectClass },
+{ "textSrc", &textSrcObjectClass },
+{ "text", &textWidgetClass },
+{ "threeD", &threeDWidgetClass },
+{ "toggle", &toggleWidgetClass },
+{ "topLevelShell", &topLevelShellWidgetClass },
+{ "transientShell", &transientShellWidgetClass },
+{ "tree", &treeWidgetClass },
+{ "vendorShell", &vendorShellWidgetClass },
+{ "viewport", &viewportWidgetClass },
+{ "wmShell", &wmShellWidgetClass },
+
+{ "arrow", &xfwfArrowWidgetClass },
+{ "gterm", &gtermWidgetClass },
+{ "layout", &layoutWidgetClass },
+{ "html", &htmlWidgetClass },
+{ "board", &xfwfBoardWidgetClass },
+{ "frame", &xfwfFrameWidgetClass },
+{ "group", &xfwfGroupWidgetClass },
+{ "icon", &xfwfIconWidgetClass },
+{ "multiList", &xfwfMultiListWidgetClass },
+{ "radioGroup", &xfwfRadioGroupWidgetClass },
+{ "rowCol", &xfwfRowColWidgetClass },
+{ "textBox", &xfwfLabelWidgetClass },
+{ "textButton", &xfwfButtonWidgetClass },
+{ "textToggle", &xfwfToggleWidgetClass },
+{ "scrollbar2", &xfwfScrollbarWidgetClass },
+{ "slider2d", &xfwfSlider2WidgetClass },
+
+{ "listtree", &listtreeWidgetClass },
+{ "tabs", &tabsWidgetClass },
+{ "separator", &separatorWidgetClass },
+{ "table", &tableWidgetClass },
+/*
+{ "scrolledtable", &scrolledTableWidgetClass },
+*/
+};
+
+int XawWidgetCount = XtNumber(XawWidgetArray);
+
diff --git a/vendor/x11iraf/obm/listres/AllWidgets.h b/vendor/x11iraf/obm/listres/AllWidgets.h
new file mode 100644
index 00000000..cded7fcb
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/AllWidgets.h
@@ -0,0 +1,33 @@
+/*
+ * $XConsortium: AllWidgets.h,v 1.2 90/02/26 12:00:56 jim Exp $
+ *
+ * Copyright 1990 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _XawAllWidgets_h
+#define _XawAllWidgets_h
+
+/*
+ * This file matches the generated AllWidgets.c
+ */
+extern XmuWidgetNode XawWidgetArray[];
+extern int XawWidgetCount;
+
+#endif /* _XawAllWidgets_h */
diff --git a/vendor/x11iraf/obm/listres/Imakefile b/vendor/x11iraf/obm/listres/Imakefile
new file mode 100644
index 00000000..6e542d74
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/Imakefile
@@ -0,0 +1,20 @@
+XCOMM $XConsortium: Imakefile,v 1.13 91/07/17 00:48:25 gildea Exp $
+
+ DEPLIBS = XawClientDepLibs
+LOCAL_LIBRARIES = XawClientLibs
+ SYS_LIBRARIES = -lm
+
+ CDEBUGFLAGS = -O
+ XAWLIB = -lXaw3d # set to Xaw3d for 3d look
+ LOCAL_LDFLAGS = -L../../lib
+ EXTRA_INCLUDES = -I../../include
+ OBMLIBS = -lobm -lXpm
+ MATHLIB = -lm
+ DEPOBM = ../libobm.a
+ SRCS = listres.c AllWidgets.c
+ OBJS = listres.o AllWidgets.o
+
+AllTarget(listres)
+NormalProgramTarget(listres,$(OBJS),${DEPOBM},${OBMLIBS} XawClientLibs, $(MATHLIB))
+
+${DEPOBM}:
diff --git a/vendor/x11iraf/obm/listres/Makefile.bak b/vendor/x11iraf/obm/listres/Makefile.bak
new file mode 100644
index 00000000..1944175c
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/Makefile.bak
@@ -0,0 +1,587 @@
+# Makefile generated by imake - do not edit!
+# $XConsortium: imake.c,v 1.89 94/08/12 00:45:51 gildea Exp $
+
+# -----------------------------------------------------------------------
+# Makefile generated from "Imake.tmpl" and <Imakefile>
+# $XConsortium: Imake.tmpl,v 1.219 94/05/13 15:58:31 matt Exp $
+# $SunSoft: @(#)Imake.tmpl 1.1 01/13/97 16:16:22 $
+#
+
+# **************************************************************************
+# NOTE:
+#
+# If the user does not define DESTDIR and/or BINDIR in the local Imakefile,
+# 'make install' will install the resultant binaries in /usr/openwin/bin.
+# This usually fails because of lack of write permission in that directory
+# for non-root users.
+#
+# The reason is that the default definition of ProjectRoot is /usr/openwin.
+# This value determines all other definitions, e.g. the binary, library and
+# manual page directories, etc. The destination directory, DESTDIR, is not
+# defined and BINDIR is defined as $(ProjectRoot)/bin in Project.tmpl.
+#
+# Care must be taken when changing ProjectRoot. It affects the inclusion
+# path of 'imake' in finding the *.cf, *.def, *.tmpl and *.rules files,
+# which are in /usr/openwin/lib/X11/config/, and the default inclusion path
+# of X11 header files and libraries. Therefore, if ProjectRoot is changed
+# not only these configuration files need to be copied to a proper location,
+# defined by IRULESRC, so 'make Makefile' can work properly, the header file
+# inclusion path, /usr/openwin/include, and the library search path,
+# /usr/openwin/lib, also need to be defined properly either in the local
+# Imakefile or one of the configuration files to avoid compilation errors
+# for programs that use X11 header files or libraries.
+#
+# Please refer to Project.tmpl, Imake.tmpl, site.def, etc. in
+# /usr/openwin/lib/X11/config/ for details.
+# **************************************************************************
+
+.SUFFIXES: .i
+
+# $XConsortium: Imake.cf,v 1.12 94/03/29 15:42:08 gildea Exp $
+# $SunSoft: @(#)Imake.cf 1.1 01/13/97 16:16:21 $
+
+# -----------------------------------------------------------------------
+# site-specific configuration parameters that need to come before
+# the platform-specific parameters - edit site.def to change
+
+# site: $XConsortium: site.sample,v 1.11 94/06/03 19:50:12 matt Exp $
+# site: $SunSoft: @(#)site.def 1.1 01/13/97 16:16:27$
+
+# -----------------------------------------------------------------------
+# platform-specific configuration parameters - edit sun.cf to change
+
+# platform: $XConsortium: sun.cf,v 1.133 94/07/08 12:23:12 gildea Exp $
+# platform: $SunSoft: @(#)sun.cf 1.5 08/25/99 12:27:05 $
+
+# operating system: SunOS 5.8
+
+# SUNSOFT SUNSOFT_LOADABLE
+
+# $XConsortium: svr4.cf,v 1.6 94/04/08 18:56:33 rws Exp $
+# $SunSoft: @(#)svr4.cf 1.1 01/13/97 16:16:29 $
+
+# $XConsortium: sv4Lib.rules,v 1.14 94/04/09 12:00:10 rws Exp $
+# $SunSoft: @(#)sv4Lib.rules 1.1 01/13/97 16:16:28 $
+
+# SUNSOFT SUNSOFT_LOADABLE
+
+ TROFFTOPS = /usr/lib/lp/postscript/dpost | /usr/lib/lp/postscript/postreverse -r
+
+# -----------------------------------------------------------------------
+# site-specific configuration parameters that go after
+# the platform-specific parameters - edit site.def to change
+
+# site: $XConsortium: site.sample,v 1.11 94/06/03 19:50:12 matt Exp $
+# site: $SunSoft: @(#)site.def 1.1 01/13/97 16:16:27$
+
+# -----------------------------------------------------------------------
+# Imake rules for building libraries, programs, scripts, and data files
+# rules: $XConsortium: Imake.rules,v 1.193 94/04/10 17:39:55 rws Exp $
+# rules: $SunSoft: @(#)Imake.rules 1.1 01/13/97 16:16:21 $
+
+# SUNSOFT SUNSOFT_LOADABLE
+
+ PATHSEP = /
+ SHELL = /bin/sh
+
+ TOP = .
+ CURRENT_DIR = .
+
+ IMAKE = imake
+ DEPEND = makedepend
+ MKDIRHIER = mkdirhier
+ CONFIGSRC = $(TOP)/config
+ IMAKESRC = $(CONFIGSRC)/imake
+ DEPENDSRC = $(CONFIGSRC)/makedepend
+ IXXSRC = $(UNSUPPORTEDSRC)/programs/ixx
+ IXX = ixx
+ IXXFLAGS = -s BaseObject -m TypeObj -r RequestObj -p Xf
+ IXXINCLUDES = -i '<X11/Fresco/enter-scope.h>'
+
+ INCROOT = /usr/openwin/include
+ USRLIBDIR = /usr/openwin/lib
+ SHLIBDIR = /usr/openwin/lib
+ LINTLIBDIR = $(USRLIBDIR)
+ MANPATH = /usr/openwin/share/man
+ MANSOURCEPATH = $(MANPATH)/man
+ MANDIR = $(MANSOURCEPATH)1
+ LIBMANDIR = $(MANSOURCEPATH)3
+ FILEMANDIR = $(MANSOURCEPATH)$(FILEMANSUFFIX)
+
+ AR = /usr/ccs/bin/ar cq
+ BOOTSTRAPCFLAGS = -DSVR4
+ CC = cc
+ AS = /usr/ccs/bin/as
+
+ COMPRESS = compress
+ CPP = /usr/ccs/lib/cpp $(STD_CPP_DEFINES)
+ PREPROCESSCMD = cc -E $(STD_CPP_DEFINES)
+ INSTALL = /usr/ucb/install
+ INSTALLFLAGS = -c
+ LD = /usr/ccs/bin/ld
+ LEX = /usr/ccs/bin/lex
+ LEXLIB = -ll
+ YACC = /usr/ccs/bin/yacc
+ CCYACC = /usr/ccs/bin/yacc
+ LINT = lint
+ LINTLIBFLAG = -y -o
+ LINTOPTS = -b -h -Xc
+ LN = ln -s
+ MAKE = /usr/ccs/bin/make
+ MV = mv
+ CP = cp
+
+ RM = rm -f
+ MANSUFFIX = 1
+ LIBMANSUFFIX = 3
+ FILEMANSUFFIX = 4
+ TROFF = troff -t -Tpost
+ MSMACROS = -ms
+ TBL = tbl
+ EQN = eqn
+
+ DVIPS = dvips
+ LATEX = latex
+
+ STD_INCLUDES =
+ STD_CPP_DEFINES = -Dsun -Dsparc -DSVR4 -DSYSV
+ STD_DEFINES = -Dsun -Dsparc -DSVR4 -DSYSV
+ EXTRA_LOAD_FLAGS =
+ EXTRA_LDOPTIONS =
+ EXTRA_LIBRARIES = -lsocket -lnsl
+ TAGS = ctags
+
+ SHAREDCODEDEF =
+ SHLIBDEF =
+
+ SHLIBLDFLAGS = -G -z text -M mapfile
+
+ PICFLAGS = -Kpic
+
+ CXXPICFLAGS = -K PIC
+
+ PROTO_DEFINES =
+
+ INSTPGMFLAGS =
+
+ INSTBINFLAGS = -m 0755
+ INSTUIDFLAGS = -m 4755
+ INSTLIBFLAGS = -m 0644
+ INSTINCFLAGS = -m 0644
+ INSTMANFLAGS = -m 0444
+ INSTDATFLAGS = -m 0444
+ INSTKMEMFLAGS = -g sys -m 2755
+
+ PROJECTROOT = /usr/openwin
+
+ TOP_INCLUDES = -I$(INCROOT)
+
+ CDEBUGFLAGS = -g
+ CCOPTIONS = -Xc -xF -xcg92
+
+ ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(STD_INCLUDES)
+ ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(EXTRA_DEFINES) $(PROTO_DEFINES) $(THREADS_DEFINES) $(DEFINES)
+ CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(THREADS_CFLAGS) $(ALLDEFINES)
+ LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) $(DEPEND_DEFINES)
+ LDPRELIB = -L$(USRLIBDIR)
+ LDPOSTLIB =
+ LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_LDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIB)
+ CXXLDOPTIONS = $(CXXDEBUGFLAGS) $(CXXOPTIONS) $(EXTRA_LDOPTIONS) $(THREADS_CXXLDFLAGS) $(LOCAL_LDFLAGS) $(LDPRELIB)
+
+ LDLIBS = $(LDPOSTLIB) $(THREADS_LIBS) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
+
+ CCENVSETUP = LD_RUN_PATH=$(USRLIBDIR)
+ CCLINK = $(CCENVSETUP) $(CC)
+
+ CXXENVSETUP = LD_RUN_PATH=$(USRLIBDIR)
+ CXXLINK = $(CXXENVSETUP) $(CXX)
+
+ LDSTRIPFLAGS = -x
+ LDCOMBINEFLAGS = -r
+ DEPENDFLAGS =
+
+ MACROFILE = sun.cf
+ RM_CMD = $(RM)
+
+ IMAKE_DEFINES =
+
+ IRULESRC = $(CONFIGDIR)
+ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES)
+
+ ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Project.tmpl \
+ $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) \
+ $(EXTRA_ICONFIGFILES)
+
+# -----------------------------------------------------------------------
+# X Window System Build Parameters and Rules
+# $XConsortium: Project.tmpl,v 1.242 94/04/13 14:58:40 rws Exp $
+# $SunSoft: @(#)Project.tmpl 1.4 12/15/98 10:56:11 $
+
+# SUNSOFT SUNSOFT_LOADABLE
+
+# -----------------------------------------------------------------------
+# X Window System make variables; these need to be coordinated with rules
+
+ BINDIR = /usr/openwin/bin
+ BUILDINCROOT = $(TOP)
+ BUILDINCDIR = $(BUILDINCROOT)/X11
+ BUILDINCTOP = ..
+ BUILDLIBDIR = $(TOP)/usrlib
+ BUILDLIBTOP = ..
+ INCDIR = $(INCROOT)/X11
+ ADMDIR = /usr/adm
+ LIBDIR = $(USRLIBDIR)/X11
+
+ FONTDIR = $(LIBDIR)/fonts
+ XINITDIR = $(LIBDIR)/xinit
+ XDMDIR = $(LIBDIR)/xdm
+ TWMDIR = $(LIBDIR)/twm
+ NLSDIR = $(LIBDIR)/nls
+ XLOCALEDIR = $(PROJECTROOT)/lib/locale
+ PEXAPIDIR = $(LIBDIR)/PEX
+ XAPPLOADDIR = $(LIBDIR)/app-defaults
+ FONTCFLAGS = -t
+
+ INSTAPPFLAGS = $(INSTDATFLAGS)
+
+ RGB = rgb
+ FONTC = bdftopcf
+ MKFONTDIR = mkfontdir
+
+ DOCUTILSRC = $(TOP)/doc/util
+ XDOCMACROS = $(DOCUTILSRC)/macros.t
+ XIDXMACROS = $(DOCUTILSRC)/indexmacros.t
+ PROGRAMSRC = $(TOP)/programs
+ LIBSRC = $(TOP)/lib
+ FONTSRC = $(TOP)/fonts
+ INCLUDESRC = $(TOP)/X11
+ SERVERSRC = $(TOP)/programs/Xserver
+ CONTRIBSRC = $(TOP)/../contrib
+ UNSUPPORTEDSRC = $(TOP)/unsupported
+ DOCSRC = $(TOP)/doc
+ RGBSRC = $(TOP)/programs/rgb
+ BDFTOPCFSRC = $(PROGRAMSRC)/bdftopcf
+ MKFONTDIRSRC = $(PROGRAMSRC)/mkfontdir
+ FONTSERVERSRC = $(PROGRAMSRC)/xfs
+ FONTINCSRC = $(TOP)/include/fonts
+ EXTINCSRC = $(TOP)/include/extensions
+ TRANSCOMMSRC = $(LIBSRC)/xtrans
+ TRANS_INCLUDES = -I$(TRANSCOMMSRC)
+
+# $XConsortium: sunLib.tmpl,v 1.37 95/05/23 14:31:40 matt Exp $
+# $SunSoft: @(#)sunLib.tmpl 1.2 02/06/97 16:06:36 $
+
+# $XConsortium: sv4Lib.tmpl,v 1.19 93/12/03 10:48:36 kaleb Exp $
+# $SunSoft: @(#)sv4Lib.tmpl 1.1 01/13/97 16:16:29 $
+
+XMULIBONLY = -lXmu -lm
+XMULIB = -lXmu -lm
+
+ SERVERLIB = /usr/openwin/server/lib
+
+ SERVERMODULES = /usr/openwin/server/modules
+
+ SERVERETC = /usr/openwin/server/etc
+
+SHLIBLDFLAGS = -G -z text -M mapfile
+PICFLAGS = -Kpic
+MAPFILE = mapfile
+
+ XLIBSRC = $(LIBSRC)/X11
+
+SOXLIBREV = 4
+DEPXONLYLIB =
+XONLYLIB = -lX11
+
+LINTXONLY = $(LINTLIBDIR)/llib-lX11.ln
+
+ XLIBONLY = $(XONLYLIB)
+
+ XEXTLIBSRC = $(LIBSRC)/Xext
+
+SOXEXTREV = 0
+DEPEXTENSIONLIB =
+EXTENSIONLIB = -lXext
+
+LINTEXTENSION = $(LINTLIBDIR)/llib-lXext.ln
+
+LINTEXTENSIONLIB = $(LINTEXTENSION)
+ DEPXLIB = $(DEPEXTENSIONLIB) $(DEPXONLYLIB)
+ XLIB = $(EXTENSIONLIB) $(XONLYLIB)
+ LINTXLIB = $(LINTXONLYLIB)
+
+ XAUTHSRC = $(LIBSRC)/Xau
+
+DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
+XAUTHLIB = -lXau
+
+LINTXAUTH = $(LINTLIBDIR)/llib-lXau.ln
+
+ XDMCPLIBSRC = $(LIBSRC)/Xdmcp
+
+DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a
+XDMCPLIB = -lXdmcp
+
+LINTXDMCP = $(LINTLIBDIR)/llib-lXdmcp.ln
+
+ XMUSRC = $(LIBSRC)/Xmu
+
+SOXMUREV = 4
+DEPXMULIB =
+XMULIB = -lXmu
+
+LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln
+
+XMULIB = -lXmu -lm
+
+ XCONFIGSRC = $(LIBSRC)/Xconfig
+
+SOXCONFIGREV = 0
+DEPXCONFIGLIB =
+XCONFIGLIB = -lXconfig
+
+LINTXCONFIG = $(LINTLIBDIR)/llib-lXconfig.ln
+
+ DGASRC = $(LIBSRC)/dga
+
+SODGAREV = 1
+DEPDGASRCLIB =
+DGASRCLIB = -ldga
+
+LINTDGASRC = $(LINTLIBDIR)/llib-ldga.ln
+
+ MISRC = $(SERVERSRC)/mi
+
+SOMIREV = 1
+DEPMILIB =
+MILIB = -lmi
+
+LINTMI = $(LINTLIBDIR)/llib-lmi.ln
+
+ MFBSRC = $(SERVERSRC)/mfb
+
+SOMFBREV = 1
+DEPMFBLIB =
+MFBLIB = -lmfb
+
+LINTMFB = $(LINTLIBDIR)/llib-lmfb.ln
+
+ CFBSRC = $(SERVERSRC)/cfb
+
+SOCFBREV = 1
+DEPCFBLIB =
+CFBLIB = -lcfb
+
+LINTCFB = $(LINTLIBDIR)/llib-lcfb.ln
+
+ OLDXLIBSRC = $(LIBSRC)/oldX
+
+SOOLDXREV = 6
+DEPOLDXLIB =
+OLDXLIB = -loldX
+
+LINTOLDX = $(LINTLIBDIR)/llib-loldX.ln
+
+ TOOLKITSRC = $(LIBSRC)/Xt
+
+SOXTREV = 4
+DEPXTOOLONLYLIB =
+XTOOLONLYLIB = -lXt
+
+LINTXTOOLONLY = $(LINTLIBDIR)/llib-lXt.ln
+
+ DEPXTOOLLIB = $(DEPXTOOLONLYLIB) $(DEPSMLIB) $(DEPICELIB)
+ XTOOLLIB = $(XTOOLONLYLIB) $(SMLIB) $(ICELIB)
+ LINTXTOOLLIB = $(LINTXTOOLONLYLIB)
+
+ AWIDGETSRC = $(LIBSRC)/Xaw
+
+SOXAWREV = 5
+DEPXAWLIB =
+XAWLIB = -lXaw
+
+LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln
+
+ XTFSRC = $(TOP)/workInProgress/Xtf
+
+SOXTFREV = 0.7
+DEPXTFLIB =
+XTFLIB = -lXtf
+
+LINTXTF = $(LINTLIBDIR)/llib-lXtf.ln
+
+ FRESCOSRC = $(TOP)/workInProgress/Fresco
+
+SOFRESCOREV = 0.7
+DEPFRESCOLIB =
+FRESCOLIB = -lFresco
+
+LINTFRESCO = $(LINTLIBDIR)/llib-lFresco.ln
+
+ XILIBSRC = $(LIBSRC)/Xi
+
+SOXINPUTREV = 5
+DEPXILIB =
+XILIB = -lXi
+
+LINTXI = $(LINTLIBDIR)/llib-lXi.ln
+
+ XTESTLIBSRC = $(LIBSRC)/Xtst
+
+SOXTESTREV = 1
+DEPXTESTLIB =
+XTESTLIB = -lXtst
+
+LINTXTEST = $(LINTLIBDIR)/llib-lXtst.ln
+
+ PEXLIBSRC = $(LIBSRC)/PEX5
+
+SOPEXREV = 6
+DEPPEXLIB =
+PEXLIB = -lPEX5
+
+LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln
+
+SODPSREV = 5
+SOSERVERDPSREV = 5
+
+ DPSLIBSRC = $(LIBSRC)/DPS
+
+SODPSREV = 5
+DEPDPSLIB =
+DPSLIB = -lDPS
+
+LINTDPS = $(LINTLIBDIR)/llib-lDPS.ln
+
+ XIELIBSRC = $(LIBSRC)/XIE
+
+SOXIEREV = 6
+DEPXIELIB =
+XIELIB = -lXIE
+
+LINTXIE = $(LINTLIBDIR)/llib-lXIE.ln
+
+ PHIGSLIBSRC = $(LIBSRC)/PHIGS
+
+DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a
+PHIGSLIB = -lphigs
+
+LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln
+
+DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a
+XBSDLIB = -lXbsd
+
+LINTXBSD = $(LINTLIBDIR)/llib-lXbsd.ln
+
+ ICESRC = $(LIBSRC)/ICE
+
+SOICEREV = 6
+DEPICELIB =
+ICELIB = -lICE
+
+LINTICE = $(LINTLIBDIR)/llib-lICE.ln
+
+ SMSRC = $(LIBSRC)/SM
+
+SOSMREV = 6
+DEPSMLIB =
+SMLIB = -lSM
+
+LINTSM = $(LINTLIBDIR)/llib-lSM.ln
+
+ FSLIBSRC = $(LIBSRC)/FS
+
+SOFSREV = 5
+DEPFSLIB =
+FSLIB = -lFS
+
+LINTFS = $(LINTLIBDIR)/llib-lFS.ln
+
+ FONTLIBSRC = $(LIBSRC)/font
+
+DEPFONTLIB = $(USRLIBDIR)/libfont.a
+FONTLIB = -lfont
+
+LINTFONT = $(LINTLIBDIR)/llib-lfont.ln
+
+ DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
+
+ DEPLIBS1 = $(DEPLIBS)
+ DEPLIBS2 = $(DEPLIBS)
+ DEPLIBS3 = $(DEPLIBS)
+
+ CONFIGDIR = $(LIBDIR)/config
+
+# -----------------------------------------------------------------------
+# start of Imakefile
+
+# $XConsortium: Imakefile,v 1.13 91/07/17 00:48:25 gildea Exp $
+
+ DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
+LOCAL_LIBRARIES = $(XAWLIB) $(XMULIBONLY) $(XTOOLLIB) $(XLIB)
+ SYS_LIBRARIES = -lm
+
+ CDEBUGFLAGS = -g
+ XAWLIB = -lXaw3d # set to Xaw3d for 3d look
+ LOCAL_LDFLAGS = -L../../lib
+ EXTRA_INCLUDES = -I../../include
+ OBMLIBS = -lobm -lXpm
+ MATHLIB = -lm
+ DEPOBM = ../libobm.a
+ SRCS = listres.c AllWidgets.c
+ OBJS = listres.o AllWidgets.o
+
+all:: listres
+
+listres: $(OBJS) ${DEPOBM}
+ $(RM) $@
+ $(CCLINK) -o $@ $(LDOPTIONS) $(OBJS) ${OBMLIBS} $(XAWLIB) $(XMULIBONLY) $(XTOOLLIB) $(XLIB) $(LDLIBS) $(MATHLIB) $(EXTRA_LOAD_FLAGS)
+
+clean::
+ $(RM) listres
+
+${DEPOBM}:
+
+# -----------------------------------------------------------------------
+# common rules for all Makefiles - do not edit
+
+.c.i:
+ $(RM) $@
+ $(CC) -E $(CFLAGS) $(_NOOP_) $*.c > $@
+
+emptyrule::
+
+clean::
+ $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"*
+
+Makefile::
+ -@if [ -f Makefile ]; then set -x; \
+ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
+ else exit 0; fi
+ $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
+
+tags::
+ $(TAGS) -w *.[ch]
+ $(TAGS) -xw *.[ch] > TAGS
+
+man_keywords::
+ catman -M $(DESTDIR)$(MANPATH) -w
+
+# ----------------------------------------------------------------------
+# empty rules for directories that do not have SUBDIRS - do not edit
+
+install::
+ @echo "install in $(CURRENT_DIR) done"
+
+install.man::
+ @echo "install.man in $(CURRENT_DIR) done"
+
+Makefiles::
+
+includes::
+
+depend::
+
+# -----------------------------------------------------------------------
+# dependencies generated by makedepend
+
diff --git a/vendor/x11iraf/obm/listres/README b/vendor/x11iraf/obm/listres/README
new file mode 100644
index 00000000..eb1f7fcd
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/README
@@ -0,0 +1,29 @@
+LISTRES -- This version of listres includes not only the standard Xt and Xaw
+widgets, but also the Xaw3d widgets and any custom widgets included in ObmW.
+
+
+Recipe for updating OBM to include new widget resources.
+
+1. For each widget &:
+
+ echo ""; echo &; listres -format "%s %s %s %s" &
+
+2. Edit output and delete header lines. Prepend the widget class name to
+the start of each resources line for that widget, e.g.
+
+ Panner Core height Height Dimension
+
+3. Reorder the columns
+
+ 1,$s!\(.*\) \(.*\) \(.*\) \(.*\) \(.*\)!\3 \5 \1!
+
+4. Sort
+
+ 1,$!sort | uniq
+
+5. Reformat into form needed by obmres.c
+
+ 1,$s!\(.*\) \(.*\) \(.*\)! { "\1", "\2", \3 },!
+
+6. Edit obmres.c to include new entries. Sort resource list and edit class
+codes as necessary. These must agree with the definitions in ObmP.h.
diff --git a/vendor/x11iraf/obm/listres/listres.c b/vendor/x11iraf/obm/listres/listres.c
new file mode 100644
index 00000000..1586c1c1
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/listres.c
@@ -0,0 +1,302 @@
+/*
+ * $XConsortium: listres.c,v 1.31 91/02/16 18:30:40 dave Exp $
+ *
+ * Copyright 1989 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Core.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xmu/WidgetNode.h>
+#include <X11/Xaw/AllWidgets.h>
+
+#define widget_list XawWidgetArray /* or motif or ol or ... */
+#define nwidgets XawWidgetCount
+
+/* Compatibility hacks. */
+#ifdef AUX
+void *memmove(a,b,n) void *a; const void *b; size_t n; { bcopy(b,a,n); }
+#else
+#if defined(sun) && (!defined(SYSV))
+void *memmove(a,b,n) void *a, *b; int n; { bcopy(b,a,n); }
+#endif
+#endif
+
+static XrmOptionDescRec Options[] = {
+ { "-top", "*topObject", XrmoptionSepArg, (caddr_t) NULL },
+ { "-format", "*resourceFormat", XrmoptionSepArg, (caddr_t) NULL },
+ { "-tree", "*showTree", XrmoptionNoArg, (caddr_t) "on" },
+ { "-nosuper", "*showSuper", XrmoptionNoArg, (caddr_t) "off" },
+ { "-variable", "*showVariable", XrmoptionNoArg, (caddr_t) "on" },
+};
+
+typedef struct {
+ Boolean show_tree;
+ Boolean show_all;
+ Boolean show_variable;
+ Boolean show_superclass;
+ char *top_object;
+ char *format;
+ } OptionsRec;
+
+OptionsRec options;
+
+#define Offset(field) XtOffsetOf(OptionsRec, field)
+
+static XtResource Resources[] = {
+ { "showTree", "ShowTree", XtRBoolean, sizeof(Boolean),
+ Offset(show_tree), XtRImmediate, (XtPointer) FALSE },
+ { "showSuper", "ShowSuper", XtRBoolean, sizeof(Boolean),
+ Offset(show_superclass), XtRImmediate, (caddr_t) TRUE },
+ { "showVariable", "ShowVariable", XtRBoolean, sizeof(Boolean),
+ Offset(show_variable), XtRImmediate, (caddr_t) FALSE },
+ { "topObject", "TopObject", XtRString, sizeof(char *),
+ Offset(top_object), XtRString, (caddr_t) "core" },
+ { "resourceFormat", "ResourceFormat", XtRString, sizeof(char *),
+ Offset(format), XtRString, (caddr_t) " %-16s %20s %-20s %s" },
+};
+
+#undef Offset
+
+char *ProgramName;
+
+usage ()
+{
+ fprintf(stderr, "usage: %s [-options...]\n", ProgramName);
+ fprintf(stderr, "\nwhere options include:\n");
+ fprintf(stderr,
+ " -all list all known widget and object classes\n");
+ fprintf(stderr,
+ " -tree list all widgets and objects in a tree\n");
+ fprintf(stderr,
+ " -nosuper do not print superclass resources\n");
+ fprintf(stderr,
+ " -variable show variable name instead of class name\n");
+ fprintf(stderr,
+ " -top name object to be top of tree\n");
+ fprintf(stderr,
+ " -format string printf format for instance, class, type\n");
+ fprintf(stderr, "\n");
+ exit (1);
+}
+
+static void print_tree_level (wn, level)
+ register XmuWidgetNode *wn;
+ register int level;
+{
+ register int i;
+
+ if (!wn) return;
+
+ for (i = 0; i < level; i++) {
+ putchar (' '); putchar (' ');
+ }
+ printf ("%d: %s/%s\n", level, wn->label, XmuWnClassname(wn));
+ print_tree_level (wn->children, level + 1);
+ print_tree_level (wn->siblings, level);
+}
+
+static void tree_known_widgets ()
+{
+ register int i;
+ register XmuWidgetNode *wn;
+
+ for (i = 0, wn = widget_list; i < nwidgets; i++, wn++) {
+ if (!wn->superclass) { /* list all rooted objects */
+ print_tree_level (wn, 0);
+ }
+ }
+}
+
+
+/*
+ * print_classname - print out the superclass-to-subclass hierchy of names
+ * in the form super\sub\sub....
+ */
+static int print_classname (node, topnode, level, showvar)
+ XmuWidgetNode *node, *topnode;
+ int level;
+ Bool showvar;
+{
+ int retval;
+
+ if (node && node != topnode) {
+ retval = print_classname (node->superclass, topnode, level + 1,
+ showvar);
+ } else {
+ retval = level - 1;
+ }
+ if (node)
+ printf ("%s%s", showvar ? node->label : XmuWnClassname(node),
+ level ? "\\" : "");
+
+ return retval;
+}
+
+static void list_known_widgets ()
+{
+ int i;
+ XmuWidgetNode *wn;
+ int width = 0;
+ char format[20];
+
+ for (i = 0, wn = widget_list; i < nwidgets; i++, wn++) {
+ int l = strlen (wn->label);
+ if (l > width) width = l;
+ }
+ sprintf (format, "%%-%ds ", width);
+ for (i = 0, wn = widget_list; i < nwidgets; i++, wn++) {
+ printf (format, wn->label);
+ print_classname (wn, (XmuWidgetNode *) NULL, 0, False);
+ putchar ('\n');
+ }
+}
+
+/* ARGSUSED */
+static void print_resources (node, format, topnode, showsuper, showvar)
+ XmuWidgetNode *node;
+ char *format;
+ XmuWidgetNode *topnode;
+ Bool showsuper;
+ Bool showvar;
+{
+ int i;
+ XtResourceList res = node->resources;
+ XmuWidgetNode **wn = node->resourcewn;
+
+ for (i = 0; i < node->nresources; i++, res++, wn++) {
+ if (!showsuper && *wn != node) continue;
+ printf (format, showvar ? (*wn)->label : XmuWnClassname(*wn),
+ res->resource_name, res->resource_class, res->resource_type);
+ putchar ('\n');
+ }
+ if (node->nconstraints > 0) {
+ printf (format, "----", "----", "----", "----");
+ putchar ('\n');
+ }
+ res = node->constraints;
+ wn = node->constraintwn;
+ for (i = 0; i < node->nconstraints; i++, res++, wn++) {
+ if (!showsuper && *wn != node) continue;
+ printf (format, showvar ? (*wn)->label : XmuWnClassname(*wn),
+ res->resource_name, res->resource_class, res->resource_type);
+ putchar ('\n');
+ }
+ return;
+}
+
+
+/*
+ * list_resources - display resources of a widget, identifying class from
+ * which they come
+ */
+static list_resources (node, format, topnode, toplevel, showsuper, showvar)
+ XmuWidgetNode *node;
+ char *format;
+ XmuWidgetNode *topnode;
+ Widget toplevel;
+ Bool showsuper;
+ Bool showvar;
+{
+ static Bool first = True;
+
+ XmuWnFetchResources (node, toplevel, topnode);
+ if (first) {
+ printf (format, showvar ? "Variable" : "WidgetClass",
+ "Instance", "Class", "Type");
+ putchar ('\n');
+ printf (format, showvar ? "--------" : "-----------",
+ "--------", "-----", "----");
+ putchar ('\n');
+ first = False;
+ }
+ printf ("%s: ", node->label);
+ print_classname (node, topnode, 0, showvar);
+ putchar ('\n');
+ print_resources (node, format, topnode, showsuper, showvar);
+ putchar ('\n');
+}
+
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+ XtAppContext appcon;
+ XmuWidgetNode *topnode;
+ Widget toplevel, container;
+
+ ProgramName = argv[0];
+
+ toplevel = XtAppInitialize (&appcon, "Listres", Options, XtNumber(Options),
+ &argc, argv, NULL, NULL, 0);
+ container = XtCreateWidget ("dummy", widgetClass, toplevel, NULL, ZERO);
+
+ XtGetApplicationResources (toplevel, (caddr_t) &options,
+ Resources, XtNumber(Resources), NULL, ZERO);
+ XmuWnInitializeNodes (widget_list, nwidgets);
+ if (argc == 1) {
+ if (options.show_tree) {
+ tree_known_widgets();
+ } else {
+ list_known_widgets();
+ }
+ exit (0);
+ }
+
+ topnode = XmuWnNameToNode (widget_list, nwidgets, options.top_object);
+ argc--, argv++; /* skip command */
+
+ if (argc > 0 && argv[0][0] == '-') {
+ int len = strlen (argv[0]);
+ if (len >= 2 && strncmp(argv[0], "-all", len) == 0) {
+ XmuWidgetNode *wn;
+ for (i = 0, wn = widget_list; i < nwidgets; i++, wn++) {
+ list_resources (wn, options.format, topnode, container,
+ (Bool) options.show_superclass,
+ (Bool) options.show_variable);
+ }
+ } else
+ usage();
+ } else {
+ for (; argc > 0; argc--, argv++) {
+ XmuWidgetNode *node;
+
+ if (argv[0][0] == '-') usage ();
+ node = XmuWnNameToNode (widget_list, nwidgets, *argv);
+ if (!node) {
+ fprintf (stderr, "%s: unable to find widget \"%s\"\n",
+ ProgramName, *argv);
+ continue;
+ }
+ list_resources (node, options.format, topnode, container,
+ (Bool) options.show_superclass,
+ (Bool) options.show_variable);
+ }
+ }
+ exit (0);
+}
diff --git a/vendor/x11iraf/obm/listres/listres.man b/vendor/x11iraf/obm/listres/listres.man
new file mode 100644
index 00000000..a57b51f8
--- /dev/null
+++ b/vendor/x11iraf/obm/listres/listres.man
@@ -0,0 +1,54 @@
+.TH LISTRES 1 "Release 5" "X Version 11"
+.SH NAME
+listres - list resources in widgets
+.SH SYNOPSIS
+.B "listres"
+[-option ...]
+.SH DESCRIPTION
+.PP
+The \fIlistres\fP program generates a list of a widget's resource database.
+The class in which each resource is first defined, the instance and class
+name, and the type of each resource is listed. If no specific widgets
+or the \fI-all\fP switch are given, a two-column list of widget names and
+their class hierarchies is printed.
+.SH OPTIONS
+\fIListres\fP accepts all of the standard toolkit command line options along
+with those listed below:
+.TP 8
+.B \-all
+This option indicates that \fIlistres\fP should print information for all
+known widgets and objects.
+.TP 8
+.B \-nosuper
+This option indicates that resources that are inherited from a superclass
+should not be listed. This is useful for determining which resources are
+new to a subclass.
+.TP 8
+.B \-variable
+This option indicates that widgets should be identified by the names of the
+class record variables rather than the class name given in the variable. This
+is useful for distinguishing subclasses that have the same class name as their
+superclasses.
+.TP 8
+.B \-top \fIname\fP
+This option specifies the name of the widget to be treated as the top of the
+hierarchy. Case is not significant, and the name may match either the class
+variable name or the class name. The default is ``core''.
+.TP 8
+.B \-format \fIprintf\-string\fP
+This option specifies the \fIprintf\fP-style format string to be used to print
+out the name, instance, class, and type of each resource.
+.SH "X DEFAULTS"
+To be written.
+.SH "SEE ALSO"
+X(1), xrdb(1), appropriate widget documents
+.SH "BUGS"
+On operating systems that do not support dynamic linking of run-time routines,
+this program must have all of its known widgets compiled in. The sources
+provide several tools for automating this process for various widget sets.
+.SH COPYRIGHT
+Copyright 1989, Massachusetts Institute of Technology.
+.br
+See \fIX(1)\fP for a full statement of rights and permissions.
+.SH AUTHOR
+Jim Fulton, MIT X Consortium
diff --git a/vendor/x11iraf/obm/marker.c b/vendor/x11iraf/obm/marker.c
new file mode 100644
index 00000000..82b5cee3
--- /dev/null
+++ b/vendor/x11iraf/obm/marker.c
@@ -0,0 +1,1869 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ctype.h>
+#include <ObmP.h>
+#include "widget.h"
+
+/*
+ * Graphics Marker class (a base class, requires a parent Gterm widget).
+ * --------------------------------------------------------------------------
+ * A marker is a graphics object implemented by the Gterm-Image widget.
+ * Markers are not real toolkit widgets, but they act much like widgets and
+ * are interfaced as an object class under the Object Manager. The Marker
+ * class is not a subclass, it is a base class like Widget, but Marker objects
+ * can exist only as children of Gterm widgets.
+ *
+ * Since markers are not independent widgets but rather part of a Gterm widget
+ * instance, the parent Gterm widget is partially responsible for managing
+ * markers. The Gterm widget implements the following commands for dealing
+ * with markers.
+ *
+ * createMarker name [attribute-list]
+ * markerInit
+ *
+ * A new marker is created by sending the createMarker message to the parent
+ * gterm widget. This creates a marker of the given name and type.
+ * The markerInit command, if sent to a gterm widget, destroys any markers
+ * defined for that widget and reinitializes the marker facility. Markers
+ * may also be created by action procedures in response to user input events.
+ *
+ * A marker may be destroyed by itself in response to an input event (e.g. the
+ * user presses the delete key), by sending the marker the destroy message
+ * to tell it to destroy itself, by sending a markerInit to the parent gterm
+ * widget, or by destroying the marker object (or any parent) with the server
+ * command destroyObject.
+ *
+ * Once a marker has been created it behaves as an independent object and
+ * receives and executes messages, responds to events, generates callbacks,
+ * and so on. The marker class defines the following commands.
+ *
+ * makeCopy name
+ * addCallback procedure [event [event ...]]
+ * deleteCallback procedure
+ * notify [event-type [param [param ...]]]
+ * destroy [nocallback]
+ *
+ * markpos
+ * redraw [function] [markpos|nomarkpos] [erase|noerase]
+ *
+ * raise [reference-marker]
+ * lower [reference-marker]
+ *
+ * move x y
+ * resize width height
+ * rotate angle # radians
+ *
+ * set attribute value # alias for setAttribute
+ * value = get attribute
+ *
+ * setAttribute attribute value
+ * value = getAttribute attribute
+ * setAttributes attribute-list
+ * getAttributes attribute-list
+ * setVertices points first npts
+ * getVertices points first npts
+ *
+ * region = getRegion [unmap] [coord-type]
+ * getRect type dx dy dnx dny
+ *
+ * Marker positions and dimensions are given in window (raster 0) pixel
+ * coordinates. NDC (raster normalized) coordinates are not supported for
+ * markers, except in the unmap option of getRegion which can return a marker
+ * description in the raster coordinate system of the raster the marker is in.
+ *
+ * The operators raise, lower, move, resize, and rotate erase the marker,
+ * modify it as indicated, and redraw it with the new attributes. For finer
+ * control over marker attributes one can use [get|set]Attribute[s] and
+ * [get|set]Vertices to edit the markers directly. In this case an auto
+ * redraw is not performed (unless the autoRedraw marker attribute is set).
+ * The usual sequence is a markpos to record the marker position, one or more
+ * setAttribute calls to change marker attributes, then a redraw to erase
+ * the old marker and redraw the new one. Markers have many attributes which
+ * can be set to control things like the position and size, colors, line
+ * widths, fill type and style, font, rubber-band technique, and so on.
+ * Refer to <ObmW/Gterm.h> for a list of marker types and attributes.
+ *
+ * The marker type may be changed at runtime without destroying the marker.
+ * For example a circle can be changed to an ellipse or a rectangle. This
+ * also works for polygons (the vertex list is preserved and restored when
+ * the marker is changed back to a polygon).
+ *
+ * The current shape of a marker may be queried with getVertices, which
+ * returns the polygon or polyline vertex list in window coordinates. A more
+ * powerful routine which does something similar is getRegion. This routine
+ * returns a high level description of the region outlined by the marker,
+ * giving the marker type (rectangle, circle, ellipse etc.), center, width
+ * and height, and so on. Any position or dimension information may
+ * optionally be transformed back to the original source raster, if the marker
+ * center is in a region of the window which is the destination of an active
+ * mapping. The unmap option will follow multiple mappings back to the
+ * original mapped source raster.
+ *
+ * The getRect function returns a rect (x y width height) describing either
+ * the rectangular region enclosed by a marker, or the rect defining the
+ * marker boundary. This works for any marker but is not likely to be useful
+ * for other than nonrotated rectangular markers. For example, the enclosed
+ * rect returned may be used in a setMapping call to map a raster into the
+ * interior of a marker.
+ */
+
+#define MAX_POLYPTS 4096
+
+typedef struct {
+ ObmContext obm; /* object manager */
+ ObmObject pobj; /* parent object */
+ Widget gt; /* gterm widget */
+ XtPointer gm; /* marker */
+ ObmCallback callback; /* callback list */
+} markerPrivate, *MarkerPrivate;
+
+typedef struct {
+ struct obmObjectCore core;
+ markerPrivate marker;
+} markerObject, *MarkerObject;
+
+static void MarkerDestroy();
+static void MarkerClassDestroy();
+static ObmObject MarkerCreate();
+static int MarkerEvaluate();
+static int markerDestroyCallback();
+static int markerFocusCallback();
+
+static int markerMakeCopy(), markerAddCallback();
+static int markerDeleteCallback(), markerCallbackProc();
+static int markerNotify(), markerDestroy(), markerMarkpos(), markerRedraw();
+static int markerRaise(), markerLower(), markerMove(), markerResize();
+static int markerRotate(), markerGetAttribute(), markerSetAttribute();
+static int markerGetAttributes(), markerSetAttributes();
+static int markerGetVertices(), markerSetVertices();
+static int markerGetRegion(), markerGetRect();
+
+extern XtPointer GmCreate(), GmCopy();
+extern double strtod();
+
+
+/* MarkerClassInit -- Initialize the class record for the marker widget class.
+ */
+void
+MarkerClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register MsgContext msg;
+ register Tcl_Interp *tcl;
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = MarkerClassDestroy;
+ classrec->Create = (ObmFunc) MarkerCreate;
+ classrec->Destroy = MarkerDestroy;
+ classrec->Evaluate = MarkerEvaluate;
+
+ /* The marker widget subclass has its own command set hence has its
+ * own interpreter. The widget will respond both to all the commands
+ * defined here, and to all the commands implemented by the base
+ * Widget class.
+ */
+ if (!classrec->class_data) {
+ msg = (MsgContext) XtMalloc (sizeof (struct msgContext));
+ msg->tcl = tcl = Tcl_CreateInterp();
+ classrec->class_data = (XtPointer) msg;
+ msg->level = 0;
+
+ Tcl_CreateCommand (tcl,
+ "makeCopy", markerMakeCopy, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "addCallback", markerAddCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteCallback", markerDeleteCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "callbackProc", markerCallbackProc, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "notify", markerNotify, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "destroy", markerDestroy, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "markpos", markerMarkpos, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "redraw", markerRedraw, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "raise", markerRaise, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "lower", markerLower, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "move", markerMove, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "resize", markerResize, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "rotate", markerRotate, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "set", markerSetAttribute, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "get", markerGetAttribute, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setAttribute", markerSetAttribute, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getAttribute", markerGetAttribute, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setAttributes", markerSetAttributes, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getAttributes", markerGetAttributes, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setVertices", markerSetVertices, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getVertices", markerGetVertices, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getRegion", markerGetRegion, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getRect", markerGetRect, (ClientData)msg, NULL);
+ }
+}
+
+
+/* MarkerClassDestroy -- Custom destroy procedure for the widget class.
+ */
+static void
+MarkerClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register MsgContext msg = (MsgContext) classrec->class_data;
+
+ if (msg) {
+ if (msg->tcl)
+ Tcl_DeleteInterp (msg->tcl);
+ XtFree ((char *)msg);
+ classrec->class_data = NULL;
+ }
+}
+
+
+/* MarkerCreate -- Create a new instance of a marker object.
+ */
+static ObmObject
+MarkerCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register MarkerObject obj;
+ register Widget gt;
+ ObmObject gterm_obj;
+ int type, interactive;
+ int erase, visible, i;
+ XtPointer marker, gm;
+
+ /* Get descriptor. */
+ if ((gterm_obj = obmFindObject (obm, parent)) == NULL)
+ return (NULL);
+ obj = (MarkerObject) XtCalloc (1, sizeof(markerObject));
+ if (obj == NULL)
+ return (NULL);
+
+ /* Examine the marker attribute list to determine if we are
+ * building an object around a marker that has already been created,
+ * or if we are creating a new marker, the marker type and create mode.
+ */
+ type = Gm_Rectangle;
+ interactive = 0;
+ visible = 0;
+ marker = NULL;
+
+ for (i=0; i < nargs; i++) {
+ Arg *ap = &args[i];
+ int ch;
+
+ if (strcmp (ap->name, "marker") == 0)
+ marker = (XtPointer)ap->value;
+ else if (strcmp (ap->name, "createMode") == 0)
+ interactive = (strcmp ((char *)ap->value, "interactive") == 0);
+ else if (strcmp (ap->name, "visible") == 0)
+ visible = ((ch = *(char *)ap->value) == 'T' || ch == 't');
+ else if (strcmp (ap->name, "type") == 0) {
+ if (!(type = GmStrToType ((char *)ap->value)))
+ type = Gm_Rectangle;
+ }
+ }
+
+ /* Create the marker. */
+ if (marker)
+ gm = marker;
+ else {
+ gt = widgetGetPointer (gterm_obj);
+ if ((gm = GmCreate (gt, type, interactive)) == NULL) {
+ XtFree ((char *)obj);
+ return (NULL);
+ }
+ }
+
+ /* Set any marker attributes. */
+ for (i=0; i < nargs; i++) {
+ Arg *ap = &args[i];
+ if (strcmp (ap->name, "marker") != 0 &&
+ strcmp (ap->name, "createMode") != 0 &&
+ strcmp (ap->name, "type") != 0)
+ GmSetAttribute (gm, ap->name, ap->value, XtRString);
+ }
+
+ /* Initialize descriptor. */
+ obj->marker.obm = obm;
+ obj->marker.pobj = gterm_obj;
+ obj->marker.gt = gt;
+ obj->marker.gm = gm;
+
+ /* Define focusin and focusout callbacks to keep track of the
+ * marker state.
+ */
+ GmAddCallback (gm, GmEvFocusIn|GmEvFocusOut,
+ markerFocusCallback, (XtPointer) obj);
+
+ /* Define a destroy callback to automatically free the Marker object
+ * when a marker is destroyed at the Gterm widget level.
+ */
+ GmAddCallback (gm, GmEvDestroy,
+ markerDestroyCallback, (XtPointer) obj);
+
+ if (!interactive && visible)
+ GmRedraw (gm, GXcopy, erase=True);
+
+ return ((ObmObject) obj);
+}
+
+
+/* MarkerDestroy -- Destroy an instance of a marker object.
+ */
+static void
+MarkerDestroy (object)
+ObmObject object;
+{
+ MarkerObject obj = (MarkerObject) object;
+ register ObmContext obm = obj->marker.obm;
+ register ObmCallback cb, next;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ /* When a marker is destroyed at the widget level or by sending a
+ * marker object the destroy message, GmDestroy is called.
+ * This in turn calls the Marker destroy callback which does an OBM
+ * Object destroy which calls the class procedure MarkerDestroy
+ * (this procedure) which calls GmDestroy again below. The second
+ * GmDestroy will find that a destroy operation is already in progress
+ * and return immediately. Hence, no matter how a Gterm marker is
+ * destroyed we end up destroying the associated OBM Marker as well.
+ */
+ if (obj->marker.gm)
+ GmDestroy (obj->marker.gm);
+
+ /* Free any callback descriptors. */
+ for (cb = obj->marker.callback; cb; cb = next) {
+ next = cb->next;
+ XtFree ((char *)cb);
+ }
+}
+
+
+/* MarkerEvaluate -- Evaluate a marker command or message.
+ */
+static int
+MarkerEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register MarkerObject obj = (MarkerObject) object;
+ register MsgContext msg = (MsgContext) obj->core.classrec->class_data;
+ register ObmContext obm = obj->marker.obm;
+ int status;
+
+ /* Since the class wide interpreter is used to evaluate the message
+ * we can't pass the object descriptor directly to the class procedure
+ * referenced in the message. Instead we pass the object reference
+ * in the message descriptor.
+ */
+ Tcl_SetResult (obm->tcl, "", TCL_VOLATILE);
+ msg->object[++msg->level] = object;
+
+ if (!obmClientCommand (msg->tcl, command)) {
+ Tcl_SetResult (obm->tcl, "invalid command", TCL_VOLATILE);
+ status = TCL_ERROR;
+ } else {
+ status = Tcl_Eval (msg->tcl, command);
+ if (status == TCL_ERROR) {
+ if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ else {
+ /* Supply a default error message if none was returned. */
+ Tcl_SetResult (obm->tcl, "evaluation error", TCL_VOLATILE);
+ }
+ obm->tcl->errorLine = msg->tcl->errorLine;
+
+ } else if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ }
+
+ msg->level--;
+ return (status);
+}
+
+
+/*
+ * MARKER class commands.
+ * -----------------------
+ */
+
+
+/* makeCopy -- Copy a marker. The new marker is initially identical to the
+ * old one, and will not be distinct until, e.g., moved to a new center.
+ *
+ * Usage: makeCopy name
+ */
+static int
+markerMakeCopy (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ XtPointer gm;
+ Arg args[10];
+ char *name;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ gm = GmCopy (mp->gm);
+
+ XtSetArg (args[0], "marker", gm);
+ obmNewObject (obm, name, "Marker", mp->pobj->core.name, args, 1);
+
+ return (TCL_OK);
+}
+
+
+/* addCallback -- Post a marker callback to be called when the specified
+ * event or events occurs. If no events are listed a Notify callback will
+ * be posted.
+ *
+ * Usage: addCallback procedure [event [event ...]]
+ */
+static int
+markerAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+ register ObmCallback cb, new_cb;
+ char *procedure;
+ int events=0, i;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ procedure = argv[1];
+ if (argc > 2) {
+ for (i=2; i < argc; i++)
+ events |= GmStrToEvent(argv[i]);
+ } else
+ events = GmEvNotify;
+
+ /* Create callback record. */
+ new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ new_cb->u.obj = (ObmObject) obj;
+ new_cb->callback_type = events;
+ strncpy (new_cb->name, procedure, SZ_NAME);
+
+ /* Add new callback to the tail of callback list minus one, with the
+ * markerDestroyCallback at the very tail of this list. This is
+ * necessary because we don't want to physically destroy the marker
+ * object until all marker object Destroy callbacks have been
+ * processed.
+ */
+ if (mp->callback) {
+ for (cb = mp->callback; cb->next; cb = cb->next)
+ ;
+ cb->next = new_cb;
+ } else
+ mp->callback = new_cb;
+
+ GmDeleteCallback (mp->gm, markerDestroyCallback, (XtPointer) obj);
+ GmAddCallback (mp->gm, events, markerCallbackProc, (XtPointer) new_cb);
+ GmAddCallback (mp->gm, GmEvDestroy, markerDestroyCallback,
+ (XtPointer) obj);
+
+ return (TCL_OK);
+}
+
+
+/* deleteCallback -- Delete a marker callback.
+ *
+ * Usage: deleteCallback procedure
+ */
+static int
+markerDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmCallback cb, prev;
+ char *procedure;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ procedure = argv[1];
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=mp->callback; cb; prev=cb, cb=cb->next)
+ if (strcmp (cb->name, procedure) == 0) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ mp->callback = cb->next;
+ GmDeleteCallback (mp->gm, markerCallbackProc, cb);
+ XtFree ((char *)cb);
+ break;
+ }
+
+ return (TCL_OK);
+}
+
+
+/* markerCallbackProc -- Low level callback procedure, called by the Gterm
+ * marker code when a marker event occurs.
+ */
+static int
+markerCallbackProc (cb, gm, events, event, params, nparams)
+register ObmCallback cb;
+XtPointer gm;
+int events;
+XEvent *event;
+String *params;
+Cardinal nparams;
+{
+ MarkerObject obj = (MarkerObject) cb->u.obj;
+ MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+ char message_data[SZ_MESSAGE];
+ register char *op;
+ int status = 0;
+
+ /* Call the user callback procedure. The callback procedure is called
+ * with the arguments "marker-name event-type event-data", where
+ * event-data is a Tcl list (delimited by braces) of data strings
+ * describing the event.
+ */
+
+ if (events & GmEvNotify) {
+ /* Callback: marker-name notify {}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "notify", " ",
+ "{}",
+ NULL);
+ }
+
+ if (events & GmEvMoveResize) {
+ /* Callback: marker-name moveResize {x y width height}
+ */
+ if (nparams >= 4) {
+ sprintf (message_data, "%s %s %s %s",
+ params[0], params[1], params[2], params[3]);
+ } else
+ strcpy (message_data, "0 0 0 0");
+
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "moveResize", " ",
+ "{", message_data, "}",
+ NULL);
+ }
+
+ if (events & GmEvModify) {
+ /* Callback: marker-name modify {attribute-name}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "modify", " ",
+ "{", nparams ? params[0] : "unknown", "}",
+ NULL);
+ }
+
+ if (events & GmEvRedraw) {
+ /* Callback: marker-name redraw {}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "redraw", " ",
+ "{}",
+ NULL);
+ }
+
+ if (events & GmEvDestroy) {
+ /* Callback: marker-name destroy {}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "destroy", " ",
+ "{}",
+ NULL);
+ }
+
+ if (events & GmEvInput) {
+ /* Callback: marker-name input {type data modifiers}
+ *
+ * where type is keyPress, keyRelease, buttonPress, or
+ * buttonRelease, data is the character typed or a digit 1-5
+ * identifying the button, and modifier is "shift", "control",
+ * and so on. Multiple modifiers may be given.
+ */
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyPressedEvent *ev = (XKeyPressedEvent *) event;
+ register char *ip, *op = message_data;
+ char buf[SZ_MESSAGE];
+ int n;
+
+ if (event->type == KeyPress)
+ strcpy (op, "keyPress ");
+ else
+ strcpy (op, "keyRelease ");
+ while (op)
+ op++;
+
+ if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) {
+ for (ip=buf; --n >= 0; )
+ if (*ip <= ' ') {
+ *op++ = '^';
+ *op++ = *ip++ + 'A' - 1;
+ } else if (isprint (*ip)) {
+ *op++ = *ip++;
+ } else
+ ip++;
+ } else {
+ /* This case occurs when only a modifier is typed. */
+ for (ip = "??"; *op++ = *ip++; )
+ ;
+ }
+ *op++ = ' ';
+ op = widgetEventState (op, ev->state);
+ while (op > message_data && isspace (*(op-1)))
+ --op;
+ *op = '\0';
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonPressedEvent *ev = (XButtonPressedEvent *) event;
+ register char *op = message_data;
+
+ if (event->type == ButtonPress)
+ strcpy (op, "buttonPress ");
+ else
+ strcpy (op, "buttonRelease ");
+ while (op)
+ op++;
+
+ sprintf (op, "%d ", ev->button);
+ while (*op)
+ op++;
+ op = widgetEventState (op, ev->state);
+ while (op > message_data && isspace (*(op-1)))
+ --op;
+ *op = '\0';
+ }
+ break;
+
+ default:
+ strcpy (message_data, "unknown none");
+ }
+
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "input", " ",
+ "{", message_data, "}",
+ NULL);
+ }
+
+ if (events & GmEvFocusIn) {
+ /* Callback: marker-name focusIn {}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "focusIn", " ",
+ "{}",
+ NULL);
+ }
+
+ if (events & GmEvFocusOut) {
+ /* Callback: marker-name focusOut {}
+ */
+ status |= Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "focusOut", " ",
+ "{}",
+ NULL);
+ }
+
+ /* The constraint callback is a special case because it can modify its
+ * arguments. The called procedure returns as the function value a
+ * list of marker attributes with new values for those attributes.
+ * These are used to modify in place the param strings passed in by
+ * the widget.
+ *
+ * Callback: marker-name constraint { {name oldval newval} ... }
+ *
+ * The data field of this callback is a list of marker attributes,
+ * giving the attribute name, old value, and new value for each
+ * attribute. The function value returned, if any, should be a list
+ * of marker attributes giving the attribute name and new value for
+ * each attribute, e.g. { {name newval} ... }. Only modified new
+ * values need be returned; if no values are returned, no constraints
+ * are applied.
+ */
+ if (events & GmEvConstraint) {
+ Tcl_Interp *tcl = obm->tcl;
+ char **items, **fields;
+ int nitems;
+ int n, i, j;
+
+ op = message_data;
+ *op++ = '{';
+ *op++ = ' ';
+
+ for (i=0; i < nparams; i += 3) {
+ sprintf (op, "{%s %s %s}",
+ params[i+0], params[i+1], params[i+2]);
+ while (*op)
+ op++;
+ *op++ = ' ';
+ }
+
+ *op++ = '}';
+ *op++ = '\0';
+
+ /* Call the client constraint procedure. */
+ status |= Tcl_VarEval (tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "constraint", " ",
+ message_data,
+ NULL);
+
+ /* Process the list of modified values returned by the client.
+ * This is a list of lists, one for each modified value.
+ */
+ if (*tcl->result && strcmp(tcl->result,"{}") != 0) {
+ if (Tcl_SplitList(tcl,tcl->result,&nitems,&items) != TCL_OK)
+ status = ERR;
+ else {
+ for (i=0; i < nitems; i++) {
+ if (Tcl_SplitList(tcl,items[i],&n,&fields) != TCL_OK) {
+ status = ERR;
+ continue;
+ }
+ if (n > 0)
+ for (j=0; j < nparams; j += 3)
+ if (strcmp (fields[0], params[j]) == 0) {
+ strcpy (params[j+2], fields[1]);
+ break;
+ }
+ free ((char *) fields);
+ }
+ }
+
+ free ((char *) items);
+ }
+ }
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+
+ return (status ? ERR : OK);
+}
+
+
+/* notify -- Generate a Marker pseudo-event, causing any posted client
+ * callback procedures to be called.
+ *
+ * Usage: notify [event-type [param [param ...]]]
+ */
+static int
+markerNotify (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *event_type;
+ int first_param;
+ XEvent event;
+
+ event_type = (argc > 1) ? argv[1] : "notify";
+ first_param = (argc > 1) ? 2 : 1;
+
+ GmNotify (mp->gm, GmStrToEvent(event_type), &event,
+ argv[first_param], max (0, argc - first_param));
+
+ return (TCL_OK);
+}
+
+
+/* destroy -- Destroy a marker. Just tell the marker to destroy itself.
+ * All cleanup outside the marker facility relies upon the use of callbacks.
+ * This includes our callback markerDestroyCallback below.
+ *
+ * Usage: destroy
+ */
+static int
+markerDestroy (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+
+ GmDestroy (mp->gm);
+ return (TCL_OK);
+}
+
+
+/* markerDestroyCallback -- Low level callback procedure, called by the
+ * Gterm widget code when a marker is about to be destroyed.
+ */
+static int
+markerDestroyCallback (obj, gm, events, event, params, nparams)
+MarkerObject obj;
+XtPointer gm;
+int events;
+XEvent *event;
+String *params;
+Cardinal nparams;
+{
+ MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+
+ obmDestroyObject (obm, (ObmObject) obj);
+ return (0);
+}
+
+
+/* markerFocusCallback -- Marker callback procedure, called when a marker
+ * gets or loses the focus.
+ */
+static int
+markerFocusCallback (obj, gm, events, event, params, nparams)
+MarkerObject obj;
+XtPointer gm;
+int events;
+XEvent *event;
+String *params;
+Cardinal nparams;
+{
+ MarkerPrivate mp = &obj->marker;
+ ObmObject gtobj = mp->pobj;
+ ObmContext obm = mp->obm;
+
+ if (events & GmEvFocusIn)
+ widget_setTTName (gtobj, obj->core.name);
+ else if (events & GmEvFocusOut)
+ widget_setTTName (gtobj, mp->pobj->core.name);
+
+ return (0);
+}
+
+
+/* markpos -- Mark the current position of a marker for a later redraw.
+ *
+ * Usage: markpos
+ *
+ * Markpos is used to mark the position of a marker before changing any
+ * marker attributes, so that a later "redraw marked" will erase the old
+ * marker rather than the new one. This is necessary, for example, if any
+ * marker attributes are changed which affect the size or position of the
+ * marker.
+ */
+static int
+markerMarkpos (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ int erase;
+
+ GmMarkpos (mp->gm);
+
+ return (TCL_OK);
+}
+
+
+/* redraw -- Redraw a marker.
+ *
+ * Usage: redraw [function] [erase|noerase] [markpos|nomarkpos]
+ *
+ * By default redraw will erase the old marker at the position indicated by
+ * a previous call to markpos, and redraw the marker with the current
+ * attributes using the drawing function copy (copy source to destination).
+ * Hence the usual usage is "markpos ... change marker attributes ... redraw".
+ * Optional arguments may be given to change the drawing function, enable or
+ * disable erase, or force redraw to do a markpos. These arguments may be
+ * given in any order.
+ *
+ * The drawing functions are as given in the XLIB documentation, minus the
+ * "GX" prefix. The most commonly used functions are "copy" and "xor".
+ * A normal marker redraw uses function=copy.
+ */
+static int
+markerRedraw (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ Boolean markpos = False;
+ Boolean erase = True;
+ int function = GXcopy;
+ int i, v;
+ char *ap;
+
+ /* Process any optional arguments. */
+ for (i=1; i < argc; i++) {
+ ap = argv[i];
+ if (strcmp (ap, "erase") == 0)
+ erase = True;
+ else if (strcmp (ap, "noerase") == 0)
+ erase = False;
+ else if (strcmp (ap, "markpos") == 0)
+ markpos = True;
+ else if (strcmp (ap, "nomarkpos") == 0)
+ markpos = False;
+ else if ((v = GmStrToFunction (ap)) > 0)
+ function = v;
+ }
+
+ if (markpos)
+ GmMarkpos (mp->gm);
+ GmRedraw (mp->gm, function, erase);
+
+ return (TCL_OK);
+}
+
+
+/* raise -- Raise a marker, i.e., cause it to be drawn on top of other
+ * markers when overlapping markers are drawn.
+ *
+ * Usage: raise [reference-marker]
+ *
+ * In a reference marker is named the marker will raise itself above this
+ * marker, otherwise the raised marker becomes the topmost marker.
+ */
+static int
+markerRaise (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ XtPointer ref_gm = NULL;
+ MarkerObject ref;
+
+ if (argc > 1) {
+ if (ref = (MarkerObject) obmFindObject (obm, argv[1]))
+ ref_gm = ref->marker.gm;
+ else
+ return (TCL_ERROR);
+ }
+
+ /* This implies an automatic erase and redraw. */
+ GmRaise (mp->gm, ref_gm);
+
+ return (TCL_OK);
+}
+
+
+/* lower -- Lower a marker, i.e., cause it to be drawn beneath other
+ * markers when overlapping markers are drawn.
+ *
+ * Usage: lower [reference-marker]
+ *
+ * In a reference marker is named the marker will lower itself beneath this
+ * marker, otherwise the lowered marker becomes the lowest marker.
+ */
+static int
+markerLower (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ XtPointer ref_gm = NULL;
+ MarkerObject ref;
+
+ if (argc > 1) {
+ if (ref = (MarkerObject) obmFindObject (obm, argv[1]))
+ ref_gm = ref->marker.gm;
+ else
+ return (TCL_ERROR);
+ }
+
+ /* This implies an automatic erase and redraw. */
+ GmLower (mp->gm, ref_gm);
+
+ return (TCL_OK);
+}
+
+
+/* move -- Move a marker.
+ *
+ * Usage: move x y
+ *
+ * Move the marker center to the indicated coordinates in the display window.
+ */
+static int
+markerMove (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ Arg args[10];
+ int erase;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[0], GmX, argv[1]);
+ XtSetArg (args[1], GmY, argv[2]);
+
+ GmMarkpos (mp->gm);
+ GmSetAttributes (mp->gm, args, 2, XtRString);
+ GmRedraw (mp->gm, GXcopy, erase=True);
+
+ return (TCL_OK);
+}
+
+
+/* resize -- Resize a marker.
+ *
+ * Usage: resize width height
+ *
+ * Resize the marker to the indicated size. By default width and height are
+ * given in pixels. For a text marker one can append "ch" to indicate that
+ * the units are chars in whatever font is in use, e.g., "40ch" or "40 chars"
+ * is an acceptable value for a text marker dimension.
+ */
+static int
+markerResize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ Arg args[10];
+ int erase;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[0], GmWidth, argv[1]);
+ XtSetArg (args[1], GmHeight, argv[2]);
+
+ GmMarkpos (mp->gm);
+ GmSetAttributes (mp->gm, args, 2, XtRString);
+ GmRedraw (mp->gm, GXcopy, erase=True);
+
+ return (TCL_OK);
+}
+
+
+/* rotate -- Rotate a marker.
+ *
+ * Usage: rotate angle
+ *
+ * Redraw a marker oriented to the given rotation angle. The angle is
+ * given in radians.
+ */
+static int
+markerRotate (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ Arg args[10];
+ int erase;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[0], GmRotangle, argv[1]);
+
+ GmMarkpos (mp->gm);
+ GmSetAttributes (mp->gm, args, 1, XtRString);
+ GmRedraw (mp->gm, GXcopy, erase=True);
+
+ return (TCL_OK);
+}
+
+
+/* getAttribute -- Return the value of a marker attribute.
+ *
+ * Usage: value = getAttribute attribute-name
+ */
+static int
+markerGetAttribute (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *name, value[SZ_COMMAND];
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+
+ if (GmGetAttribute (mp->gm, name, (XtArgVal)value, XtRString) < 0)
+ return (TCL_ERROR);
+ else {
+ Tcl_SetResult (obm->tcl, value, TCL_VOLATILE);
+ return (TCL_OK);
+ }
+}
+
+
+/* setAttribute -- Set the value of a marker attribute.
+ *
+ * Usage: setAttribute attribute-name value
+ */
+static int
+markerSetAttribute (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *name, *value;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ value = argv[2];
+
+ if (GmSetAttribute (mp->gm, name, (XtArgVal)value, XtRString) < 0)
+ return (TCL_ERROR);
+ else
+ return (TCL_OK);
+}
+
+
+/* getAttributes -- Return the values of a list of marker attributes.
+ *
+ * Usage: getAttributes attribute-list
+ * i.e. getAttributes {name value [name value ...]}
+ * or getAttributes name value [name value ...]
+ *
+ * where "value" is the name of the variable in which the attribute value
+ * is to be stored.
+ */
+static int
+markerGetAttributes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *name, *variable, value[SZ_COMMAND];
+ int i, status = 0;
+ char **items;
+ int nitems;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if (argc == 2) {
+ /* Attribute list passed as a list argument. */
+ if (Tcl_SplitList (tcl, argv[1], &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+ } else if (argc > 2) {
+ /* Attribute list passed as separate arguments. */
+ nitems = argc - 1;
+ items = (char **) XtMalloc (nitems * sizeof(char *));
+ if (items == NULL)
+ return (TCL_ERROR);
+ for (i=0; i < nitems; i++)
+ items[i] = argv[i+1];
+ } else
+ return (TCL_ERROR);
+
+ for (i=0; i < nitems; i += 2) {
+ name = items[i];
+ variable = items[i+1];
+
+ if (GmGetAttribute (mp->gm, name, (XtArgVal)value, XtRString) < 0)
+ status++;
+ if ((Tcl_SetVar (obm->tcl, variable, value, 0)) == NULL)
+ status++;
+ }
+
+ free ((char *) items);
+ return (status ? TCL_ERROR : TCL_OK);
+}
+
+
+/* setAttributes -- Set the values of a list of marker attributes.
+ *
+ * Usage: setAttributes attribute-list
+ * i.e. setAttributes {name value [name value ...]}
+ *
+ * where "value" is the new value of the associated marker attribute.
+ */
+static int
+markerSetAttributes (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *name, *value;
+ Arg args[MAX_ARGS];
+ int status, argno, i;
+ char **items;
+ int nitems;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if (argc == 2) {
+ /* Attribute list passed as a list argument. */
+ if (Tcl_SplitList (tcl, argv[1], &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+ } else if (argc > 2) {
+ /* Attribute list passed as separate arguments. */
+ nitems = argc - 1;
+ items = (char **) XtMalloc (nitems * sizeof(char *));
+ if (items == NULL)
+ return (TCL_ERROR);
+ for (i=0; i < nitems; i++)
+ items[i] = argv[i+1];
+ } else
+ return (TCL_ERROR);
+
+ for (i=0, argno=0; i < nitems && argno < MAX_ARGS; i += 2, argno++) {
+ name = items[i];
+ value = items[i+1];
+ XtSetArg (args[argno], name, value);
+ }
+
+ if (GmSetAttributes (mp->gm, args, argno, XtRString) < 0)
+ status = TCL_ERROR;
+ else
+ status = TCL_OK;
+
+ free ((char *) items);
+ return (status);
+}
+
+
+/* getVertices -- Get some or all of the vertices making up the polygon or
+ * polyline representation of a marker.
+ *
+ * Usage: getVertices points [first npts]
+ *
+ * The polygon or polyline representation of a marker is returned in the
+ * variable "points", as a string of the form { {x y} {x y} ...}. The first
+ * point is number zero. Coordinates are specified in raster zero pixel
+ * coordinates.
+ */
+static int
+markerGetVertices (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+
+ register int i;
+ register char *op;
+ register DPoint *pv;
+ int first, maxpts, npts, ngot;
+ int nchars, status, buflen;
+ char *points, *buf;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ points = argv[1];
+ first = (argc > 2) ? atoi(argv[2]) : 0;
+ npts = (argc > 3) ? atoi(argv[3]) : 0;
+ maxpts = max (npts, MAX_POLYPTS);
+again:
+ if ((pv = (DPoint *) XtMalloc (maxpts * sizeof(DPoint))) == NULL)
+ return (TCL_ERROR);
+
+ ngot = GmGetVertices (mp->gm, pv, first, npts ? npts : maxpts);
+ if (ngot >= maxpts) {
+ /* This is pretty unlikely. */
+ XtFree ((char *)pv);
+ maxpts *= 2;
+ goto again;
+ }
+
+ buflen = SZ_COMMAND;
+ buf = XtMalloc (buflen);
+ if (buf == NULL) {
+ XtFree ((char *)pv);
+ return (TCL_ERROR);
+ }
+
+ op = buf;
+ *op++ = '{';
+ *op++ = ' ';
+
+ for (i=0; i < ngot; i++) { /* MF001 */
+ sprintf (op, "{%d %d} ", (int)pv[i].x, (int)pv[i].y);
+ while (*op) /* MF002 */
+ op++;
+
+ if (op - buf + SZ_NUMBER > buflen) {
+ buflen += SZ_COMMAND;
+ nchars = op - buf;
+ if ((buf = XtRealloc (buf, buflen)) == NULL) {
+ XtFree ((char *)pv);
+ return (TCL_ERROR);
+ }
+ op = buf + nchars;
+ }
+ }
+
+ *op++ = '}';
+ *op++ = '\0';
+
+ if ((Tcl_SetVar (obm->tcl, points, buf, 0)) == NULL)
+ status = TCL_ERROR;
+ else
+ status = TCL_OK;
+
+ XtFree ((char *)pv);
+ XtFree (buf);
+
+ return (status);
+}
+
+
+/* setVertices -- Set some or all of the vertices making up the polygon or
+ * polyline representation of a marker.
+ *
+ * Usage: setVertices points [first npts]
+ *
+ * The polygon or polyline representation of a marker is set using the points
+ * passed in the "points" variable as a string of the form { {x y} {x y} ...}.
+ * If FIRST and NPTS are not specified first is assumed to be zero (the first
+ * point) and NPTS is the length of the points array. Coordinates are
+ * specified in raster zero pixel coordinates. In the case of 'poly' type
+ * markers the procedure will close the polygon by adding a copy of the first
+ * point to the list.
+ */
+static int
+markerSetVertices (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+
+ register int i;
+ register char *ip;
+ register DPoint *pv;
+ int first, maxpts, npts, ngot;
+ char *ipp, *points, *ip_save;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ points = argv[1];
+ first = (argc > 2) ? atoi(argv[2]) : 0;
+ npts = (argc > 3) ? atoi(argv[3]) : 0;
+ maxpts = max (npts, MAX_POLYPTS);
+
+ if ((pv = (DPoint *) XtMalloc (maxpts * sizeof(DPoint))) == NULL)
+ return (TCL_ERROR);
+
+ /* Get the points array. */
+ for (ngot=0, ip=points; *ip; ) {
+ while (isspace(*ip) || *ip == '{')
+ ip++;
+
+ ip_save = ip;
+ pv[ngot].x = strtod (ip, &ipp); ip = ipp;
+ pv[ngot].y = strtod (ip, &ipp); ip = ipp;
+ if (ip == ip_save) {
+ XtFree ((char *) pv);
+ return (TCL_ERROR);
+ }
+
+ while (isspace(*ip) || *ip == '}')
+ ip++;
+
+ if (++ngot >= maxpts) {
+ maxpts *= 2;
+ if ((pv = (DPoint *) XtRealloc ((char *)pv,
+ maxpts * sizeof(DPoint))) == NULL)
+ return (TCL_ERROR);
+ }
+ }
+
+ GmSetVertices (mp->gm, pv, first, npts ? npts : ngot);
+
+ XtFree ((char *)pv);
+ return (TCL_OK);
+}
+
+
+/* getRegion -- Return as a text string a high level description of the
+ * region defined by a marker.
+ *
+ * Usage: region = getRegion [unmap] [coord-type]
+ *
+ * The output string defines the marker type and the major marker positional
+ * attributes. The region description formats for the various marker types
+ * follow.
+ *
+ * text raster x y width height
+ * line raster x y x y
+ * polyline raster npts { {x y} {x y} ...}
+ * rectangle raster x y width height rotangle
+ * circle raster x y radius
+ * ellipse raster x y width height rotangle
+ * polygon raster npts { {x y} {x y} ...}
+ *
+ * Here, width and height refer to the distance from the marker center to an
+ * edge, not to the width or height of the whole marker. This avoids
+ * ambiguities about where the edge of a marker is if the width is even or
+ * odd. Using the center to edge measurement, the edge is at x +/- width,
+ * y +/- height.
+ *
+ * If the "unmap" flag is given getRegion will attempt to associate the
+ * marker with a mapped raster, reversing any mappings from the screen back
+ * to the original source raster, and returning the raster number and raster
+ * coordinates and marker sizes. If "unmap" is not given the marker
+ * coordinates will refer to raster 0. Either raster pixel ("pixel" or
+ * "Pixel") or raster NDC ("ndc" or "NDC") coordinates may be returned, pixel
+ * coordinates being the default.
+ */
+static int
+markerGetRegion (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ MarkerPrivate mp = &obj->marker;
+ ObmContext obm = mp->obm;
+ register DPoint *pv, *vv;
+ register char *op;
+ register int i;
+
+ Boolean unmap = False;
+ int ctype_out = GtPixel;
+ int x, y, width, height;
+ int maxpts, npts, src, dst, mapping;
+ int ctype, pvlen, buflen, nchars;
+ double rx, ry, rwidth, rheight;
+ Boolean output_points;
+ char *buf, *ap;
+ int marker_type;
+ double rotangle;
+ int status, v;
+ Arg args[10];
+
+ /* Process any optional arguments. */
+ for (i=1; i < argc; i++) {
+ ap = argv[i];
+ if (strcmp (ap, "unmap") == 0)
+ unmap = True;
+ else if ((v = coordType (ap)) > 0)
+ ctype_out = v;
+ }
+
+ /* First get the basic attributes like x, y, width, height, which
+ * we need for most markers.
+ */
+ XtSetArg (args[0], GmType, &marker_type);
+ XtSetArg (args[1], GmX, &x);
+ XtSetArg (args[2], GmY, &y);
+ XtSetArg (args[3], GmWidth, &width);
+ XtSetArg (args[4], GmHeight, &height);
+ if (GmGetAttributes (mp->gm, args, 5, XtRInt) < 0)
+ return (TCL_ERROR);
+
+ if (GmGetAttribute (mp->gm, GmRotangle, &rotangle, XtRFloat) < 0)
+ return (TCL_ERROR);
+
+ /* Get the points array, needed for some markers. */
+ maxpts = MAX_POLYPTS;
+again:
+ if ((pv = (DPoint *) XtMalloc (maxpts * sizeof(DPoint))) == NULL)
+ return (TCL_ERROR);
+
+ /* To ease the coordinate conversions we store the marker center and
+ * width information as the first two elements in the points array.
+ * These are not part of the marker polygon or polyline. Putting them
+ * in the points vector allows us to transform everything in one
+ * operation.
+ */
+ pv[0].x = x;
+ pv[0].y = y;
+ pv[1].x = x + width;
+ pv[1].y = y + height;
+ vv = pv + 2;
+
+ /* Now read the points array into pv[2]. */
+ npts = GmGetVertices (mp->gm, vv, 0, maxpts - 2);
+ if (npts == maxpts-2) {
+ /* This is pretty unlikely. */
+ XtFree ((char *)pv);
+ maxpts *= 2;
+ goto again;
+ }
+
+ /* If the unmap option is specified select the mapping, if any, which
+ * contains the marker center. Transform the coordinate vector
+ * backwards to the source raster. This process is repeated until we
+ * get back to a raster pixel which is not the destination of any
+ * mapping.
+ */
+ src = 0;
+ pvlen = npts + 2;
+
+ if (unmap) {
+ do {
+ src = GtSelectRaster (mp->gt, dst=src,
+ GtPixel, (int)(pv[0].x + 0.5), (int)(pv[0].y + 0.5),
+ GtPixel, &x, &y, &mapping);
+ if (src != dst)
+ GtMapVector (mp->gt, mapping, GtUnmap, pv, pv, pvlen);
+ } while (dst != src);
+ }
+
+ /* Convert the point data to NDC coordinates if indicated. NDC
+ * coordinates are scaled to the integer range 0:MAXNDC at the widget
+ * level, which we scale to the range 0-1 floating at the GUI level.
+ */
+ if (ctype_out == GtNDC) {
+ GtPixelToNDC (mp->gt, src, pv, pv, pvlen);
+ for (i=0; i < pvlen; i++) {
+ pv[i].x /= (double)MAXNDC;
+ pv[i].y /= (double)MAXNDC;
+ }
+ }
+
+ rx = pv[0].x;
+ ry = pv[0].y;
+ rwidth = abs (pv[1].x - rx);
+ rheight = abs (pv[1].y - ry);
+
+ buflen = SZ_COMMAND;
+ output_points = False;
+ op = buf = XtMalloc (buflen);
+ if (buf == NULL) {
+ XtFree ((char *)pv);
+ return (TCL_ERROR);
+ }
+
+ /* Generate the marker description. */
+ switch (marker_type) {
+ case Gm_Text:
+ /* text raster x y width height */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f %0.5f",
+ GmText, src, rx, ry, rwidth, rheight);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f %0.2f",
+ GmText, src, rx, ry, rwidth, rheight);
+ }
+ break;
+
+ case Gm_Line:
+ /* line raster x y x y */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f %0.5f", GmLine, src,
+ vv[0].x, vv[0].y, vv[1].x, vv[1].y);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f %0.2f", GmLine, src,
+ vv[0].x, vv[0].y, vv[1].x, vv[1].y);
+ }
+ break;
+
+ case Gm_Polyline:
+ /* polyline raster npts { {x y} {x y} ...} */
+ sprintf (op, "%s %d %d ", GmPolyline, src, npts);
+ output_points = True;
+ break;
+
+ case Gm_Rectangle:
+ /* rectangle raster x y width height rotangle */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f %0.5f %0.5f",
+ GmRectangle, src, rx, ry, rwidth, rheight, rotangle);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f %0.2f %0.4f",
+ GmRectangle, src, rx, ry, rwidth, rheight, rotangle);
+ }
+ break;
+
+ case Gm_Box:
+ /* box raster x y width height rotangle */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f %0.5f %0.5f",
+ GmBox, src, rx, ry, rwidth, rheight, rotangle);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f %0.2f %0.4f",
+ GmBox, src, rx, ry, rwidth, rheight, rotangle);
+ }
+ break;
+
+ case Gm_Circle:
+ /* circle raster x y radius */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f", GmCircle, src,
+ rx, ry, rwidth);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f", GmCircle, src,
+ rx, ry, rwidth);
+ }
+ break;
+
+ case Gm_Ellipse:
+ /* ellipse raster x y width height rotangle */
+ if (ctype_out == GtNDC) {
+ sprintf (op, "%s %d %0.5f %0.5f %0.5f %0.5f %0.5f",
+ GmEllipse, src, rx, ry, rwidth, rheight, rotangle);
+ } else {
+ sprintf (op, "%s %d %0.2f %0.2f %0.2f %0.2f %0.4f",
+ GmEllipse, src, rx, ry, rwidth, rheight, rotangle);
+ }
+ break;
+
+ case Gm_Polygon:
+ /* polygon raster npts { {x y} {x y} ...} */
+ sprintf (op, "%s %d %d ", GmPolygon, src, npts);
+ output_points = True;
+ break;
+
+ default:
+ XtFree (buf);
+ XtFree ((char *)pv);
+ return (TCL_ERROR);
+ }
+
+ /* If the marker description includes a point vector output this
+ * too.
+ */
+ if (output_points) {
+ while (*op)
+ op++;
+
+ *op++ = '{';
+ *op++ = ' ';
+
+ for (i=0; i < npts; i++) {
+ if (ctype_out == GtNDC)
+ sprintf (op, "{%0.5f %0.5f} ", vv[i].x, vv[i].y);
+ else
+ sprintf (op, "{%0.2f %0.2f} ", vv[i].x, vv[i].y);
+ while (*op) /* MF003 */
+ op++;
+
+ if (op - buf + SZ_NUMBER > buflen) {
+ buflen += SZ_COMMAND;
+ nchars = op - buf;
+ if ((buf = XtRealloc (buf, buflen)) == NULL) {
+ XtFree ((char *)pv);
+ return (TCL_ERROR);
+ }
+ op = buf + nchars;
+ }
+ }
+
+ *op++ = '}';
+ *op++ = '\0';
+ }
+
+ Tcl_SetResult (obm->tcl, buf, TCL_VOLATILE);
+ XtFree ((char *)pv);
+ XtFree (buf);
+
+ return (TCL_OK);
+}
+
+
+/* getRect -- Return the region defined by a rectangle marker. The rect is
+ * returned in a form convenient for use as the destination rect in a gterm
+ * widget raster mapping.
+ *
+ * Usage: getRect type dx dy dnx dny
+ *
+ * The rect is stored in the output arguments. The rect coordinates are
+ * integer pixel coordinates (raster 0 pixel coordinates), as with all marker
+ * level coords. If the rect type is "interior" the rect defining the region
+ * enclosed by the marker is returned. If the rect type is "boundary' the
+ * rect returned refers to the location of the marker itself. If the rect
+ * type is "boundingBox" the rect returned is one which is large enough to
+ * completely enclose the marker. getRect may be used with any marker, but
+ * the interior and boundary options are probably not useful except for
+ * nonrotated rectangular markers.
+ */
+static int
+markerGetRect (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ MarkerObject obj = (MarkerObject) msg->object[msg->level];
+ register MarkerPrivate mp = &obj->marker;
+ register ObmContext obm = mp->obm;
+ char *dx_out, *dy_out, *dnx_out, *dny_out;
+ int marker_type, x, y, width, height, status;
+ int dx, dy, dnx, dny;
+ int x1, x2, y1, y2;
+ char *type, buf[32];
+ Arg args[10];
+
+ if (argc < 6)
+ return (TCL_ERROR);
+
+ type = argv[1];
+ dx_out = argv[2];
+ dy_out = argv[3];
+ dnx_out = argv[4];
+ dny_out = argv[5];
+
+ XtSetArg (args[0], GmType, &marker_type);
+ XtSetArg (args[1], GmX, &x);
+ XtSetArg (args[2], GmY, &y);
+ XtSetArg (args[3], GmWidth, &width);
+ XtSetArg (args[4], GmHeight, &height);
+ if (GmGetAttributes (mp->gm, args, 5, XtRInt) < 0)
+ return (TCL_ERROR);
+
+ /* Get the coordinates of the marker boundary. */
+ if (marker_type == Gm_Text) {
+ x1 = x; x2 = x + width - 1;
+ y1 = y; y2 = y + height - 1;
+ } else {
+ x1 = x - width; x2 = x + width;
+ y1 = y - height; y2 = y + height;
+ }
+
+ if (strcmp (type, "boundary") == 0) {
+ /* Return the rect defining the marker itself. */
+ dx = x1; dnx = max(0, x2 - x1 + 1);
+ dy = y1; dny = max(0, y2 - y1 + 1);
+
+ } else if (strcmp (type, "boundingBox") == 0) {
+ /* Return a rect large enough to enclose the entire marker.
+ */
+ GmGetBoundingBox (mp->gm, &dx, &dy, &dnx, &dny);
+
+ } else {
+ /* Compute the enclosed region, leaving a little space between
+ * the rect and the marker boundary. This is the default.
+ */
+ dx = x1 + 2; dnx = max(0, (x2 - 2) - (x1 + 2) + 1);
+ dy = y1 + 2; dny = max(0, (y2 - 2) - (y1 + 2) + 1);
+ }
+
+ status = 0;
+ sprintf (buf, "%d", dx);
+ if ((Tcl_SetVar (obm->tcl, dx_out, buf, 0)) == NULL)
+ status++;
+ sprintf (buf, "%d", dy);
+ if ((Tcl_SetVar (obm->tcl, dy_out, buf, 0)) == NULL)
+ status++;
+ sprintf (buf, "%d", dnx);
+ if ((Tcl_SetVar (obm->tcl, dnx_out, buf, 0)) == NULL)
+ status++;
+ sprintf (buf, "%d", dny);
+ if ((Tcl_SetVar (obm->tcl, dny_out, buf, 0)) == NULL)
+ status++;
+
+ return (TCL_OK);
+}
diff --git a/vendor/x11iraf/obm/obmres.c b/vendor/x11iraf/obm/obmres.c
new file mode 100644
index 00000000..e6acd827
--- /dev/null
+++ b/vendor/x11iraf/obm/obmres.c
@@ -0,0 +1,2301 @@
+#include <stdio.h>
+
+/*
+ * OBMRES.C -- A little program to generate the resource list for the object
+ * manager (Xt/Athena widgets).
+ *
+ * This file is not part of the runtime Object Manager code.
+ */
+
+/* Widget class codes. These must match the values given in ObmP.h.
+ */
+#define Core 00000000000, 00000000001
+#define Object 00000000000, 00000000002
+#define Simple 00000000000, 00000000004
+#define Shell 00000000000, 00000000010
+
+#define AsciiSink 00000000000, 00000000020
+#define AsciiSrc 00000000000, 00000000040
+#define AsciiText 00000000000, 00000000100
+#define Box 00000000000, 00000000200
+#define Command 00000000000, 00000000400
+#define Dialog 00000000000, 00000001000
+#define Form 00000000000, 00000002000
+#define Grip 00000000000, 00000004000
+#define Label 00000000000, 00000010000
+#define List 00000000000, 00000020000
+#define MenuButton 00000000000, 00000040000
+#define Paned 00000000000, 00000100000
+#define Panner 00000000000, 00000200000
+#define Porthole 00000000000, 00000400000
+#define Repeater 00000000000, 00001000000
+#define Scrollbar 00000000000, 00002000000
+#define SimpleMenu 00000000000, 00004000000
+#define Sme 00000000000, 00010000000
+#define SmeBSB 00000000000, 00020000000
+#define SmeLine 00000000000, 00040000000
+#define StripChart 00000000000, 00100000000
+#define Toggle 00000000000, 00200000000
+#define Tree 00000000000, 00400000000
+#define Viewport 00000000000, 01000000000
+
+#define Gterm 00000000001, 00000000000
+#define Layout 00000000002, 00000000000
+#define HTML 00000000004, 00000000000
+#define Arrow 00000000010, 00000000000
+#define Board 00000000020, 00000000000
+#define Scrollbar2 00000000040, 00000000000
+#define Slider2d 00000000100, 00000000000
+#define Frame 00000000200, 00000000000
+#define Group 00000000400, 00000000000
+#define Icon 00000001000, 00000000000
+#define MultiList 00000002000, 00000000000
+#define RadioGroup 00000004000, 00000000000
+#define RowCol 00000010000, 00000000000
+#define TextBox 00000020000, 00000000000
+#define TextButton 00000040000, 00000000000
+#define TextToggle 00000100000, 00000000000
+#define XfwfCommon 00000200000, 00000000000
+#define XfwfMenuBar 00000400000, 00000000000
+#define Tabs 00001000000, 00000000000
+#define ListTree 00002000000, 00000000000
+#define Separator 00004000000, 00000000000
+#define Table 00010000000, 00000000000
+
+#define ApplicationShell Shell
+#define OverrideShell Shell
+#define TopLevelShell Shell
+#define TransientShell Shell
+#define WMShell Shell
+
+
+/* The following should list in sort order all the resources to be indexed,
+ * giving for each the resource type and the widget class in which it is used.
+ *
+ * NOTES. The asciiText widget recognizes the asciiSrc and asciiSink resources
+ * hence these should be listed as asciiText resources too. Listres lists
+ * resources for some widgets which have no public XtN definition; these should
+ * be omitted.
+ */
+struct resource_list {
+ char *resource; /* resource name */
+ char *type; /* resource type */
+ unsigned long class1, class2; /* widget using resource */
+} resources[] = {
+ { "abs_height", "Position", Arrow },
+ { "abs_height", "Position", Board },
+ { "abs_height", "Position", Group },
+ { "abs_height", "Position", Icon },
+ { "abs_height", "Position", RadioGroup },
+ { "abs_height", "Position", RowCol },
+ { "abs_height", "Position", Scrollbar2 },
+ { "abs_height", "Position", Slider2d },
+ { "abs_height", "Position", TextBox },
+ { "abs_height", "Position", TextButton },
+ { "abs_height", "Position", TextToggle },
+ { "abs_height", "Position", XfwfMenuBar },
+ { "abs_width", "Position", Arrow },
+ { "abs_width", "Position", Board },
+ { "abs_width", "Position", Group },
+ { "abs_width", "Position", Icon },
+ { "abs_width", "Position", RadioGroup },
+ { "abs_width", "Position", RowCol },
+ { "abs_width", "Position", Scrollbar2 },
+ { "abs_width", "Position", Slider2d },
+ { "abs_width", "Position", TextBox },
+ { "abs_width", "Position", TextButton },
+ { "abs_width", "Position", TextToggle },
+ { "abs_width", "Position", XfwfMenuBar },
+ { "abs_x", "Position", Arrow },
+ { "abs_x", "Position", Board },
+ { "abs_x", "Position", Group },
+ { "abs_x", "Position", Icon },
+ { "abs_x", "Position", RadioGroup },
+ { "abs_x", "Position", RowCol },
+ { "abs_x", "Position", Scrollbar2 },
+ { "abs_x", "Position", Slider2d },
+ { "abs_x", "Position", TextBox },
+ { "abs_x", "Position", TextButton },
+ { "abs_x", "Position", TextToggle },
+ { "abs_x", "Position", XfwfMenuBar },
+ { "abs_y", "Position", Arrow },
+ { "abs_y", "Position", Board },
+ { "abs_y", "Position", Group },
+ { "abs_y", "Position", Icon },
+ { "abs_y", "Position", RadioGroup },
+ { "abs_y", "Position", RowCol },
+ { "abs_y", "Position", Scrollbar2 },
+ { "abs_y", "Position", Slider2d },
+ { "abs_y", "Position", TextBox },
+ { "abs_y", "Position", TextButton },
+ { "abs_y", "Position", TextToggle },
+ { "abs_y", "Position", XfwfMenuBar },
+ { "accelerators", "AcceleratorTable", ApplicationShell },
+ { "accelerators", "AcceleratorTable", Arrow },
+ { "accelerators", "AcceleratorTable", AsciiText },
+ { "accelerators", "AcceleratorTable", Board },
+ { "accelerators", "AcceleratorTable", Box },
+ { "accelerators", "AcceleratorTable", Command },
+ { "accelerators", "AcceleratorTable", Core },
+ { "accelerators", "AcceleratorTable", Dialog },
+ { "accelerators", "AcceleratorTable", Form },
+ { "accelerators", "AcceleratorTable", Frame },
+ { "accelerators", "AcceleratorTable", Grip },
+ { "accelerators", "AcceleratorTable", Group },
+ { "accelerators", "AcceleratorTable", Gterm },
+ { "accelerators", "AcceleratorTable", HTML },
+ { "accelerators", "AcceleratorTable", Icon },
+ { "accelerators", "AcceleratorTable", Label },
+ { "accelerators", "AcceleratorTable", Layout },
+ { "accelerators", "AcceleratorTable", List },
+ { "accelerators", "AcceleratorTable", MenuButton },
+ { "accelerators", "AcceleratorTable", MultiList },
+ { "accelerators", "AcceleratorTable", OverrideShell },
+ { "accelerators", "AcceleratorTable", Paned },
+ { "accelerators", "AcceleratorTable", Panner },
+ { "accelerators", "AcceleratorTable", Porthole },
+ { "accelerators", "AcceleratorTable", RadioGroup },
+ { "accelerators", "AcceleratorTable", Repeater },
+ { "accelerators", "AcceleratorTable", RowCol },
+ { "accelerators", "AcceleratorTable", Scrollbar },
+ { "accelerators", "AcceleratorTable", Scrollbar2 },
+ { "accelerators", "AcceleratorTable", Shell },
+ { "accelerators", "AcceleratorTable", Simple },
+ { "accelerators", "AcceleratorTable", SimpleMenu },
+ { "accelerators", "AcceleratorTable", Slider2d },
+ { "accelerators", "AcceleratorTable", StripChart },
+ { "accelerators", "AcceleratorTable", Table },
+ { "accelerators", "AcceleratorTable", Tabs },
+ { "accelerators", "AcceleratorTable", TextBox },
+ { "accelerators", "AcceleratorTable", TextButton },
+ { "accelerators", "AcceleratorTable", TextToggle },
+ { "accelerators", "AcceleratorTable", Toggle },
+ { "accelerators", "AcceleratorTable", TopLevelShell },
+ { "accelerators", "AcceleratorTable", TransientShell },
+ { "accelerators", "AcceleratorTable", Tree },
+ { "accelerators", "AcceleratorTable", Viewport },
+ { "accelerators", "AcceleratorTable", WMShell },
+ { "accelerators", "AcceleratorTable", XfwfCommon },
+ { "accelerators", "AcceleratorTable", XfwfMenuBar },
+ { "addColumn", "Callback", Table },
+ { "addRow", "Callback", Table },
+ { "allowAddColumn", "Callback", Table },
+ { "allowAddRow", "Callback", Table },
+ { "allowDeleteColumn", "Callback", Table },
+ { "allowDeleteRow", "Callback", Table },
+ { "allowDeleteTable", "Callback", Table },
+ { "activate", "Callback", Group },
+ { "activate", "Callback", Icon },
+ { "activate", "Callback", RadioGroup },
+ { "activate", "Callback", TextButton },
+ { "activate", "Callback", TextToggle },
+ { "activateCallback", "Callback", ListTree },
+ { "activeAnchorBG", "Pixel", HTML },
+ { "activeAnchorFG", "Pixel", HTML },
+ { "addressFont", "FontStruct", HTML },
+ { "alignment", "Alignment", Group },
+ { "alignment", "Alignment", RadioGroup },
+ { "alignment", "Alignment", RowCol },
+ { "alignment", "Alignment", Slider2d },
+ { "alignment", "Alignment", TextBox },
+ { "alignment", "Alignment", TextButton },
+ { "alignment", "Alignment", TextToggle },
+ { "alignment", "Alignment", XfwfMenuBar },
+ { "allowAddColumn", "Callback", Table },
+ { "allowAddRow", "Callback", Table },
+ { "allowDeleteColumn", "Callback", Table },
+ { "allowDeleteRow", "Callback", Table },
+ { "allowDeleteTable", "Callback", Table },
+ { "allowHoriz", "Boolean", Viewport },
+ { "allowOff", "Boolean", Panner },
+ { "allowResize", "Boolean", Paned },
+ { "allowShellResize", "Boolean", ApplicationShell },
+ { "allowShellResize", "Boolean", OverrideShell },
+ { "allowShellResize", "Boolean", Shell },
+ { "allowShellResize", "Boolean", SimpleMenu },
+ { "allowShellResize", "Boolean", TopLevelShell },
+ { "allowShellResize", "Boolean", TransientShell },
+ { "allowShellResize", "Boolean", WMShell },
+ { "allowVert", "Boolean", Viewport },
+ { "alphaFont1", "FontStruct", Gterm },
+ { "alphaFont2", "FontStruct", Gterm },
+ { "alphaFont3", "FontStruct", Gterm },
+ { "alphaFont4", "FontStruct", Gterm },
+ { "alphaFont5", "FontStruct", Gterm },
+ { "alphaFont6", "FontStruct", Gterm },
+ { "alphaFont7", "FontStruct", Gterm },
+ { "alphaFont8", "FontStruct", Gterm },
+ { "ancestorSensitive", "Boolean", ApplicationShell },
+ { "ancestorSensitive", "Boolean", Arrow },
+ { "ancestorSensitive", "Boolean", AsciiText },
+ { "ancestorSensitive", "Boolean", Board },
+ { "ancestorSensitive", "Boolean", Box },
+ { "ancestorSensitive", "Boolean", Command },
+ { "ancestorSensitive", "Boolean", Core },
+ { "ancestorSensitive", "Boolean", Dialog },
+ { "ancestorSensitive", "Boolean", Form },
+ { "ancestorSensitive", "Boolean", Frame },
+ { "ancestorSensitive", "Boolean", Grip },
+ { "ancestorSensitive", "Boolean", Group },
+ { "ancestorSensitive", "Boolean", Gterm },
+ { "ancestorSensitive", "Boolean", HTML },
+ { "ancestorSensitive", "Boolean", Icon },
+ { "ancestorSensitive", "Boolean", Label },
+ { "ancestorSensitive", "Boolean", Layout },
+ { "ancestorSensitive", "Boolean", List },
+ { "ancestorSensitive", "Boolean", MenuButton },
+ { "ancestorSensitive", "Boolean", MultiList },
+ { "ancestorSensitive", "Boolean", OverrideShell },
+ { "ancestorSensitive", "Boolean", Paned },
+ { "ancestorSensitive", "Boolean", Panner },
+ { "ancestorSensitive", "Boolean", Porthole },
+ { "ancestorSensitive", "Boolean", RadioGroup },
+ { "ancestorSensitive", "Boolean", Repeater },
+ { "ancestorSensitive", "Boolean", RowCol },
+ { "ancestorSensitive", "Boolean", Scrollbar },
+ { "ancestorSensitive", "Boolean", Scrollbar2 },
+ { "ancestorSensitive", "Boolean", Shell },
+ { "ancestorSensitive", "Boolean", Simple },
+ { "ancestorSensitive", "Boolean", SimpleMenu },
+ { "ancestorSensitive", "Boolean", Slider2d },
+ { "ancestorSensitive", "Boolean", Sme },
+ { "ancestorSensitive", "Boolean", SmeBSB },
+ { "ancestorSensitive", "Boolean", SmeLine },
+ { "ancestorSensitive", "Boolean", StripChart },
+ { "ancestorSensitive", "Boolean", Table },
+ { "ancestorSensitive", "Boolean", TextBox },
+ { "ancestorSensitive", "Boolean", TextButton },
+ { "ancestorSensitive", "Boolean", TextToggle },
+ { "ancestorSensitive", "Boolean", Toggle },
+ { "ancestorSensitive", "Boolean", TopLevelShell },
+ { "ancestorSensitive", "Boolean", TransientShell },
+ { "ancestorSensitive", "Boolean", Tree },
+ { "ancestorSensitive", "Boolean", Viewport },
+ { "ancestorSensitive", "Boolean", WMShell },
+ { "ancestorSensitive", "Boolean", XfwfCommon },
+ { "ancestorSensitive", "Boolean", XfwfMenuBar },
+ { "anchorCallback", "Callback", HTML },
+ { "anchorColor", "Pixel", HTML },
+ { "anchorUnderlines", "Int", HTML },
+ { "argc", "Int", ApplicationShell },
+ { "argv", "StringArray", ApplicationShell },
+ { "arrowShadow", "Dimension", Arrow },
+ { "autoFill", "Boolean", AsciiText },
+ { "autoReconfigure", "Boolean", Tree },
+ { "background", "Pixel", ApplicationShell },
+ { "background", "Pixel", Arrow },
+ { "background", "Pixel", AsciiSink },
+ { "background", "Pixel", AsciiText },
+ { "background", "Pixel", Board },
+ { "background", "Pixel", Box },
+ { "background", "Pixel", Command },
+ { "background", "Pixel", Core },
+ { "background", "Pixel", Dialog },
+ { "background", "Pixel", Form },
+ { "background", "Pixel", Frame },
+ { "background", "Pixel", Group },
+ { "background", "Pixel", Gterm },
+ { "background", "Pixel", HTML },
+ { "background", "Pixel", Icon },
+ { "background", "Pixel", Label },
+ { "background", "Pixel", Layout },
+ { "background", "Pixel", List },
+ { "background", "Pixel", MenuButton },
+ { "background", "Pixel", MultiList },
+ { "background", "Pixel", OverrideShell },
+ { "background", "Pixel", Paned },
+ { "background", "Pixel", Panner },
+ { "background", "Pixel", Porthole },
+ { "background", "Pixel", RadioGroup },
+ { "background", "Pixel", Repeater },
+ { "background", "Pixel", RowCol },
+ { "background", "Pixel", Separator },
+ { "background", "Pixel", Scrollbar },
+ { "background", "Pixel", Scrollbar2 },
+ { "background", "Pixel", Shell },
+ { "background", "Pixel", Simple },
+ { "background", "Pixel", SimpleMenu },
+ { "background", "Pixel", Slider2d },
+ { "background", "Pixel", StripChart },
+ { "background", "Pixel", Table },
+ { "background", "Pixel", TextBox },
+ { "background", "Pixel", TextButton },
+ { "background", "Pixel", TextToggle },
+ { "background", "Pixel", Toggle },
+ { "background", "Pixel", TopLevelShell },
+ { "background", "Pixel", TransientShell },
+ { "background", "Pixel", Tree },
+ { "background", "Pixel", Viewport },
+ { "background", "Pixel", WMShell },
+ { "background", "Pixel", XfwfCommon },
+ { "background", "Pixel", XfwfMenuBar },
+ { "backgroundPixmap", "Pixmap", ApplicationShell },
+ { "backgroundPixmap", "Pixmap", Arrow },
+ { "backgroundPixmap", "Pixmap", AsciiText },
+ { "backgroundPixmap", "Pixmap", Board },
+ { "backgroundPixmap", "Pixmap", Box },
+ { "backgroundPixmap", "Pixmap", Command },
+ { "backgroundPixmap", "Pixmap", Core },
+ { "backgroundPixmap", "Pixmap", Dialog },
+ { "backgroundPixmap", "Pixmap", Form },
+ { "backgroundPixmap", "Pixmap", Frame },
+ { "backgroundPixmap", "Pixmap", Grip },
+ { "backgroundPixmap", "Pixmap", Group },
+ { "backgroundPixmap", "Pixmap", Gterm },
+ { "backgroundPixmap", "Pixmap", HTML },
+ { "backgroundPixmap", "Pixmap", Icon },
+ { "backgroundPixmap", "Pixmap", Label },
+ { "backgroundPixmap", "Pixmap", Layout },
+ { "backgroundPixmap", "Pixmap", List },
+ { "backgroundPixmap", "Pixmap", ListTree },
+ { "backgroundPixmap", "Pixmap", MenuButton },
+ { "backgroundPixmap", "Pixmap", MultiList },
+ { "backgroundPixmap", "Pixmap", OverrideShell },
+ { "backgroundPixmap", "Pixmap", Paned },
+ { "backgroundPixmap", "Pixmap", Panner },
+ { "backgroundPixmap", "Pixmap", Porthole },
+ { "backgroundPixmap", "Pixmap", RadioGroup },
+ { "backgroundPixmap", "Pixmap", Repeater },
+ { "backgroundPixmap", "Pixmap", RowCol },
+ { "backgroundPixmap", "Pixmap", Scrollbar },
+ { "backgroundPixmap", "Pixmap", Scrollbar2 },
+ { "backgroundPixmap", "Pixmap", Shell },
+ { "backgroundPixmap", "Pixmap", Simple },
+ { "backgroundPixmap", "Pixmap", SimpleMenu },
+ { "backgroundPixmap", "Pixmap", Slider2d },
+ { "backgroundPixmap", "Pixmap", StripChart },
+ { "backgroundPixmap", "Pixmap", Table },
+ { "backgroundPixmap", "Pixmap", Tabs },
+ { "backgroundPixmap", "Pixmap", TextBox },
+ { "backgroundPixmap", "Pixmap", TextButton },
+ { "backgroundPixmap", "Pixmap", TextToggle },
+ { "backgroundPixmap", "Pixmap", Toggle },
+ { "backgroundPixmap", "Pixmap", TopLevelShell },
+ { "backgroundPixmap", "Pixmap", TransientShell },
+ { "backgroundPixmap", "Pixmap", Tree },
+ { "backgroundPixmap", "Pixmap", Viewport },
+ { "backgroundPixmap", "Pixmap", WMShell },
+ { "backgroundPixmap", "Pixmap", XfwfCommon },
+ { "backgroundPixmap", "Pixmap", XfwfMenuBar },
+ { "backgroundStipple", "String", Panner },
+ { "backingStore", "BackingStore", SimpleMenu },
+ { "baseHeight", "Int", ApplicationShell },
+ { "baseHeight", "Int", TopLevelShell },
+ { "baseHeight", "Int", TransientShell },
+ { "baseHeight", "Int", WMShell },
+ { "basePixel", "Int", Gterm },
+ { "baseWidth", "Int", ApplicationShell },
+ { "baseWidth", "Int", TopLevelShell },
+ { "baseWidth", "Int", TransientShell },
+ { "baseWidth", "Int", WMShell },
+ { "betweenCursor", "Cursor", Paned },
+ { "bitmap", "Bitmap", Command },
+ { "bitmap", "Bitmap", Label },
+ { "bitmap", "Bitmap", MenuButton },
+ { "bitmap", "Bitmap", Repeater },
+ { "bitmap", "Bitmap", Separator },
+ { "bitmap", "Bitmap", Toggle },
+ { "boldFont", "FontStruct", HTML },
+ { "border", "Pixel", Separator },
+ { "borderColor", "Pixel", ApplicationShell },
+ { "borderColor", "Pixel", Arrow },
+ { "borderColor", "Pixel", AsciiText },
+ { "borderColor", "Pixel", Board },
+ { "borderColor", "Pixel", Box },
+ { "borderColor", "Pixel", Command },
+ { "borderColor", "Pixel", Core },
+ { "borderColor", "Pixel", Dialog },
+ { "borderColor", "Pixel", Form },
+ { "borderColor", "Pixel", Frame },
+ { "borderColor", "Pixel", Grip },
+ { "borderColor", "Pixel", Group },
+ { "borderColor", "Pixel", Gterm },
+ { "borderColor", "Pixel", HTML },
+ { "borderColor", "Pixel", Icon },
+ { "borderColor", "Pixel", Label },
+ { "borderColor", "Pixel", Layout },
+ { "borderColor", "Pixel", List },
+ { "borderColor", "Pixel", MenuButton },
+ { "borderColor", "Pixel", MultiList },
+ { "borderColor", "Pixel", OverrideShell },
+ { "borderColor", "Pixel", Paned },
+ { "borderColor", "Pixel", Panner },
+ { "borderColor", "Pixel", Porthole },
+ { "borderColor", "Pixel", RadioGroup },
+ { "borderColor", "Pixel", Repeater },
+ { "borderColor", "Pixel", RowCol },
+ { "borderColor", "Pixel", Scrollbar },
+ { "borderColor", "Pixel", Scrollbar2 },
+ { "borderColor", "Pixel", Shell },
+ { "borderColor", "Pixel", Simple },
+ { "borderColor", "Pixel", SimpleMenu },
+ { "borderColor", "Pixel", Slider2d },
+ { "borderColor", "Pixel", StripChart },
+ { "borderColor", "Pixel", Table },
+ { "borderColor", "Pixel", TextBox },
+ { "borderColor", "Pixel", TextButton },
+ { "borderColor", "Pixel", TextToggle },
+ { "borderColor", "Pixel", Toggle },
+ { "borderColor", "Pixel", TopLevelShell },
+ { "borderColor", "Pixel", TransientShell },
+ { "borderColor", "Pixel", Tree },
+ { "borderColor", "Pixel", Viewport },
+ { "borderColor", "Pixel", WMShell },
+ { "borderColor", "Pixel", XfwfCommon },
+ { "borderColor", "Pixel", XfwfMenuBar },
+ { "borderPixmap", "Pixmap", ApplicationShell },
+ { "borderPixmap", "Pixmap", Arrow },
+ { "borderPixmap", "Pixmap", AsciiText },
+ { "borderPixmap", "Pixmap", Board },
+ { "borderPixmap", "Pixmap", Box },
+ { "borderPixmap", "Pixmap", Command },
+ { "borderPixmap", "Pixmap", Core },
+ { "borderPixmap", "Pixmap", Dialog },
+ { "borderPixmap", "Pixmap", Form },
+ { "borderPixmap", "Pixmap", Frame },
+ { "borderPixmap", "Pixmap", Grip },
+ { "borderPixmap", "Pixmap", Group },
+ { "borderPixmap", "Pixmap", Gterm },
+ { "borderPixmap", "Pixmap", HTML },
+ { "borderPixmap", "Pixmap", Icon },
+ { "borderPixmap", "Pixmap", Label },
+ { "borderPixmap", "Pixmap", Layout },
+ { "borderPixmap", "Pixmap", List },
+ { "borderPixmap", "Pixmap", ListTree },
+ { "borderPixmap", "Pixmap", MenuButton },
+ { "borderPixmap", "Pixmap", MultiList },
+ { "borderPixmap", "Pixmap", OverrideShell },
+ { "borderPixmap", "Pixmap", Paned },
+ { "borderPixmap", "Pixmap", Panner },
+ { "borderPixmap", "Pixmap", Porthole },
+ { "borderPixmap", "Pixmap", RadioGroup },
+ { "borderPixmap", "Pixmap", Repeater },
+ { "borderPixmap", "Pixmap", RowCol },
+ { "borderPixmap", "Pixmap", Scrollbar },
+ { "borderPixmap", "Pixmap", Scrollbar2 },
+ { "borderPixmap", "Pixmap", Shell },
+ { "borderPixmap", "Pixmap", Simple },
+ { "borderPixmap", "Pixmap", SimpleMenu },
+ { "borderPixmap", "Pixmap", Slider2d },
+ { "borderPixmap", "Pixmap", StripChart },
+ { "borderPixmap", "Pixmap", Table },
+ { "borderPixmap", "Pixmap", Tabs },
+ { "borderPixmap", "Pixmap", TextBox },
+ { "borderPixmap", "Pixmap", TextButton },
+ { "borderPixmap", "Pixmap", TextToggle },
+ { "borderPixmap", "Pixmap", Toggle },
+ { "borderPixmap", "Pixmap", TopLevelShell },
+ { "borderPixmap", "Pixmap", TransientShell },
+ { "borderPixmap", "Pixmap", Tree },
+ { "borderPixmap", "Pixmap", Viewport },
+ { "borderPixmap", "Pixmap", WMShell },
+ { "borderPixmap", "Pixmap", XfwfCommon },
+ { "borderPixmap", "Pixmap", XfwfMenuBar },
+ { "borderWidth", "Dimension", ApplicationShell },
+ { "borderWidth", "Dimension", Arrow },
+ { "borderWidth", "Dimension", AsciiText },
+ { "borderWidth", "Dimension", Board },
+ { "borderWidth", "Dimension", Box },
+ { "borderWidth", "Dimension", Command },
+ { "borderWidth", "Dimension", Core },
+ { "borderWidth", "Dimension", Dialog },
+ { "borderWidth", "Dimension", Form },
+ { "borderWidth", "Dimension", Frame },
+ { "borderWidth", "Dimension", Grip },
+ { "borderWidth", "Dimension", Group },
+ { "borderWidth", "Dimension", Gterm },
+ { "borderWidth", "Dimension", HTML },
+ { "borderWidth", "Dimension", Icon },
+ { "borderWidth", "Dimension", Label },
+ { "borderWidth", "Dimension", Layout },
+ { "borderWidth", "Dimension", List },
+ { "borderWidth", "Dimension", MenuButton },
+ { "borderWidth", "Dimension", MultiList },
+ { "borderWidth", "Dimension", OverrideShell },
+ { "borderWidth", "Dimension", Paned },
+ { "borderWidth", "Dimension", Panner },
+ { "borderWidth", "Dimension", Porthole },
+ { "borderWidth", "Dimension", RadioGroup },
+ { "borderWidth", "Dimension", Repeater },
+ { "borderWidth", "Dimension", RowCol },
+ { "borderWidth", "Dimension", Scrollbar },
+ { "borderWidth", "Dimension", Scrollbar2 },
+ { "borderWidth", "Dimension", Separator },
+ { "borderWidth", "Dimension", Shell },
+ { "borderWidth", "Dimension", Simple },
+ { "borderWidth", "Dimension", SimpleMenu },
+ { "borderWidth", "Dimension", Slider2d },
+ { "borderWidth", "Dimension", Sme },
+ { "borderWidth", "Dimension", SmeBSB },
+ { "borderWidth", "Dimension", SmeLine },
+ { "borderWidth", "Dimension", StripChart },
+ { "borderWidth", "Dimension", Tabs },
+ { "borderWidth", "Dimension", TextBox },
+ { "borderWidth", "Dimension", TextButton },
+ { "borderWidth", "Dimension", TextToggle },
+ { "borderWidth", "Dimension", Toggle },
+ { "borderWidth", "Dimension", TopLevelShell },
+ { "borderWidth", "Dimension", TransientShell },
+ { "borderWidth", "Dimension", Tree },
+ { "borderWidth", "Dimension", Viewport },
+ { "borderWidth", "Dimension", WMShell },
+ { "borderWidth", "Dimension", XfwfCommon },
+ { "borderWidth", "Dimension", XfwfMenuBar },
+ { "bottom", "EdgeType", Dialog },
+ { "bottom", "EdgeType", Form },
+ { "bottom", "EdgeType", Viewport },
+ { "bottomMargin", "Dimension", SimpleMenu },
+ { "bottomMargin", "Dimension", Slider2d },
+ { "bottomMargin", "Dimension", TextBox },
+ { "bottomMargin", "Dimension", TextButton },
+ { "bottomMargin", "Dimension", TextToggle },
+ { "bottomMargin", "Position", AsciiText },
+ { "bottomShadowColor", "Pixel", Arrow },
+ { "bottomShadowColor", "Pixel", Board },
+ { "bottomShadowColor", "Pixel", Frame },
+ { "bottomShadowColor", "Pixel", Group },
+ { "bottomShadowColor", "Pixel", Icon },
+ { "bottomShadowColor", "Pixel", RadioGroup },
+ { "bottomShadowColor", "Pixel", RowCol },
+ { "bottomShadowColor", "Pixel", Scrollbar2 },
+ { "bottomShadowColor", "Pixel", Slider2d },
+ { "bottomShadowColor", "Pixel", TextBox },
+ { "bottomShadowColor", "Pixel", TextButton },
+ { "bottomShadowColor", "Pixel", TextToggle },
+ { "bottomShadowColor", "Pixel", XfwfMenuBar },
+ { "bottomShadowContast", "Int", Tabs },
+ { "bottomShadowPixel", "Pixel", Table },
+ { "bottomShadowPixmap", "Pixmap", Table },
+ { "bottomShadowStipple", "Bitmap", Arrow },
+ { "bottomShadowStipple", "Bitmap", Board },
+ { "bottomShadowStipple", "Bitmap", Frame },
+ { "bottomShadowStipple", "Bitmap", Group },
+ { "bottomShadowStipple", "Bitmap", Icon },
+ { "bottomShadowStipple", "Bitmap", RadioGroup },
+ { "bottomShadowStipple", "Bitmap", RowCol },
+ { "bottomShadowStipple", "Bitmap", Scrollbar2 },
+ { "bottomShadowStipple", "Bitmap", Slider2d },
+ { "bottomShadowStipple", "Bitmap", TextBox },
+ { "bottomShadowStipple", "Bitmap", TextButton },
+ { "bottomShadowStipple", "Bitmap", TextToggle },
+ { "bottomShadowStipple", "Bitmap", XfwfMenuBar },
+ { "branchPixmap", "Bitmap", ListTree },
+ { "branchOpenPixmap", "Bitmap", ListTree },
+ { "branchCallback", "Callback", ListTree },
+ { "busyCursor", "String", Gterm },
+ { "busyCursorBgColor", "Pixel", Gterm },
+ { "busyCursorFgColor", "Pixel", Gterm },
+ { "cacheRasters", "String", Gterm },
+ { "callback", "Callback", Arrow },
+ { "callback", "Callback", AsciiSrc },
+ { "callback", "Callback", AsciiText },
+ { "callback", "Callback", Command },
+ { "callback", "Callback", Grip },
+ { "callback", "Callback", List },
+ { "callback", "Callback", MenuButton },
+ { "callback", "Callback", MultiList },
+ { "callback", "Callback", Repeater },
+ { "callback", "Callback", Sme },
+ { "callback", "Callback", SmeBSB },
+ { "callback", "Callback", SmeLine },
+ { "callback", "Callback", Tabs },
+ { "callback", "Callback", Toggle },
+ { "canvasHeight", "Dimension", Panner },
+ { "canvasWidth", "Dimension", Panner },
+ { "changedCell", "Callback", Table },
+ { "changedColumnWidth", "Callback", Table },
+ { "changedRowHeight", "Callback", Table },
+ { "children", "WidgetList", ApplicationShell },
+ { "children", "WidgetList", Arrow },
+ { "children", "WidgetList", Board },
+ { "children", "WidgetList", Box },
+ { "children", "WidgetList", Dialog },
+ { "children", "WidgetList", Form },
+ { "children", "WidgetList", Frame },
+ { "children", "WidgetList", Group },
+ { "children", "WidgetList", HTML },
+ { "children", "WidgetList", Icon },
+ { "children", "WidgetList", Layout },
+ { "children", "WidgetList", OverrideShell },
+ { "children", "WidgetList", Paned },
+ { "children", "WidgetList", Porthole },
+ { "children", "WidgetList", RadioGroup },
+ { "children", "WidgetList", RowCol },
+ { "children", "WidgetList", Scrollbar2 },
+ { "children", "WidgetList", Shell },
+ { "children", "WidgetList", SimpleMenu },
+ { "children", "WidgetList", Slider2d },
+ { "children", "WidgetList", Table },
+ { "children", "WidgetList", TextBox },
+ { "children", "WidgetList", TextButton },
+ { "children", "WidgetList", TextToggle },
+ { "children", "WidgetList", TopLevelShell },
+ { "children", "WidgetList", TransientShell },
+ { "children", "WidgetList", Tree },
+ { "children", "WidgetList", Viewport },
+ { "children", "WidgetList", WMShell },
+ { "children", "WidgetList", XfwfCommon },
+ { "children", "WidgetList", XfwfMenuBar },
+ { "cmapInitialize", "Boolean", Gterm },
+ { "cmapInterpolate", "Boolean", Gterm },
+ { "cmapName", "String", Gterm },
+ { "cmapShadow", "Int", Gterm },
+ { "cmapUpdate", "Int", Gterm },
+ { "color0", "Pixel", Gterm },
+ { "color1", "Pixel", Gterm },
+ { "color2", "Pixel", Gterm },
+ { "color3", "Pixel", Gterm },
+ { "color4", "Pixel", Gterm },
+ { "color5", "Pixel", Gterm },
+ { "color6", "Pixel", Gterm },
+ { "color7", "Pixel", Gterm },
+ { "color8", "Pixel", Gterm },
+ { "color9", "Pixel", Gterm },
+ { "colormap", "Colormap", ApplicationShell },
+ { "colormap", "Colormap", Arrow },
+ { "colormap", "Colormap", AsciiText },
+ { "colormap", "Colormap", Board },
+ { "colormap", "Colormap", Box },
+ { "colormap", "Colormap", Command },
+ { "colormap", "Colormap", Core },
+ { "colormap", "Colormap", Dialog },
+ { "colormap", "Colormap", Form },
+ { "colormap", "Colormap", Frame },
+ { "colormap", "Colormap", Grip },
+ { "colormap", "Colormap", Group },
+ { "colormap", "Colormap", Gterm },
+ { "colormap", "Colormap", HTML },
+ { "colormap", "Colormap", Icon },
+ { "colormap", "Colormap", Label },
+ { "colormap", "Colormap", Layout },
+ { "colormap", "Colormap", List },
+ { "colormap", "Colormap", MenuButton },
+ { "colormap", "Colormap", MultiList },
+ { "colormap", "Colormap", OverrideShell },
+ { "colormap", "Colormap", Paned },
+ { "colormap", "Colormap", Panner },
+ { "colormap", "Colormap", Porthole },
+ { "colormap", "Colormap", RadioGroup },
+ { "colormap", "Colormap", Repeater },
+ { "colormap", "Colormap", RowCol },
+ { "colormap", "Colormap", Scrollbar },
+ { "colormap", "Colormap", Scrollbar2 },
+ { "colormap", "Colormap", Shell },
+ { "colormap", "Colormap", Simple },
+ { "colormap", "Colormap", SimpleMenu },
+ { "colormap", "Colormap", Slider2d },
+ { "colormap", "Colormap", StripChart },
+ { "colormap", "Colormap", Table },
+ { "colormap", "Colormap", Tabs },
+ { "colormap", "Colormap", TextBox },
+ { "colormap", "Colormap", TextButton },
+ { "colormap", "Colormap", TextToggle },
+ { "colormap", "Colormap", Toggle },
+ { "colormap", "Colormap", TopLevelShell },
+ { "colormap", "Colormap", TransientShell },
+ { "colormap", "Colormap", Tree },
+ { "colormap", "Colormap", Viewport },
+ { "colormap", "Colormap", WMShell },
+ { "colormap", "Colormap", XfwfCommon },
+ { "colormap", "Colormap", XfwfMenuBar },
+ { "columnForeground", "Pixel", Table },
+ { "columnMargin", "Dimension", Table },
+ { "columnSpacing", "Dimension", List },
+ { "columnSpacing", "Dimension", MultiList },
+ { "columnWidth", "Dimension", MultiList },
+ { "columns", "Int", Group },
+ { "columns", "Int", RadioGroup },
+ { "columns", "Int", RowCol },
+ { "columns", "Int", Table },
+ { "columns", "Int", XfwfMenuBar },
+ { "copyOnResize", "Boolean", Gterm },
+ { "cornerRoundPercent", "Dimension", Command },
+ { "cornerRoundPercent", "Dimension", MenuButton },
+ { "cornerRoundPercent", "Dimension", Repeater },
+ { "cornerRoundPercent", "Dimension", Toggle },
+ { "createPopupChildProc", "Function", ApplicationShell },
+ { "createPopupChildProc", "Function", OverrideShell },
+ { "createPopupChildProc", "Function", Shell },
+ { "createPopupChildProc", "Function", SimpleMenu },
+ { "createPopupChildProc", "Function", TopLevelShell },
+ { "createPopupChildProc", "Function", TransientShell },
+ { "createPopupChildProc", "Function", WMShell },
+ { "createTable", "Callback", Table },
+ { "crosshairCursorColor", "Pixel", Gterm },
+ { "cursor", "Cursor", Arrow },
+ { "cursor", "Cursor", AsciiText },
+ { "cursor", "Cursor", Board },
+ { "cursor", "Cursor", Command },
+ { "cursor", "Cursor", Frame },
+ { "cursor", "Cursor", Grip },
+ { "cursor", "Cursor", Group },
+ { "cursor", "Cursor", Icon },
+ { "cursor", "Cursor", Label },
+ { "cursor", "Cursor", List },
+ { "cursor", "Cursor", MenuButton },
+ { "cursor", "Cursor", MultiList },
+ { "cursor", "Cursor", Paned },
+ { "cursor", "Cursor", Panner },
+ { "cursor", "Cursor", RadioGroup },
+ { "cursor", "Cursor", Repeater },
+ { "cursor", "Cursor", RowCol },
+ { "cursor", "Cursor", Scrollbar },
+ { "cursor", "Cursor", Scrollbar2 },
+ { "cursor", "Cursor", Separator },
+ { "cursor", "Cursor", Simple },
+ { "cursor", "Cursor", SimpleMenu },
+ { "cursor", "Cursor", Slider2d },
+ { "cursor", "Cursor", StripChart },
+ { "cursor", "Cursor", TextBox },
+ { "cursor", "Cursor", TextButton },
+ { "cursor", "Cursor", TextToggle },
+ { "cursor", "Cursor", Toggle },
+ { "cursor", "Cursor", XfwfMenuBar },
+ { "cursorName", "String", AsciiText },
+ { "cursorName", "String", Command },
+ { "cursorName", "String", Grip },
+ { "cursorName", "String", Label },
+ { "cursorName", "String", List },
+ { "cursorName", "String", MenuButton },
+ { "cursorName", "String", MultiList },
+ { "cursorName", "String", Panner },
+ { "cursorName", "String", Repeater },
+ { "cursorName", "String", Separator },
+ { "cursorName", "String", Scrollbar },
+ { "cursorName", "String", Simple },
+ { "cursorName", "String", StripChart },
+ { "cursorName", "String", Toggle },
+ { "dashedAnchorUnderlines", "Boolean", HTML },
+ { "dashedVisitedAnchorUnderlines", "Boolean", HTML },
+ { "dataCompression", "Boolean", AsciiSrc },
+ { "dataCompression", "Boolean", AsciiText },
+ { "debug", "Boolean", Layout },
+ { "decay", "Int", Repeater },
+ { "defaultColumns", "Int", List },
+ { "defaultColumns", "Int", MultiList },
+ { "defaultDistance", "Int", Dialog },
+ { "defaultDistance", "Int", Form },
+ { "defaultDistance", "Int", Viewport },
+ { "defaultMarker", "String", Gterm },
+ { "defaultScale", "Dimension", Panner },
+ { "defaultWidth", "Int", Table },
+ { "deiconifyWindow", "Boolean", Gterm },
+ { "deleteColumn", "Callback", Table },
+ { "deleteRow", "Callback", Table },
+ { "deleteTable", "Callback", Table },
+ { "delayImageLoads", "Boolean", HTML },
+ { "depth", "Int", ApplicationShell },
+ { "depth", "Int", Arrow },
+ { "depth", "Int", AsciiText },
+ { "depth", "Int", Board },
+ { "depth", "Int", Box },
+ { "depth", "Int", Command },
+ { "depth", "Int", Core },
+ { "depth", "Int", Dialog },
+ { "depth", "Int", Form },
+ { "depth", "Int", Frame },
+ { "depth", "Int", Grip },
+ { "depth", "Int", Group },
+ { "depth", "Int", Gterm },
+ { "depth", "Int", HTML },
+ { "depth", "Int", Icon },
+ { "depth", "Int", Label },
+ { "depth", "Int", Layout },
+ { "depth", "Int", List },
+ { "depth", "Int", MenuButton },
+ { "depth", "Int", MultiList },
+ { "depth", "Int", OverrideShell },
+ { "depth", "Int", Paned },
+ { "depth", "Int", Panner },
+ { "depth", "Int", Porthole },
+ { "depth", "Int", RadioGroup },
+ { "depth", "Int", Repeater },
+ { "depth", "Int", RowCol },
+ { "depth", "Int", Scrollbar },
+ { "depth", "Int", Scrollbar2 },
+ { "depth", "Int", Shell },
+ { "depth", "Int", Simple },
+ { "depth", "Int", SimpleMenu },
+ { "depth", "Int", Slider2d },
+ { "depth", "Int", StripChart },
+ { "depth", "Int", Table },
+ { "depth", "Int", TextBox },
+ { "depth", "Int", TextButton },
+ { "depth", "Int", TextToggle },
+ { "depth", "Int", Toggle },
+ { "depth", "Int", TopLevelShell },
+ { "depth", "Int", TransientShell },
+ { "depth", "Int", Tree },
+ { "depth", "Int", Viewport },
+ { "depth", "Int", WMShell },
+ { "depth", "Int", XfwfCommon },
+ { "depth", "Int", XfwfMenuBar },
+ { "destroyCallback", "Callback", ApplicationShell },
+ { "destroyCallback", "Callback", Arrow },
+ { "destroyCallback", "Callback", AsciiSink },
+ { "destroyCallback", "Callback", AsciiSrc },
+ { "destroyCallback", "Callback", AsciiText },
+ { "destroyCallback", "Callback", Board },
+ { "destroyCallback", "Callback", Box },
+ { "destroyCallback", "Callback", Command },
+ { "destroyCallback", "Callback", Core },
+ { "destroyCallback", "Callback", Dialog },
+ { "destroyCallback", "Callback", Form },
+ { "destroyCallback", "Callback", Frame },
+ { "destroyCallback", "Callback", Grip },
+ { "destroyCallback", "Callback", Group },
+ { "destroyCallback", "Callback", Gterm },
+ { "destroyCallback", "Callback", HTML },
+ { "destroyCallback", "Callback", Icon },
+ { "destroyCallback", "Callback", Label },
+ { "destroyCallback", "Callback", Layout },
+ { "destroyCallback", "Callback", List },
+ { "destroyCallback", "Callback", MenuButton },
+ { "destroyCallback", "Callback", MultiList },
+ { "destroyCallback", "Callback", Object },
+ { "destroyCallback", "Callback", OverrideShell },
+ { "destroyCallback", "Callback", Paned },
+ { "destroyCallback", "Callback", Panner },
+ { "destroyCallback", "Callback", Porthole },
+ { "destroyCallback", "Callback", RadioGroup },
+ { "destroyCallback", "Callback", Repeater },
+ { "destroyCallback", "Callback", RowCol },
+ { "destroyCallback", "Callback", Scrollbar },
+ { "destroyCallback", "Callback", Scrollbar2 },
+ { "destroyCallback", "Callback", Shell },
+ { "destroyCallback", "Callback", Simple },
+ { "destroyCallback", "Callback", SimpleMenu },
+ { "destroyCallback", "Callback", Slider2d },
+ { "destroyCallback", "Callback", Sme },
+ { "destroyCallback", "Callback", SmeBSB },
+ { "destroyCallback", "Callback", SmeLine },
+ { "destroyCallback", "Callback", StripChart },
+ { "destroyCallback", "Callback", Table },
+ { "destroyCallback", "Callback", TextBox },
+ { "destroyCallback", "Callback", TextButton },
+ { "destroyCallback", "Callback", TextToggle },
+ { "destroyCallback", "Callback", Toggle },
+ { "destroyCallback", "Callback", TopLevelShell },
+ { "destroyCallback", "Callback", TransientShell },
+ { "destroyCallback", "Callback", Tree },
+ { "destroyCallback", "Callback", Viewport },
+ { "destroyCallback", "Callback", WMShell },
+ { "destroyCallback", "Callback", XfwfCommon },
+ { "destroyCallback", "Callback", XfwfMenuBar },
+ { "dialogBgColor", "Pixel", Gterm },
+ { "dialogFgColor", "Pixel", Gterm },
+ { "dialogFont1", "FontStruct", Gterm },
+ { "dialogFont2", "FontStruct", Gterm },
+ { "dialogFont3", "FontStruct", Gterm },
+ { "dialogFont4", "FontStruct", Gterm },
+ { "dialogFont5", "FontStruct", Gterm },
+ { "dialogFont6", "FontStruct", Gterm },
+ { "dialogFont7", "FontStruct", Gterm },
+ { "dialogFont8", "FontStruct", Gterm },
+ { "direction", "Alignment", Arrow },
+ { "displayCaret", "Boolean", AsciiText },
+ { "displayNonprinting", "Boolean", AsciiSink },
+ { "displayNonprinting", "Boolean", AsciiText },
+ { "displayPosition", "Int", AsciiText },
+ { "echo", "Boolean", AsciiSink },
+ { "echo", "Boolean", AsciiText },
+ { "editBackground", "Pixel", Table },
+ { "editForeground", "Pixel", Table },
+ { "editable", "Boolean", Table },
+ { "editType", "EditMode", AsciiSrc },
+ { "editType", "EditMode", AsciiText },
+ { "encoding", "UnsignedChar", Command },
+ { "encoding", "UnsignedChar", Label },
+ { "encoding", "UnsignedChar", MenuButton },
+ { "encoding", "UnsignedChar", Repeater },
+ { "encoding", "UnsignedChar", Table },
+ { "encoding", "UnsignedChar", Toggle },
+ { "encoding", "UnsignedChar", Table },
+ { "fancySelections", "Boolean", HTML },
+ { "fixedFont", "FontStruct", HTML },
+ { "fixedboldFont", "FontStruct", HTML },
+ { "fixeditalicFont", "FontStruct", HTML },
+ { "flash", "Boolean", Repeater },
+ { "font", "FontStruct", AsciiSink },
+ { "font", "FontStruct", AsciiText },
+ { "font", "FontStruct", Command },
+ { "font", "FontStruct", Group },
+ { "font", "FontStruct", HTML },
+ { "font", "FontStruct", Label },
+ { "font", "FontStruct", List },
+ { "font", "FontStruct", ListTree },
+ { "font", "FontStruct", MenuButton },
+ { "font", "FontStruct", MultiList },
+ { "font", "FontStruct", RadioGroup },
+ { "font", "FontStruct", Repeater },
+ { "font", "FontStruct", Slider2d },
+ { "font", "FontStruct", SmeBSB },
+ { "font", "FontStruct", Tabs },
+ { "font", "FontStruct", Table },
+ { "font", "FontStruct", TextBox },
+ { "font", "FontStruct", TextButton },
+ { "font", "FontStruct", TextToggle },
+ { "font", "FontStruct", Toggle },
+ { "footerText", "String", HTML },
+ { "forceBars", "Boolean", Viewport },
+ { "forceColumns", "Boolean", List },
+ { "forceColumns", "Boolean", MultiList },
+ { "foreground", "Pixel", Arrow },
+ { "foreground", "Pixel", AsciiSink },
+ { "foreground", "Pixel", AsciiText },
+ { "foreground", "Pixel", Command },
+ { "foreground", "Pixel", Grip },
+ { "foreground", "Pixel", Group },
+ { "foreground", "Pixel", HTML },
+ { "foreground", "Pixel", Label },
+ { "foreground", "Pixel", List },
+ { "foreground", "Pixel", ListTree },
+ { "foreground", "Pixel", MenuButton },
+ { "foreground", "Pixel", MultiList },
+ { "foreground", "Pixel", Panner },
+ { "foreground", "Pixel", RadioGroup },
+ { "foreground", "Pixel", Repeater },
+ { "foreground", "Pixel", Scrollbar },
+ { "foreground", "Pixel", Separator },
+ { "foreground", "Pixel", Slider2d },
+ { "foreground", "Pixel", SmeBSB },
+ { "foreground", "Pixel", SmeLine },
+ { "foreground", "Pixel", StripChart },
+ { "foreground", "Pixel", Table },
+ { "foreground", "Pixel", TextBox },
+ { "foreground", "Pixel", TextButton },
+ { "foreground", "Pixel", TextToggle },
+ { "foreground", "Pixel", Toggle },
+ { "foreground", "Pixel", Tree },
+ { "frameType", "FrameType", Arrow },
+ { "frameType", "FrameType", Board },
+ { "frameType", "FrameType", Frame },
+ { "frameType", "FrameType", Group },
+ { "frameType", "FrameType", Icon },
+ { "frameType", "FrameType", RadioGroup },
+ { "frameType", "FrameType", RowCol },
+ { "frameType", "FrameType", Scrollbar2 },
+ { "frameType", "FrameType", Slider2d },
+ { "frameType", "FrameType", TextBox },
+ { "frameType", "FrameType", TextButton },
+ { "frameType", "FrameType", TextToggle },
+ { "frameType", "FrameType", XfwfMenuBar },
+ { "frameWidth", "Dimension", Arrow },
+ { "frameWidth", "Dimension", Board },
+ { "frameWidth", "Dimension", Frame },
+ { "frameWidth", "Dimension", Group },
+ { "frameWidth", "Dimension", Icon },
+ { "frameWidth", "Dimension", RadioGroup },
+ { "frameWidth", "Dimension", RowCol },
+ { "frameWidth", "Dimension", Scrollbar2 },
+ { "frameWidth", "Dimension", Slider2d },
+ { "frameWidth", "Dimension", TextBox },
+ { "frameWidth", "Dimension", TextButton },
+ { "frameWidth", "Dimension", TextToggle },
+ { "frameWidth", "Dimension", XfwfMenuBar },
+ { "fromHoriz", "Widget", Dialog },
+ { "fromHoriz", "Widget", Form },
+ { "fromHoriz", "Widget", Viewport },
+ { "fromVert", "Widget", Dialog },
+ { "fromVert", "Widget", Form },
+ { "fromVert", "Widget", Viewport },
+ { "geometry", "String", ApplicationShell },
+ { "geometry", "String", OverrideShell },
+ { "geometry", "String", Shell },
+ { "geometry", "String", SimpleMenu },
+ { "geometry", "String", TopLevelShell },
+ { "geometry", "String", TransientShell },
+ { "geometry", "String", WMShell },
+ { "getValue", "Callback", StripChart },
+ { "ginmodeBlinkInterval", "Int", Gterm },
+ { "ginmodeCursor", "String", Gterm },
+ { "ginmodeCursorBgColor", "Pixel", Gterm },
+ { "ginmodeCursorFgColor", "Pixel", Gterm },
+ { "gravity", "Gravity", Tree },
+ { "gripCursor", "Cursor", Paned },
+ { "gripIndent", "Position", Paned },
+ { "gripTranslations", "TranslationTable", Paned },
+ { "hSpace", "Dimension", Box },
+ { "hSpace", "Dimension", Tree },
+ { "header1Font1Font", "FontStruct", HTML },
+ { "header2Font2Font", "FontStruct", HTML },
+ { "header3Font3Font", "FontStruct", HTML },
+ { "header4Font4Font", "FontStruct", HTML },
+ { "header5Font5Font", "FontStruct", HTML },
+ { "header6Font6Font", "FontStruct", HTML },
+ { "headerText", "String", HTML },
+ { "height", "Dimension", ApplicationShell },
+ { "height", "Dimension", Arrow },
+ { "height", "Dimension", AsciiText },
+ { "height", "Dimension", Board },
+ { "height", "Dimension", Box },
+ { "height", "Dimension", Command },
+ { "height", "Dimension", Core },
+ { "height", "Dimension", Dialog },
+ { "height", "Dimension", Form },
+ { "height", "Dimension", Frame },
+ { "height", "Dimension", Grip },
+ { "height", "Dimension", Group },
+ { "height", "Dimension", Gterm },
+ { "height", "Dimension", HTML },
+ { "height", "Dimension", Icon },
+ { "height", "Dimension", Label },
+ { "height", "Dimension", Layout },
+ { "height", "Dimension", List },
+ { "height", "Dimension", MenuButton },
+ { "height", "Dimension", MultiList },
+ { "height", "Dimension", OverrideShell },
+ { "height", "Dimension", Paned },
+ { "height", "Dimension", Panner },
+ { "height", "Dimension", Porthole },
+ { "height", "Dimension", RadioGroup },
+ { "height", "Dimension", Repeater },
+ { "height", "Dimension", RowCol },
+ { "height", "Dimension", Scrollbar },
+ { "height", "Dimension", Scrollbar2 },
+ { "height", "Dimension", Separator },
+ { "height", "Dimension", Shell },
+ { "height", "Dimension", Simple },
+ { "height", "Dimension", SimpleMenu },
+ { "height", "Dimension", Slider2d },
+ { "height", "Dimension", Sme },
+ { "height", "Dimension", SmeBSB },
+ { "height", "Dimension", SmeLine },
+ { "height", "Dimension", StripChart },
+ { "height", "Dimension", Table },
+ { "height", "Dimension", TextBox },
+ { "height", "Dimension", TextButton },
+ { "height", "Dimension", TextToggle },
+ { "height", "Dimension", Toggle },
+ { "height", "Dimension", TopLevelShell },
+ { "height", "Dimension", TransientShell },
+ { "height", "Dimension", Tree },
+ { "height", "Dimension", Viewport },
+ { "height", "Dimension", WMShell },
+ { "height", "Dimension", XfwfCommon },
+ { "height", "Dimension", XfwfMenuBar },
+ { "heightInc", "Int", ApplicationShell },
+ { "heightInc", "Int", TopLevelShell },
+ { "heightInc", "Int", TransientShell },
+ { "heightInc", "Int", WMShell },
+ { "highlight", "Pixel", StripChart },
+ { "highlightBackground", "Pixel", MultiList },
+ { "highlightCallback", "Callback", ListTree },
+ { "highlightColor", "Pixel", Arrow },
+ { "highlightColor", "Pixel", Board },
+ { "highlightColor", "Pixel", Frame },
+ { "highlightColor", "Pixel", Group },
+ { "highlightColor", "Pixel", Icon },
+ { "highlightColor", "Pixel", RadioGroup },
+ { "highlightColor", "Pixel", RowCol },
+ { "highlightColor", "Pixel", Scrollbar2 },
+ { "highlightColor", "Pixel", Slider2d },
+ { "highlightColor", "Pixel", TextBox },
+ { "highlightColor", "Pixel", TextButton },
+ { "highlightColor", "Pixel", TextToggle },
+ { "highlightColor", "Pixel", XfwfCommon },
+ { "highlightColor", "Pixel", XfwfMenuBar },
+ { "highlightForeground", "Pixel", MultiList },
+ { "highlightPixmap", "Pixmap", Arrow },
+ { "highlightPixmap", "Pixmap", Board },
+ { "highlightPixmap", "Pixmap", Frame },
+ { "highlightPixmap", "Pixmap", Group },
+ { "highlightPixmap", "Pixmap", Icon },
+ { "highlightPixmap", "Pixmap", RadioGroup },
+ { "highlightPixmap", "Pixmap", RowCol },
+ { "highlightPixmap", "Pixmap", Scrollbar2 },
+ { "highlightPixmap", "Pixmap", Slider2d },
+ { "highlightPixmap", "Pixmap", TextBox },
+ { "highlightPixmap", "Pixmap", TextButton },
+ { "highlightPixmap", "Pixmap", TextToggle },
+ { "highlightPixmap", "Pixmap", XfwfCommon },
+ { "highlightPixmap", "Pixmap", XfwfMenuBar },
+ { "highlightThickness", "Dimension", Arrow },
+ { "highlightThickness", "Dimension", Board },
+ { "highlightThickness", "Dimension", Command },
+ { "highlightThickness", "Dimension", Frame },
+ { "highlightThickness", "Dimension", Group },
+ { "highlightThickness", "Dimension", Icon },
+ { "highlightThickness", "Dimension", MenuButton },
+ { "highlightThickness", "Dimension", RadioGroup },
+ { "highlightThickness", "Dimension", Repeater },
+ { "highlightThickness", "Dimension", RowCol },
+ { "highlightThickness", "Dimension", Scrollbar2 },
+ { "highlightThickness", "Dimension", Slider2d },
+ { "highlightThickness", "Dimension", TextBox },
+ { "highlightThickness", "Dimension", TextButton },
+ { "highlightThickness", "Dimension", TextToggle },
+ { "highlightThickness", "Dimension", Toggle },
+ { "highlightThickness", "Dimension", XfwfCommon },
+ { "highlightThickness", "Dimension", XfwfMenuBar },
+ { "horizDistance", "Int", Dialog },
+ { "horizDistance", "Int", Form },
+ { "horizDistance", "Int", Viewport },
+ { "horizontalBetweenCursor", "Cursor", Paned },
+ { "horizontalGripCursor", "Cursor", Paned },
+ { "horizontalScroll", "Widget", Table },
+ { "horizontalScrollBar", "Widget", HTML },
+ { "horizontalScrollOnTop", "Boolean", HTML },
+ { "horizontalSpacing", "Dimension", ListTree },
+ { "hunit", "Float", Arrow },
+ { "hunit", "Float", Board },
+ { "hunit", "Float", Group },
+ { "hunit", "Float", Icon },
+ { "hunit", "Float", RadioGroup },
+ { "hunit", "Float", RowCol },
+ { "hunit", "Float", Scrollbar2 },
+ { "hunit", "Float", Slider2d },
+ { "hunit", "Float", TextBox },
+ { "hunit", "Float", TextButton },
+ { "hunit", "Float", TextToggle },
+ { "hunit", "Float", XfwfMenuBar },
+ { "icon", "Bitmap", Dialog },
+ { "iconMask", "Bitmap", ApplicationShell },
+ { "iconMask", "Bitmap", TopLevelShell },
+ { "iconMask", "Bitmap", TransientShell },
+ { "iconMask", "Bitmap", WMShell },
+ { "iconName", "String", ApplicationShell },
+ { "iconName", "String", TopLevelShell },
+ { "iconNameEncoding", "Atom", ApplicationShell },
+ { "iconNameEncoding", "Atom", TopLevelShell },
+ { "iconPixmap", "Bitmap", ApplicationShell },
+ { "iconPixmap", "Bitmap", TopLevelShell },
+ { "iconPixmap", "Bitmap", TransientShell },
+ { "iconPixmap", "Bitmap", WMShell },
+ { "iconWindow", "Window", ApplicationShell },
+ { "iconWindow", "Window", TopLevelShell },
+ { "iconWindow", "Window", TransientShell },
+ { "iconWindow", "Window", WMShell },
+ { "iconX", "Int", ApplicationShell },
+ { "iconX", "Int", TopLevelShell },
+ { "iconX", "Int", TransientShell },
+ { "iconX", "Int", WMShell },
+ { "iconY", "Int", ApplicationShell },
+ { "iconY", "Int", TopLevelShell },
+ { "iconY", "Int", TransientShell },
+ { "iconY", "Int", WMShell },
+ { "iconic", "Boolean", ApplicationShell },
+ { "iconic", "Boolean", TopLevelShell },
+ { "idleCursor", "String", Gterm },
+ { "idleCursorBgColor", "Pixel", Gterm },
+ { "idleCursorFgColor", "Pixel", Gterm },
+ { "image", "Icon", Icon },
+ { "imageBorders", "Boolean", HTML },
+ { "increment", "Float", Scrollbar2 },
+ { "indent", "Dimension", ListTree },
+ { "initialDelay", "Cardinal", Arrow },
+ { "initialDelay", "Cardinal", Scrollbar2 },
+ { "initialDelay", "Int", Repeater },
+ { "initialState", "InitialState", ApplicationShell },
+ { "initialState", "InitialState", TopLevelShell },
+ { "initialState", "InitialState", TransientShell },
+ { "initialState", "InitialState", WMShell },
+ { "insensitiveContrast", "Int", Tabs },
+ { "innerOffset", "Dimension", Arrow },
+ { "innerOffset", "Dimension", Board },
+ { "innerOffset", "Dimension", Frame },
+ { "innerOffset", "Dimension", Group },
+ { "innerOffset", "Dimension", Icon },
+ { "innerOffset", "Dimension", RadioGroup },
+ { "innerOffset", "Dimension", RowCol },
+ { "innerOffset", "Dimension", Scrollbar2 },
+ { "innerOffset", "Dimension", Slider2d },
+ { "innerOffset", "Dimension", TextBox },
+ { "innerOffset", "Dimension", TextButton },
+ { "innerOffset", "Dimension", TextToggle },
+ { "innerOffset", "Dimension", XfwfMenuBar },
+ { "input", "Bool", ApplicationShell },
+ { "input", "Bool", TopLevelShell },
+ { "input", "Bool", TransientShell },
+ { "input", "Bool", WMShell },
+ { "insensitiveBorder", "Pixmap", AsciiText },
+ { "insensitiveBorder", "Pixmap", Command },
+ { "insensitiveBorder", "Pixmap", Grip },
+ { "insensitiveBorder", "Pixmap", Label },
+ { "insensitiveBorder", "Pixmap", List },
+ { "insensitiveBorder", "Pixmap", MenuButton },
+ { "insensitiveBorder", "Pixmap", MultiList },
+ { "insensitiveBorder", "Pixmap", Panner },
+ { "insensitiveBorder", "Pixmap", Repeater },
+ { "insensitiveBorder", "Pixmap", Scrollbar },
+ { "insensitiveBorder", "Pixmap", Simple },
+ { "insensitiveBorder", "Pixmap", StripChart },
+ { "insensitiveBorder", "Pixmap", Toggle },
+ { "insertPosition", "Function", ApplicationShell },
+ { "insertPosition", "Function", Arrow },
+ { "insertPosition", "Function", Board },
+ { "insertPosition", "Function", Box },
+ { "insertPosition", "Function", Dialog },
+ { "insertPosition", "Function", Form },
+ { "insertPosition", "Function", Frame },
+ { "insertPosition", "Function", Group },
+ { "insertPosition", "Function", HTML },
+ { "insertPosition", "Function", Icon },
+ { "insertPosition", "Function", Layout },
+ { "insertPosition", "Function", OverrideShell },
+ { "insertPosition", "Function", Paned },
+ { "insertPosition", "Function", Porthole },
+ { "insertPosition", "Function", RadioGroup },
+ { "insertPosition", "Function", RowCol },
+ { "insertPosition", "Function", Scrollbar2 },
+ { "insertPosition", "Function", Shell },
+ { "insertPosition", "Function", SimpleMenu },
+ { "insertPosition", "Function", Slider2d },
+ { "insertPosition", "Function", TextBox },
+ { "insertPosition", "Function", TextButton },
+ { "insertPosition", "Function", TextToggle },
+ { "insertPosition", "Function", TopLevelShell },
+ { "insertPosition", "Function", TransientShell },
+ { "insertPosition", "Function", Tree },
+ { "insertPosition", "Function", Viewport },
+ { "insertPosition", "Function", WMShell },
+ { "insertPosition", "Function", XfwfCommon },
+ { "insertPosition", "Function", XfwfMenuBar },
+ { "insertPosition", "Int", AsciiText },
+ { "internalBorderColor", "Pixel", Paned },
+ { "internalBorderWidth", "Dimension", Paned },
+ { "internalHeight", "Dimension", Command },
+ { "internalHeight", "Dimension", Label },
+ { "internalHeight", "Dimension", List },
+ { "internalHeight", "Dimension", MenuButton },
+ { "internalHeight", "Dimension", Repeater },
+ { "internalHeight", "Dimension", Table },
+ { "internalHeight", "Dimension", Tabs },
+ { "internalHeight", "Dimension", Toggle },
+ { "internalSpace", "Dimension", Panner },
+ { "internalWidth", "Dimension", Command },
+ { "internalWidth", "Dimension", Label },
+ { "internalWidth", "Dimension", List },
+ { "internalWidth", "Dimension", MenuButton },
+ { "internalWidth", "Dimension", Repeater },
+ { "internalWidth", "Dimension", Table },
+ { "internalWidth", "Dimension", Tabs },
+ { "internalWidth", "Dimension", Toggle },
+ { "isIndex", "Boolean", HTML },
+ { "italicFont", "FontStruct", HTML },
+ { "jumpProc", "Callback", Scrollbar },
+ { "jumpScroll", "Int", StripChart },
+ { "justify", "Justify", Command },
+ { "justify", "Justify", Label },
+ { "justify", "Justify", MenuButton },
+ { "justify", "Justify", Repeater },
+ { "justify", "Justify", SmeBSB },
+ { "justify", "Justify", Table },
+ { "justify", "Justify", Toggle },
+ { "label", "String", Command },
+ { "label", "String", Dialog },
+ { "label", "String", Group },
+ { "label", "String", Label },
+ { "label", "String", MenuButton },
+ { "label", "String", RadioGroup },
+ { "label", "String", Repeater },
+ { "label", "String", SimpleMenu },
+ { "label", "String", Slider2d },
+ { "label", "String", SmeBSB },
+ { "label", "String", TextBox },
+ { "label", "String", TextButton },
+ { "label", "String", TextToggle },
+ { "label", "String", Toggle },
+ { "labelClass", "Pointer", SimpleMenu },
+ { "labelShadowWidth", "Dimension", Table },
+ { "labels", "StringArray", RadioGroup },
+ { "layout", "Layout", Layout },
+ { "leafPixmap", "Bitmap", ListTree },
+ { "leafOpenPixmap", "Bitmap", ListTree },
+ { "leafCallback", "Callback", ListTree },
+ { "left", "EdgeType", Dialog },
+ { "left", "EdgeType", Form },
+ { "left", "EdgeType", Viewport },
+ { "leftBitmap", "Bitmap", Command },
+ { "leftBitmap", "Bitmap", Label },
+ { "leftBitmap", "Bitmap", MenuButton },
+ { "leftBitmap", "Bitmap", Repeater },
+ { "leftBitmap", "Bitmap", SmeBSB },
+ { "leftBitmap", "Bitmap", Toggle },
+ { "leftCursor", "Cursor", Paned },
+ { "leftMargin", "Dimension", Slider2d },
+ { "leftMargin", "Dimension", SmeBSB },
+ { "leftMargin", "Dimension", TextBox },
+ { "leftMargin", "Dimension", TextButton },
+ { "leftMargin", "Dimension", TextToggle },
+ { "leftMargin", "Position", AsciiText },
+ { "length", "Dimension", Scrollbar },
+ { "length", "Int", AsciiSrc },
+ { "length", "Int", AsciiText },
+ { "lineWidth", "Dimension", Panner },
+ { "lineWidth", "Dimension", SmeLine },
+ { "lineWidth", "Dimension", Tree },
+ { "lineWidth", "Dimension", ListTree },
+ { "linkCallback", "Callback", HTML },
+ { "list", "Pointer", List },
+ { "list", "Pointer", MultiList },
+ { "listingFont", "FontStruct", HTML },
+ { "literal", "Boolean", Table },
+ { "literalWidth", "Int", Table },
+ { "location", "String", Arrow },
+ { "location", "String", Board },
+ { "location", "String", Group },
+ { "location", "String", Icon },
+ { "location", "String", RadioGroup },
+ { "location", "String", RowCol },
+ { "location", "String", Scrollbar2 },
+ { "location", "String", Slider2d },
+ { "location", "String", TextBox },
+ { "location", "String", TextButton },
+ { "location", "String", TextToggle },
+ { "location", "String", XfwfMenuBar },
+ { "longest", "Int", List },
+ { "longest", "Int", MultiList },
+ { "lowerCursor", "Cursor", Paned },
+ { "mappedWhenManaged", "Boolean", ApplicationShell },
+ { "mappedWhenManaged", "Boolean", Arrow },
+ { "mappedWhenManaged", "Boolean", AsciiText },
+ { "mappedWhenManaged", "Boolean", Board },
+ { "mappedWhenManaged", "Boolean", Box },
+ { "mappedWhenManaged", "Boolean", Command },
+ { "mappedWhenManaged", "Boolean", Core },
+ { "mappedWhenManaged", "Boolean", Dialog },
+ { "mappedWhenManaged", "Boolean", Form },
+ { "mappedWhenManaged", "Boolean", Frame },
+ { "mappedWhenManaged", "Boolean", Grip },
+ { "mappedWhenManaged", "Boolean", Group },
+ { "mappedWhenManaged", "Boolean", Gterm },
+ { "mappedWhenManaged", "Boolean", HTML },
+ { "mappedWhenManaged", "Boolean", Icon },
+ { "mappedWhenManaged", "Boolean", Label },
+ { "mappedWhenManaged", "Boolean", Layout },
+ { "mappedWhenManaged", "Boolean", List },
+ { "mappedWhenManaged", "Boolean", MenuButton },
+ { "mappedWhenManaged", "Boolean", MultiList },
+ { "mappedWhenManaged", "Boolean", OverrideShell },
+ { "mappedWhenManaged", "Boolean", Paned },
+ { "mappedWhenManaged", "Boolean", Panner },
+ { "mappedWhenManaged", "Boolean", Porthole },
+ { "mappedWhenManaged", "Boolean", RadioGroup },
+ { "mappedWhenManaged", "Boolean", Repeater },
+ { "mappedWhenManaged", "Boolean", RowCol },
+ { "mappedWhenManaged", "Boolean", Scrollbar },
+ { "mappedWhenManaged", "Boolean", Scrollbar2 },
+ { "mappedWhenManaged", "Boolean", Separator },
+ { "mappedWhenManaged", "Boolean", Shell },
+ { "mappedWhenManaged", "Boolean", Simple },
+ { "mappedWhenManaged", "Boolean", SimpleMenu },
+ { "mappedWhenManaged", "Boolean", Slider2d },
+ { "mappedWhenManaged", "Boolean", StripChart },
+ { "mappedWhenManaged", "Boolean", Table },
+ { "mappedWhenManaged", "Boolean", TextBox },
+ { "mappedWhenManaged", "Boolean", TextButton },
+ { "mappedWhenManaged", "Boolean", TextToggle },
+ { "mappedWhenManaged", "Boolean", Toggle },
+ { "mappedWhenManaged", "Boolean", TopLevelShell },
+ { "mappedWhenManaged", "Boolean", TransientShell },
+ { "mappedWhenManaged", "Boolean", Tree },
+ { "mappedWhenManaged", "Boolean", Viewport },
+ { "mappedWhenManaged", "Boolean", WMShell },
+ { "mappedWhenManaged", "Boolean", XfwfCommon },
+ { "mappedWhenManaged", "Boolean", XfwfMenuBar },
+ { "margin", "Dimension", ListTree },
+ { "marginHeight", "Dimension", HTML },
+ { "marginWidth", "Dimension", HTML },
+ { "markerBoxKnotColor", "Pixel", Gterm },
+ { "markerBoxKnotSize", "Int", Gterm },
+ { "markerBoxLineColor", "Pixel", Gterm },
+ { "markerCircleKnotColor", "Pixel", Gterm },
+ { "markerCircleKnotSize", "Int", Gterm },
+ { "markerCircleLineColor", "Pixel", Gterm },
+ { "markerCursorBgColor", "Pixel", Gterm },
+ { "markerCursorFgColor", "Pixel", Gterm },
+ { "markerEllipseKnotColor", "Pixel", Gterm },
+ { "markerEllipseKnotSize", "Int", Gterm },
+ { "markerEllipseLineColor", "Pixel", Gterm },
+ { "markerFill", "Boolean", Gterm },
+ { "markerFillBgColor", "Pixel", Gterm },
+ { "markerFillColor", "Pixel", Gterm },
+ { "markerFillStyle", "Int", Gterm },
+ { "markerHighlightColor", "Pixel", Gterm },
+ { "markerHighlightWidth", "Int", Gterm },
+ { "markerLineKnotColor", "Pixel", Gterm },
+ { "markerLineKnotSize", "Int", Gterm },
+ { "markerLineLineColor", "Pixel", Gterm },
+ { "markerLineStyle", "Int", Gterm },
+ { "markerLineWidth", "Int", Gterm },
+ { "markerPgonKnotColor", "Pixel", Gterm },
+ { "markerPgonKnotSize", "Int", Gterm },
+ { "markerPgonLineColor", "Pixel", Gterm },
+ { "markerRectKnotColor", "Pixel", Gterm },
+ { "markerRectKnotSize", "Int", Gterm },
+ { "markerRectLineColor", "Pixel", Gterm },
+ { "markerTextBgColor", "Pixel", Gterm },
+ { "markerTextBorder", "Int", Gterm },
+ { "markerTextColor", "Pixel", Gterm },
+ { "markerTextFont", "FontStruct", Gterm },
+ { "markerTextLineColor", "Pixel", Gterm },
+ { "markerTextString", "String", Gterm },
+ { "markerTranslations", "String", Gterm },
+ { "maskNumber", "Int", Table },
+ { "max", "Dimension", Paned },
+ { "maxAspectX", "Int", ApplicationShell },
+ { "maxAspectX", "Int", TopLevelShell },
+ { "maxAspectX", "Int", TransientShell },
+ { "maxAspectX", "Int", WMShell },
+ { "maxAspectY", "Int", ApplicationShell },
+ { "maxAspectY", "Int", TopLevelShell },
+ { "maxAspectY", "Int", TransientShell },
+ { "maxAspectY", "Int", WMShell },
+ { "maxColors", "Int", Gterm },
+ { "maxHeight", "Int", ApplicationShell },
+ { "maxHeight", "Int", TopLevelShell },
+ { "maxHeight", "Int", TransientShell },
+ { "maxHeight", "Int", WMShell },
+ { "maxMappings", "Int", Gterm },
+ { "maxRasters", "Int", Gterm },
+ { "maxSelectable", "Int", MultiList },
+ { "maxWidth", "Int", ApplicationShell },
+ { "maxWidth", "Int", TopLevelShell },
+ { "maxWidth", "Int", TransientShell },
+ { "maxWidth", "Int", WMShell },
+ { "menuName", "String", MenuButton },
+ { "menuOnScreen", "Boolean", SimpleMenu },
+ { "min", "Dimension", Paned },
+ { "minAspectX", "Int", ApplicationShell },
+ { "minAspectX", "Int", TopLevelShell },
+ { "minAspectX", "Int", TransientShell },
+ { "minAspectX", "Int", WMShell },
+ { "minAspectY", "Int", ApplicationShell },
+ { "minAspectY", "Int", TopLevelShell },
+ { "minAspectY", "Int", TransientShell },
+ { "minAspectY", "Int", WMShell },
+ { "minHeight", "Int", ApplicationShell },
+ { "minHeight", "Int", TopLevelShell },
+ { "minHeight", "Int", TransientShell },
+ { "minHeight", "Int", WMShell },
+ { "minScale", "Int", StripChart },
+ { "minWidth", "Int", ApplicationShell },
+ { "minWidth", "Int", TopLevelShell },
+ { "minWidth", "Int", TransientShell },
+ { "minWidth", "Int", WMShell },
+ { "minimumDelay", "Int", Repeater },
+ { "minimumThumb", "Dimension", Scrollbar },
+ { "minsize", "Dimension", Scrollbar2 },
+ { "minsize", "Dimension", Slider2d },
+ { "nearEdge", "Int", Gterm },
+ { "nearVertex", "Int", Gterm },
+ { "nextTop", "Callback", Arrow },
+ { "nextTop", "Callback", Board },
+ { "nextTop", "Callback", Frame },
+ { "nextTop", "Callback", Group },
+ { "nextTop", "Callback", Icon },
+ { "nextTop", "Callback", RadioGroup },
+ { "nextTop", "Callback", RowCol },
+ { "nextTop", "Callback", Scrollbar2 },
+ { "nextTop", "Callback", Slider2d },
+ { "nextTop", "Callback", TextBox },
+ { "nextTop", "Callback", TextButton },
+ { "nextTop", "Callback", TextToggle },
+ { "nextTop", "Callback", XfwfCommon },
+ { "nextTop", "Callback", XfwfMenuBar },
+ { "numChildren", "Cardinal", ApplicationShell },
+ { "numChildren", "Cardinal", Arrow },
+ { "numChildren", "Cardinal", Board },
+ { "numChildren", "Cardinal", Box },
+ { "numChildren", "Cardinal", Dialog },
+ { "numChildren", "Cardinal", Form },
+ { "numChildren", "Cardinal", Frame },
+ { "numChildren", "Cardinal", Group },
+ { "numChildren", "Cardinal", HTML },
+ { "numChildren", "Cardinal", Icon },
+ { "numChildren", "Cardinal", Layout },
+ { "numChildren", "Cardinal", OverrideShell },
+ { "numChildren", "Cardinal", Paned },
+ { "numChildren", "Cardinal", Porthole },
+ { "numChildren", "Cardinal", RadioGroup },
+ { "numChildren", "Cardinal", RowCol },
+ { "numChildren", "Cardinal", Scrollbar2 },
+ { "numChildren", "Cardinal", Shell },
+ { "numChildren", "Cardinal", SimpleMenu },
+ { "numChildren", "Cardinal", Slider2d },
+ { "numChildren", "Cardinal", TextBox },
+ { "numChildren", "Cardinal", TextButton },
+ { "numChildren", "Cardinal", TextToggle },
+ { "numChildren", "Cardinal", TopLevelShell },
+ { "numChildren", "Cardinal", TransientShell },
+ { "numChildren", "Cardinal", Table },
+ { "numChildren", "Cardinal", Tree },
+ { "numChildren", "Cardinal", Viewport },
+ { "numChildren", "Cardinal", WMShell },
+ { "numChildren", "Cardinal", XfwfCommon },
+ { "numChildren", "Cardinal", XfwfMenuBar },
+ { "numberStrings", "Int", List },
+ { "numberStrings", "Int", MultiList },
+ { "offCallback", "Callback", TextToggle },
+ { "offIcon", "Icon", TextToggle },
+ { "on", "Boolean", TextToggle },
+ { "onCallback", "Callback", TextToggle },
+ { "onIcon", "Icon", TextToggle },
+ { "orientation", "Orientation", Box },
+ { "orientation", "Orientation", Paned },
+ { "orientation", "Orientation", Scrollbar },
+ { "outerOffset", "Dimension", Arrow },
+ { "outerOffset", "Dimension", Board },
+ { "outerOffset", "Dimension", Frame },
+ { "outerOffset", "Dimension", Group },
+ { "outerOffset", "Dimension", Icon },
+ { "outerOffset", "Dimension", RadioGroup },
+ { "outerOffset", "Dimension", RowCol },
+ { "outerOffset", "Dimension", Scrollbar2 },
+ { "outerOffset", "Dimension", Slider2d },
+ { "outerOffset", "Dimension", TextBox },
+ { "outerOffset", "Dimension", TextButton },
+ { "outerOffset", "Dimension", TextToggle },
+ { "outerOffset", "Dimension", XfwfMenuBar },
+ { "overrideRedirect", "Boolean", ApplicationShell },
+ { "overrideRedirect", "Boolean", OverrideShell },
+ { "overrideRedirect", "Boolean", Shell },
+ { "overrideRedirect", "Boolean", SimpleMenu },
+ { "overrideRedirect", "Boolean", TopLevelShell },
+ { "overrideRedirect", "Boolean", TransientShell },
+ { "overrideRedirect", "Boolean", WMShell },
+ { "pathCallback", "Callback", ListTree },
+ { "pasteBuffer", "Boolean", List },
+ { "pasteBuffer", "Boolean", MultiList },
+ { "percentVerticalSpace", "Int", HTML },
+ { "pickTop", "Boolean", Scrollbar },
+ { "pieceSize", "Int", AsciiSrc },
+ { "pieceSize", "Int", AsciiText },
+ { "plainFont", "FontStruct", HTML },
+ { "plainboldFont", "FontStruct", HTML },
+ { "plainitalicFont", "FontStruct", HTML },
+ { "pointerColor", "Pixel", AsciiText },
+ { "pointerColor", "Pixel", Command },
+ { "pointerColor", "Pixel", Grip },
+ { "pointerColor", "Pixel", Label },
+ { "pointerColor", "Pixel", List },
+ { "pointerColor", "Pixel", MenuButton },
+ { "pointerColor", "Pixel", MultiList },
+ { "pointerColor", "Pixel", Panner },
+ { "pointerColor", "Pixel", Repeater },
+ { "pointerColor", "Pixel", Scrollbar },
+ { "pointerColor", "Pixel", Simple },
+ { "pointerColor", "Pixel", StripChart },
+ { "pointerColor", "Pixel", Toggle },
+ { "pointerColorBackground", "Pixel", AsciiText },
+ { "pointerColorBackground", "Pixel", Command },
+ { "pointerColorBackground", "Pixel", Grip },
+ { "pointerColorBackground", "Pixel", Label },
+ { "pointerColorBackground", "Pixel", List },
+ { "pointerColorBackground", "Pixel", MenuButton },
+ { "pointerColorBackground", "Pixel", MultiList },
+ { "pointerColorBackground", "Pixel", Panner },
+ { "pointerColorBackground", "Pixel", Repeater },
+ { "pointerColorBackground", "Pixel", Scrollbar },
+ { "pointerColorBackground", "Pixel", Simple },
+ { "pointerColorBackground", "Pixel", StripChart },
+ { "pointerColorBackground", "Pixel", Toggle },
+ { "pointerMotionCallback", "Pointer", HTML },
+ { "popdownCallback", "Callback", ApplicationShell },
+ { "popdownCallback", "Callback", OverrideShell },
+ { "popdownCallback", "Callback", Shell },
+ { "popdownCallback", "Callback", SimpleMenu },
+ { "popdownCallback", "Callback", Tabs },
+ { "popdownCallback", "Callback", TopLevelShell },
+ { "popdownCallback", "Callback", TransientShell },
+ { "popdownCallback", "Callback", WMShell },
+ { "popupCallback", "Callback", ApplicationShell },
+ { "popupCallback", "Callback", OverrideShell },
+ { "popupCallback", "Callback", Shell },
+ { "popupCallback", "Callback", SimpleMenu },
+ { "popupCallback", "Callback", Tabs },
+ { "popupCallback", "Callback", TopLevelShell },
+ { "popupCallback", "Callback", TransientShell },
+ { "popupCallback", "Callback", WMShell },
+ { "popupOnEntry", "Widget", SimpleMenu },
+ { "position", "Int", Paned },
+ { "preferredPaneSize", "Dimension", Paned },
+ { "previouslyVisitedTestFunction", "Pointer", HTML },
+ { "radioData", "Pointer", Toggle },
+ { "radioGroup", "Widget", Toggle },
+ { "raiseWindow", "Boolean", Gterm },
+ { "refigureMode", "Boolean", Paned },
+ { "rel_height", "Float", Arrow },
+ { "rel_height", "Float", Board },
+ { "rel_height", "Float", Group },
+ { "rel_height", "Float", Icon },
+ { "rel_height", "Float", RadioGroup },
+ { "rel_height", "Float", RowCol },
+ { "rel_height", "Float", Scrollbar2 },
+ { "rel_height", "Float", Slider2d },
+ { "rel_height", "Float", TextBox },
+ { "rel_height", "Float", TextButton },
+ { "rel_height", "Float", TextToggle },
+ { "rel_height", "Float", XfwfMenuBar },
+ { "rel_width", "Float", Arrow },
+ { "rel_width", "Float", Board },
+ { "rel_width", "Float", Group },
+ { "rel_width", "Float", Icon },
+ { "rel_width", "Float", RadioGroup },
+ { "rel_width", "Float", RowCol },
+ { "rel_width", "Float", Scrollbar2 },
+ { "rel_width", "Float", Slider2d },
+ { "rel_width", "Float", TextBox },
+ { "rel_width", "Float", TextButton },
+ { "rel_width", "Float", TextToggle },
+ { "rel_width", "Float", XfwfMenuBar },
+ { "rel_x", "Float", Arrow },
+ { "rel_x", "Float", Board },
+ { "rel_x", "Float", Group },
+ { "rel_x", "Float", Icon },
+ { "rel_x", "Float", RadioGroup },
+ { "rel_x", "Float", RowCol },
+ { "rel_x", "Float", Scrollbar2 },
+ { "rel_x", "Float", Slider2d },
+ { "rel_x", "Float", TextBox },
+ { "rel_x", "Float", TextButton },
+ { "rel_x", "Float", TextToggle },
+ { "rel_x", "Float", XfwfMenuBar },
+ { "rel_y", "Float", Arrow },
+ { "rel_y", "Float", Board },
+ { "rel_y", "Float", Group },
+ { "rel_y", "Float", Icon },
+ { "rel_y", "Float", RadioGroup },
+ { "rel_y", "Float", RowCol },
+ { "rel_y", "Float", Scrollbar2 },
+ { "rel_y", "Float", Slider2d },
+ { "rel_y", "Float", TextBox },
+ { "rel_y", "Float", TextButton },
+ { "rel_y", "Float", TextToggle },
+ { "rel_y", "Float", XfwfMenuBar },
+ { "repeatDelay", "Cardinal", Arrow },
+ { "repeatDelay", "Cardinal", Scrollbar2 },
+ { "repeatDelay", "Int", Repeater },
+ { "reportCallback", "Callback", Panner },
+ { "reportCallback", "Callback", Porthole },
+ { "reportCallback", "Callback", Viewport },
+ { "resizable", "Boolean", Dialog },
+ { "resizable", "Boolean", Form },
+ { "resizable", "Boolean", Tabs },
+ { "resizable", "Boolean", Viewport },
+ { "resize", "Boolean", Command },
+ { "resize", "Boolean", Label },
+ { "resize", "Boolean", MenuButton },
+ { "resize", "Boolean", Panner },
+ { "resize", "Boolean", Repeater },
+ { "resize", "Boolean", Toggle },
+ { "resize", "ResizeMode", AsciiText },
+ { "resizeToPreferred", "Boolean", Paned },
+ { "resolveDelayedImage", "Pointer", HTML },
+ { "resolveImageFunction", "Pointer", HTML },
+ { "right", "EdgeType", Dialog },
+ { "right", "EdgeType", Form },
+ { "right", "EdgeType", Viewport },
+ { "rightBitmap", "Bitmap", SmeBSB },
+ { "rightCursor", "Cursor", Paned },
+ { "rightMargin", "Dimension", Slider2d },
+ { "rightMargin", "Dimension", SmeBSB },
+ { "rightMargin", "Dimension", TextBox },
+ { "rightMargin", "Dimension", TextButton },
+ { "rightMargin", "Dimension", TextToggle },
+ { "rightMargin", "Position", AsciiText },
+ { "rowForeground", "Pixel", Table },
+ { "rowHeight", "Dimension", MultiList },
+ { "rowHeight", "Dimension", SimpleMenu },
+ { "rowHeight", "Int", Table },
+ { "rowOriented", "Boolean", Table },
+ { "rowMargin", "Dimension", Table },
+ { "rowSpacing", "Dimension", List },
+ { "rowSpacing", "Dimension", MultiList },
+ { "rows", "Int", Group },
+ { "rows", "Int", RadioGroup },
+ { "rows", "Int", RowCol },
+ { "rows", "Int", Table },
+ { "rows", "Int", XfwfMenuBar },
+ { "rubberBand", "Boolean", Panner },
+ { "rvLength", "Int", Slider2d },
+ { "rvLength", "Int", TextBox },
+ { "rvLength", "Int", TextButton },
+ { "rvLength", "Int", TextToggle },
+ { "rvStart", "Int", Slider2d },
+ { "rvStart", "Int", TextBox },
+ { "rvStart", "Int", TextButton },
+ { "rvStart", "Int", TextToggle },
+ { "saveUnder", "Boolean", ApplicationShell },
+ { "saveUnder", "Boolean", OverrideShell },
+ { "saveUnder", "Boolean", Shell },
+ { "saveUnder", "Boolean", SimpleMenu },
+ { "saveUnder", "Boolean", TopLevelShell },
+ { "saveUnder", "Boolean", TransientShell },
+ { "saveUnder", "Boolean", WMShell },
+ { "screen", "Screen", ApplicationShell },
+ { "screen", "Screen", Arrow },
+ { "screen", "Screen", AsciiText },
+ { "screen", "Screen", Board },
+ { "screen", "Screen", Box },
+ { "screen", "Screen", Command },
+ { "screen", "Screen", Core },
+ { "screen", "Screen", Dialog },
+ { "screen", "Screen", Form },
+ { "screen", "Screen", Frame },
+ { "screen", "Screen", Grip },
+ { "screen", "Screen", Group },
+ { "screen", "Screen", Gterm },
+ { "screen", "Screen", HTML },
+ { "screen", "Screen", Icon },
+ { "screen", "Screen", Label },
+ { "screen", "Screen", Layout },
+ { "screen", "Screen", List },
+ { "screen", "Screen", MenuButton },
+ { "screen", "Screen", MultiList },
+ { "screen", "Screen", OverrideShell },
+ { "screen", "Screen", Paned },
+ { "screen", "Screen", Panner },
+ { "screen", "Screen", Porthole },
+ { "screen", "Screen", RadioGroup },
+ { "screen", "Screen", Repeater },
+ { "screen", "Screen", RowCol },
+ { "screen", "Screen", Scrollbar },
+ { "screen", "Screen", Scrollbar2 },
+ { "screen", "Screen", Shell },
+ { "screen", "Screen", Simple },
+ { "screen", "Screen", SimpleMenu },
+ { "screen", "Screen", Slider2d },
+ { "screen", "Screen", StripChart },
+ { "screen", "Screen", Table },
+ { "screen", "Screen", TextBox },
+ { "screen", "Screen", TextButton },
+ { "screen", "Screen", TextToggle },
+ { "screen", "Screen", Toggle },
+ { "screen", "Screen", TopLevelShell },
+ { "screen", "Screen", TransientShell },
+ { "screen", "Screen", Tree },
+ { "screen", "Screen", Viewport },
+ { "screen", "Screen", WMShell },
+ { "screen", "Screen", XfwfCommon },
+ { "screen", "Screen", XfwfMenuBar },
+ { "scrollCallback", "Callback", Scrollbar2 },
+ { "scrollCallback", "Callback", Slider2d },
+ { "scrollDCursor", "Cursor", Scrollbar },
+ { "scrollHCursor", "Cursor", Scrollbar },
+ { "scrollHorizontal", "ScrollMode", AsciiText },
+ { "scrollLCursor", "Cursor", Scrollbar },
+ { "scrollProc", "Callback", Scrollbar },
+ { "scrollRCursor", "Cursor", Scrollbar },
+ { "scrollResponse", "XTCallbackProc", Scrollbar2 },
+ { "scrollResponse", "XTCallbackProc", Slider2d },
+ { "scrollUCursor", "Cursor", Scrollbar },
+ { "scrollVCursor", "Cursor", Scrollbar },
+ { "scrollVertical", "ScrollMode", AsciiText },
+ { "scrollbarForeground", "Pixel", Scrollbar2 },
+ { "selectTypes", "Pointer", AsciiText },
+ { "selectInsensitive", "Boolean", Tabs },
+ { "selection", "Long", Group },
+ { "selection", "Long", RadioGroup },
+ { "selectionStyle", "SelectionType", Group },
+ { "selectionStyle", "SelectionType", RadioGroup },
+ { "sensitive", "Boolean", ApplicationShell },
+ { "sensitive", "Boolean", Arrow },
+ { "sensitive", "Boolean", AsciiText },
+ { "sensitive", "Boolean", Board },
+ { "sensitive", "Boolean", Box },
+ { "sensitive", "Boolean", Command },
+ { "sensitive", "Boolean", Core },
+ { "sensitive", "Boolean", Dialog },
+ { "sensitive", "Boolean", Form },
+ { "sensitive", "Boolean", Frame },
+ { "sensitive", "Boolean", Grip },
+ { "sensitive", "Boolean", Group },
+ { "sensitive", "Boolean", Gterm },
+ { "sensitive", "Boolean", HTML },
+ { "sensitive", "Boolean", Icon },
+ { "sensitive", "Boolean", Label },
+ { "sensitive", "Boolean", Layout },
+ { "sensitive", "Boolean", List },
+ { "sensitive", "Boolean", MenuButton },
+ { "sensitive", "Boolean", MultiList },
+ { "sensitive", "Boolean", OverrideShell },
+ { "sensitive", "Boolean", Paned },
+ { "sensitive", "Boolean", Panner },
+ { "sensitive", "Boolean", Porthole },
+ { "sensitive", "Boolean", RadioGroup },
+ { "sensitive", "Boolean", Repeater },
+ { "sensitive", "Boolean", RowCol },
+ { "sensitive", "Boolean", Scrollbar },
+ { "sensitive", "Boolean", Scrollbar2 },
+ { "sensitive", "Boolean", Shell },
+ { "sensitive", "Boolean", Simple },
+ { "sensitive", "Boolean", SimpleMenu },
+ { "sensitive", "Boolean", Slider2d },
+ { "sensitive", "Boolean", Sme },
+ { "sensitive", "Boolean", SmeBSB },
+ { "sensitive", "Boolean", SmeLine },
+ { "sensitive", "Boolean", StripChart },
+ { "sensitive", "Boolean", Table },
+ { "sensitive", "Boolean", TextBox },
+ { "sensitive", "Boolean", TextButton },
+ { "sensitive", "Boolean", TextToggle },
+ { "sensitive", "Boolean", Toggle },
+ { "sensitive", "Boolean", TopLevelShell },
+ { "sensitive", "Boolean", TransientShell },
+ { "sensitive", "Boolean", Tree },
+ { "sensitive", "Boolean", Viewport },
+ { "sensitive", "Boolean", WMShell },
+ { "sensitive", "Boolean", XfwfCommon },
+ { "sensitive", "Boolean", XfwfMenuBar },
+ { "sensitiveArray", "Pointer", MultiList },
+ { "shadeSurplus", "Boolean", MultiList },
+ { "shadow", "Dimension", Scrollbar2 },
+ { "shadowColor", "Pixel", Panner },
+ { "shadowScheme", "ShadowScheme", Arrow },
+ { "shadowScheme", "ShadowScheme", Board },
+ { "shadowScheme", "ShadowScheme", Frame },
+ { "shadowScheme", "ShadowScheme", Group },
+ { "shadowScheme", "ShadowScheme", Icon },
+ { "shadowScheme", "ShadowScheme", RadioGroup },
+ { "shadowScheme", "ShadowScheme", RowCol },
+ { "shadowScheme", "ShadowScheme", Scrollbar2 },
+ { "shadowScheme", "ShadowScheme", Slider2d },
+ { "shadowScheme", "ShadowScheme", TextBox },
+ { "shadowScheme", "ShadowScheme", TextButton },
+ { "shadowScheme", "ShadowScheme", TextToggle },
+ { "shadowScheme", "ShadowScheme", XfwfMenuBar },
+ { "shadowThickness", "Dimension", Panner },
+ { "shadowWidth", "Dimension", Table },
+ { "shapeStyle", "ShapeStyle", Command },
+ { "shapeStyle", "ShapeStyle", MenuButton },
+ { "shapeStyle", "ShapeStyle", Repeater },
+ { "shapeStyle", "ShapeStyle", Toggle },
+ { "showGrip", "Boolean", Paned },
+ { "shown", "Float", Scrollbar },
+ { "shrinkToFit", "Boolean", Group },
+ { "shrinkToFit", "Boolean", RadioGroup },
+ { "shrinkToFit", "Boolean", RowCol },
+ { "shrinkToFit", "Boolean", Slider2d },
+ { "shrinkToFit", "Boolean", TextBox },
+ { "shrinkToFit", "Boolean", TextButton },
+ { "shrinkToFit", "Boolean", TextToggle },
+ { "shrinkToFit", "Boolean", XfwfMenuBar },
+ { "skipAdjust", "Boolean", Paned },
+ { "sliderHeight", "Dimension", Panner },
+ { "sliderWidth", "Dimension", Panner },
+ { "sliderX", "Position", Panner },
+ { "sliderY", "Position", Panner },
+ { "startCallback", "Callback", Repeater },
+ { "state", "Boolean", Toggle },
+ { "stipple", "Bitmap", SmeLine },
+ { "stopCallback", "Callback", Repeater },
+ { "storeByRow", "Boolean", Group },
+ { "storeByRow", "Boolean", RadioGroup },
+ { "storeByRow", "Boolean", RowCol },
+ { "storeByRow", "Boolean", XfwfMenuBar },
+ { "string", "String", AsciiSrc },
+ { "string", "String", AsciiText },
+ { "submitFormCallback", "Callback", HTML },
+ { "tabForeground", "Pixel", Tabs },
+ { "tabLabel", "String", Tabs },
+ { "tableMargin", "Dimension", Table },
+ { "tabLeftBitmap", "Bitmap", Tabs },
+ { "tablist", "String", MultiList },
+ { "tablist", "String", Slider2d },
+ { "tablist", "String", TextBox },
+ { "tablist", "String", TextButton },
+ { "tablist", "String", TextToggle },
+ { "text", "String", HTML },
+ { "textSink", "Widget", AsciiText },
+ { "textSource", "Widget", AsciiText },
+ { "thickness", "Dimension", Scrollbar },
+ { "thumb", "Bitmap", Scrollbar },
+ { "thumbColor", "Pixel", Slider2d },
+ { "thumbFrameType", "FrameType", Slider2d },
+ { "thumbFrameWidth", "Dimension", Slider2d },
+ { "thumbPixmap", "Pixmap", Slider2d },
+ { "thumbProc", "Callback", Scrollbar },
+ { "title", "String", ApplicationShell },
+ { "title", "String", TopLevelShell },
+ { "title", "String", TransientShell },
+ { "title", "String", WMShell },
+ { "titleEncoding", "Atom", ApplicationShell },
+ { "titleEncoding", "Atom", TopLevelShell },
+ { "titleEncoding", "Atom", TransientShell },
+ { "titleEncoding", "Atom", WMShell },
+ { "titleText", "String", HTML },
+ { "top", "EdgeType", Dialog },
+ { "top", "EdgeType", Form },
+ { "top", "EdgeType", Viewport },
+ { "topMargin", "Dimension", SimpleMenu },
+ { "topMargin", "Dimension", Slider2d },
+ { "topMargin", "Dimension", TextBox },
+ { "topMargin", "Dimension", TextButton },
+ { "topMargin", "Dimension", TextToggle },
+ { "topMargin", "Position", AsciiText },
+ { "topOfThumb", "Float", Scrollbar },
+ { "topShadowColor", "Pixel", Arrow },
+ { "topShadowColor", "Pixel", Board },
+ { "topShadowColor", "Pixel", Frame },
+ { "topShadowColor", "Pixel", Group },
+ { "topShadowColor", "Pixel", Icon },
+ { "topShadowColor", "Pixel", RadioGroup },
+ { "topShadowColor", "Pixel", RowCol },
+ { "topShadowColor", "Pixel", Scrollbar2 },
+ { "topShadowColor", "Pixel", Slider2d },
+ { "topShadowColor", "Pixel", TextBox },
+ { "topShadowColor", "Pixel", TextButton },
+ { "topShadowColor", "Pixel", TextToggle },
+ { "topShadowColor", "Pixel", XfwfMenuBar },
+ { "topShadowPixel", "Pixel", Table },
+ { "topShadowPixmap", "Pixmap", Table },
+ { "topShadowContast", "Int", Tabs },
+ { "topShadowStipple", "Bitmap", Arrow },
+ { "topShadowStipple", "Bitmap", Board },
+ { "topShadowStipple", "Bitmap", Frame },
+ { "topShadowStipple", "Bitmap", Group },
+ { "topShadowStipple", "Bitmap", Icon },
+ { "topShadowStipple", "Bitmap", RadioGroup },
+ { "topShadowStipple", "Bitmap", RowCol },
+ { "topShadowStipple", "Bitmap", Scrollbar2 },
+ { "topShadowStipple", "Bitmap", Slider2d },
+ { "topShadowStipple", "Bitmap", TextBox },
+ { "topShadowStipple", "Bitmap", TextButton },
+ { "topShadowStipple", "Bitmap", TextToggle },
+ { "topShadowStipple", "Bitmap", XfwfMenuBar },
+ { "topWidget", "Widget", Tabs },
+ { "transient", "Boolean", ApplicationShell },
+ { "transient", "Boolean", TopLevelShell },
+ { "transient", "Boolean", TransientShell },
+ { "transient", "Boolean", WMShell },
+ { "transientFor", "Widget", TransientShell },
+ { "translations", "TranslationTable", ApplicationShell },
+ { "translations", "TranslationTable", Arrow },
+ { "translations", "TranslationTable", AsciiText },
+ { "translations", "TranslationTable", Board },
+ { "translations", "TranslationTable", Box },
+ { "translations", "TranslationTable", Command },
+ { "translations", "TranslationTable", Core },
+ { "translations", "TranslationTable", Dialog },
+ { "translations", "TranslationTable", Form },
+ { "translations", "TranslationTable", Frame },
+ { "translations", "TranslationTable", Grip },
+ { "translations", "TranslationTable", Group },
+ { "translations", "TranslationTable", Gterm },
+ { "translations", "TranslationTable", HTML },
+ { "translations", "TranslationTable", Icon },
+ { "translations", "TranslationTable", Label },
+ { "translations", "TranslationTable", Layout },
+ { "translations", "TranslationTable", List },
+ { "translations", "TranslationTable", MenuButton },
+ { "translations", "TranslationTable", MultiList },
+ { "translations", "TranslationTable", OverrideShell },
+ { "translations", "TranslationTable", Paned },
+ { "translations", "TranslationTable", Panner },
+ { "translations", "TranslationTable", Porthole },
+ { "translations", "TranslationTable", RadioGroup },
+ { "translations", "TranslationTable", Repeater },
+ { "translations", "TranslationTable", RowCol },
+ { "translations", "TranslationTable", Scrollbar },
+ { "translations", "TranslationTable", Scrollbar2 },
+ { "translations", "TranslationTable", Shell },
+ { "translations", "TranslationTable", Simple },
+ { "translations", "TranslationTable", SimpleMenu },
+ { "translations", "TranslationTable", Slider2d },
+ { "translations", "TranslationTable", StripChart },
+ { "translations", "TranslationTable", Table },
+ { "translations", "TranslationTable", TextBox },
+ { "translations", "TranslationTable", TextButton },
+ { "translations", "TranslationTable", TextToggle },
+ { "translations", "TranslationTable", Toggle },
+ { "translations", "TranslationTable", TopLevelShell },
+ { "translations", "TranslationTable", TransientShell },
+ { "translations", "TranslationTable", Tree },
+ { "translations", "TranslationTable", Viewport },
+ { "translations", "TranslationTable", WMShell },
+ { "translations", "TranslationTable", XfwfCommon },
+ { "translations", "TranslationTable", XfwfMenuBar },
+ { "traversalOn", "Boolean", Arrow },
+ { "traversalOn", "Boolean", Board },
+ { "traversalOn", "Boolean", Frame },
+ { "traversalOn", "Boolean", Group },
+ { "traversalOn", "Boolean", Icon },
+ { "traversalOn", "Boolean", RadioGroup },
+ { "traversalOn", "Boolean", RowCol },
+ { "traversalOn", "Boolean", Scrollbar2 },
+ { "traversalOn", "Boolean", Slider2d },
+ { "traversalOn", "Boolean", TextBox },
+ { "traversalOn", "Boolean", TextButton },
+ { "traversalOn", "Boolean", TextToggle },
+ { "traversalOn", "Boolean", XfwfCommon },
+ { "traversalOn", "Boolean", XfwfMenuBar },
+ { "treeGC", "GC", Tree },
+ { "treeParent", "Widget", Tree },
+ { "type", "AsciiType", AsciiSrc },
+ { "type", "AsciiType", AsciiText },
+ { "unrealizeCallback", "Callback", AsciiText },
+ { "update", "Int", StripChart },
+ { "upperCursor", "Cursor", Paned },
+ { "useBottom", "Boolean", Viewport },
+ { "useRight", "Boolean", Viewport },
+ { "useStringInPlace", "Boolean", AsciiSrc },
+ { "useStringInPlace", "Boolean", AsciiText },
+ { "useTimers", "Boolean", Gterm },
+ { "userData", "Pointer", Arrow },
+ { "userData", "Pointer", Board },
+ { "userData", "Pointer", Frame },
+ { "userData", "Pointer", Group },
+ { "userData", "Pointer", Icon },
+ { "userData", "Pointer", RadioGroup },
+ { "userData", "Pointer", Repeater },
+ { "userData", "Pointer", RowCol },
+ { "userData", "Pointer", Scrollbar2 },
+ { "userData", "Pointer", Slider2d },
+ { "userData", "Pointer", TextBox },
+ { "userData", "Pointer", TextButton },
+ { "userData", "Pointer", TextToggle },
+ { "userData", "Pointer", XfwfCommon },
+ { "userData", "Pointer", XfwfMenuBar },
+ { "userData", "Pixmap", Table },
+ { "vSpace", "Dimension", Box },
+ { "vSpace", "Dimension", Tree },
+ { "value", "String", Dialog },
+ { "vertDistance", "Int", Dialog },
+ { "vertDistance", "Int", Form },
+ { "vertDistance", "Int", Viewport },
+ { "vertSpace", "Int", SmeBSB },
+ { "vertical", "Boolean", Scrollbar2 },
+ { "verticalBetweenCursor", "Cursor", Paned },
+ { "verticalGripCursor", "Cursor", Paned },
+ { "verticalList", "Boolean", List },
+ { "verticalList", "Boolean", MultiList },
+ { "verticalScroll", "Widget", Table },
+ { "verticalScrollBar", "Widget", HTML },
+ { "verticalScrollOnRight", "Boolean", HTML },
+ { "verticalSpacing", "Dimension", ListTree },
+ { "view", "Widget", HTML },
+ { "visitedAnchorColor", "Pixel", HTML },
+ { "visitedAnchorUnderlines", "Int", HTML },
+ { "visual", "Visual", ApplicationShell },
+ { "visual", "Visual", OverrideShell },
+ { "visual", "Visual", Shell },
+ { "visual", "Visual", SimpleMenu },
+ { "visual", "Visual", TopLevelShell },
+ { "visual", "Visual", TransientShell },
+ { "visual", "Visual", WMShell },
+ { "vunit", "Float", Arrow },
+ { "vunit", "Float", Board },
+ { "vunit", "Float", Group },
+ { "vunit", "Float", Icon },
+ { "vunit", "Float", RadioGroup },
+ { "vunit", "Float", RowCol },
+ { "vunit", "Float", Scrollbar2 },
+ { "vunit", "Float", Slider2d },
+ { "vunit", "Float", TextBox },
+ { "vunit", "Float", TextButton },
+ { "vunit", "Float", TextToggle },
+ { "vunit", "Float", XfwfMenuBar },
+ { "waitforwm", "Boolean", ApplicationShell },
+ { "waitforwm", "Boolean", TopLevelShell },
+ { "waitforwm", "Boolean", TransientShell },
+ { "waitforwm", "Boolean", WMShell },
+ { "warpCursor", "Boolean", Gterm },
+ { "whatCell", "Callback", Table },
+ { "width", "Dimension", ApplicationShell },
+ { "width", "Dimension", Arrow },
+ { "width", "Dimension", AsciiText },
+ { "width", "Dimension", Board },
+ { "width", "Dimension", Box },
+ { "width", "Dimension", Command },
+ { "width", "Dimension", Core },
+ { "width", "Dimension", Dialog },
+ { "width", "Dimension", Form },
+ { "width", "Dimension", Frame },
+ { "width", "Dimension", Grip },
+ { "width", "Dimension", Group },
+ { "width", "Dimension", Gterm },
+ { "width", "Dimension", HTML },
+ { "width", "Dimension", Icon },
+ { "width", "Dimension", Label },
+ { "width", "Dimension", Layout },
+ { "width", "Dimension", List },
+ { "width", "Dimension", MenuButton },
+ { "width", "Dimension", MultiList },
+ { "width", "Dimension", OverrideShell },
+ { "width", "Dimension", Paned },
+ { "width", "Dimension", Panner },
+ { "width", "Dimension", Porthole },
+ { "width", "Dimension", RadioGroup },
+ { "width", "Dimension", Repeater },
+ { "width", "Dimension", RowCol },
+ { "width", "Dimension", Scrollbar },
+ { "width", "Dimension", Scrollbar2 },
+ { "width", "Dimension", Separator },
+ { "width", "Dimension", Shell },
+ { "width", "Dimension", Simple },
+ { "width", "Dimension", SimpleMenu },
+ { "width", "Dimension", Slider2d },
+ { "width", "Dimension", Sme },
+ { "width", "Dimension", SmeBSB },
+ { "width", "Dimension", SmeLine },
+ { "width", "Dimension", StripChart },
+ { "width", "Dimension", Table },
+ { "width", "Dimension", TextBox },
+ { "width", "Dimension", TextButton },
+ { "width", "Dimension", TextToggle },
+ { "width", "Dimension", Toggle },
+ { "width", "Dimension", TopLevelShell },
+ { "width", "Dimension", TransientShell },
+ { "width", "Dimension", Tree },
+ { "width", "Dimension", Viewport },
+ { "width", "Dimension", WMShell },
+ { "width", "Dimension", XfwfCommon },
+ { "width", "Dimension", XfwfMenuBar },
+ { "widthInc", "Int", ApplicationShell },
+ { "widthInc", "Int", TopLevelShell },
+ { "widthInc", "Int", TransientShell },
+ { "widthInc", "Int", WMShell },
+ { "winGravity", "Int", ApplicationShell },
+ { "winGravity", "Int", TopLevelShell },
+ { "winGravity", "Int", TransientShell },
+ { "winGravity", "Int", WMShell },
+ { "windowGroup", "Window", ApplicationShell },
+ { "windowGroup", "Window", TopLevelShell },
+ { "windowGroup", "Window", TransientShell },
+ { "windowGroup", "Window", WMShell },
+ { "wmTimeout", "Int", ApplicationShell },
+ { "wmTimeout", "Int", TopLevelShell },
+ { "wmTimeout", "Int", TransientShell },
+ { "wmTimeout", "Int", WMShell },
+ { "wrap", "WrapMode", AsciiText },
+ { "x", "Position", ApplicationShell },
+ { "x", "Position", Arrow },
+ { "x", "Position", AsciiText },
+ { "x", "Position", Board },
+ { "x", "Position", Box },
+ { "x", "Position", Command },
+ { "x", "Position", Core },
+ { "x", "Position", Dialog },
+ { "x", "Position", Form },
+ { "x", "Position", Frame },
+ { "x", "Position", Grip },
+ { "x", "Position", Group },
+ { "x", "Position", Gterm },
+ { "x", "Position", HTML },
+ { "x", "Position", Icon },
+ { "x", "Position", Label },
+ { "x", "Position", Layout },
+ { "x", "Position", List },
+ { "x", "Position", MenuButton },
+ { "x", "Position", MultiList },
+ { "x", "Position", OverrideShell },
+ { "x", "Position", Paned },
+ { "x", "Position", Panner },
+ { "x", "Position", Porthole },
+ { "x", "Position", RadioGroup },
+ { "x", "Position", Repeater },
+ { "x", "Position", RowCol },
+ { "x", "Position", Scrollbar },
+ { "x", "Position", Scrollbar2 },
+ { "x", "Position", Separator },
+ { "x", "Position", Shell },
+ { "x", "Position", Simple },
+ { "x", "Position", SimpleMenu },
+ { "x", "Position", Slider2d },
+ { "x", "Position", Sme },
+ { "x", "Position", SmeBSB },
+ { "x", "Position", SmeLine },
+ { "x", "Position", StripChart },
+ { "x", "Position", Table },
+ { "x", "Position", TextBox },
+ { "x", "Position", TextButton },
+ { "x", "Position", TextToggle },
+ { "x", "Position", Toggle },
+ { "x", "Position", TopLevelShell },
+ { "x", "Position", TransientShell },
+ { "x", "Position", Tree },
+ { "x", "Position", Viewport },
+ { "x", "Position", WMShell },
+ { "x", "Position", XfwfCommon },
+ { "x", "Position", XfwfMenuBar },
+ { "xorFill", "Boolean", Gterm },
+ { "xorFillBgColor", "Int", Gterm },
+ { "xorFillColor", "Int", Gterm },
+ { "y", "Position", ApplicationShell },
+ { "y", "Position", Arrow },
+ { "y", "Position", AsciiText },
+ { "y", "Position", Board },
+ { "y", "Position", Box },
+ { "y", "Position", Command },
+ { "y", "Position", Core },
+ { "y", "Position", Dialog },
+ { "y", "Position", Form },
+ { "y", "Position", Frame },
+ { "y", "Position", Grip },
+ { "y", "Position", Group },
+ { "y", "Position", Gterm },
+ { "y", "Position", HTML },
+ { "y", "Position", Icon },
+ { "y", "Position", Label },
+ { "y", "Position", Layout },
+ { "y", "Position", List },
+ { "y", "Position", MenuButton },
+ { "y", "Position", MultiList },
+ { "y", "Position", OverrideShell },
+ { "y", "Position", Paned },
+ { "y", "Position", Panner },
+ { "y", "Position", Porthole },
+ { "y", "Position", RadioGroup },
+ { "y", "Position", Repeater },
+ { "y", "Position", RowCol },
+ { "y", "Position", Scrollbar },
+ { "y", "Position", Scrollbar2 },
+ { "y", "Position", Separator },
+ { "y", "Position", Shell },
+ { "y", "Position", Simple },
+ { "y", "Position", SimpleMenu },
+ { "y", "Position", Slider2d },
+ { "y", "Position", Sme },
+ { "y", "Position", SmeBSB },
+ { "y", "Position", SmeLine },
+ { "y", "Position", StripChart },
+ { "y", "Position", Table },
+ { "y", "Position", TextBox },
+ { "y", "Position", TextButton },
+ { "y", "Position", TextToggle },
+ { "y", "Position", Toggle },
+ { "y", "Position", TopLevelShell },
+ { "y", "Position", TransientShell },
+ { "y", "Position", Tree },
+ { "y", "Position", Viewport },
+ { "y", "Position", WMShell },
+ { "y", "Position", XfwfCommon },
+ { "y", "Position", XfwfMenuBar },
+ { (char *)NULL, (char *)NULL, (unsigned long)NULL },
+};
+
+/* Prints a table listing the unique resource name/type pairs, with a bitmask
+ * indicating the widget classes using each resource/type pair.
+ */
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ register struct resource_list *rp, *np;
+ register unsigned long flags1, flags2;
+ int decorate = 0;
+
+ if (argc >= 2 && !strcmp(argv[1],"-decorate"))
+ decorate++;
+
+ for (rp=resources; rp && rp->resource; rp=np) {
+ for (np=rp, flags1=flags2=0; np && np->type &&
+ (!strcmp(rp->resource,np->resource) &&
+ !strcmp(rp->type,np->type)); ) {
+
+ flags1 |= np->class1;
+ flags2 |= np->class2;
+ np++;
+ }
+
+ if (decorate) {
+ printf ("{ \"%s\", XtR%s, %011o, %011o, NULL },\n",
+ rp->resource, rp->type, flags1, flags2);
+ } else {
+ printf ("%s %s %011o %011o\n",
+ rp->resource, rp->type, flags1, flags2);
+ }
+ }
+}
diff --git a/vendor/x11iraf/obm/obmres.dat b/vendor/x11iraf/obm/obmres.dat
new file mode 100644
index 00000000..756a12d4
--- /dev/null
+++ b/vendor/x11iraf/obm/obmres.dat
@@ -0,0 +1,538 @@
+/*
+ * OBMRES.DAT -- Global resource table used by the object manager.
+ * Format: resource name, resource type, widget classes bitflags, hash link.
+ *
+ * To regenerate this file, add any new resources to the table in the
+ * obmres.c file, sort the table, and then do the following. (Note: the
+ * widget type code #defines in obmres.c must agree with those in obm.c,
+ * ignoring the Wt prefix used in obm.c.)
+ *
+ * 1. cc obmres.c -o obmres.e
+ * 2. obmres.e -decorate > temp
+ * 3. Replace the text following this comment by the contents of
+ * the file temp.
+ *
+ * The "undecorated" output of obmres may be used for various queries, e.g.,
+ * obmres.e | awk '{ print $2 }' | sort | uniq
+ * will list all the resource types.
+ */
+
+/* The following definitions appear to be needed to work around omissions
+ * in the X11R4 Athena widget public include files.
+ */
+#ifndef XtREdgeType
+# define XtREdgeType "EdgeType"
+#endif
+#ifndef XtRWrapMode
+# define XtRWrapMode "WrapMode"
+#endif
+#ifndef XtRTextResizeMode
+# define XtRTextResizeMode "TextResizeMode"
+#endif
+#ifndef XtRTextScrollMode
+# define XtRTextScrollMode "TextScrollMode"
+#endif
+#ifndef XtRResizeMode
+# define XtRResizeMode "ResizeMode"
+#endif
+#ifndef XtRScrollMode
+# define XtRScrollMode "ScrollMode"
+#endif
+#ifndef XtNwaitforwm
+# define XtNwaitforwm XtNwaitForWm
+#endif
+
+
+{ "abs_height", XtRPosition, 00000575570, 00000000000, NULL },
+{ "abs_width", XtRPosition, 00000575570, 00000000000, NULL },
+{ "abs_x", XtRPosition, 00000575570, 00000000000, NULL },
+{ "abs_y", XtRPosition, 00000575570, 00000000000, NULL },
+{ "accelerators", XtRAcceleratorTable, 00011777777, 01707777715, NULL },
+{ "addColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "addRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowAddColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowAddRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteTable", XtRCallback, 00010000000, 00000000000, NULL },
+{ "activate", XtRCallback, 00000145400, 00000000000, NULL },
+{ "activateCallback", XtRCallback, 00002000000, 00000000000, NULL },
+{ "activeAnchorBG", XtRPixel, 00000000004, 00000000000, NULL },
+{ "activeAnchorFG", XtRPixel, 00000000004, 00000000000, NULL },
+{ "addressFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "alignment", XtRAlignment, 00000574500, 00000000000, NULL },
+{ "allowAddColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowAddRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowDeleteTable", XtRCallback, 00010000000, 00000000000, NULL },
+{ "allowHoriz", XtRBoolean, 00000000000, 01000000000, NULL },
+{ "allowOff", XtRBoolean, 00000000000, 00000200000, NULL },
+{ "allowResize", XtRBoolean, 00000000000, 00000100000, NULL },
+{ "allowShellResize", XtRBoolean, 00000000000, 00004000010, NULL },
+{ "allowVert", XtRBoolean, 00000000000, 01000000000, NULL },
+{ "alphaFont1", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont2", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont3", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont4", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont5", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont6", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont7", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "alphaFont8", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "ancestorSensitive", XtRBoolean, 00010777777, 01777777715, NULL },
+{ "anchorCallback", XtRCallback, 00000000004, 00000000000, NULL },
+{ "anchorColor", XtRPixel, 00000000004, 00000000000, NULL },
+{ "anchorUnderlines", XtRInt, 00000000004, 00000000000, NULL },
+{ "argc", XtRInt, 00000000000, 00000000010, NULL },
+{ "argv", XtRStringArray, 00000000000, 00000000010, NULL },
+{ "arrowShadow", XtRDimension, 00000000010, 00000000000, NULL },
+{ "autoFill", XtRBoolean, 00000000000, 00000000100, NULL },
+{ "autoReconfigure", XtRBoolean, 00000000000, 00400000000, NULL },
+{ "background", XtRPixel, 00014777777, 01707773735, NULL },
+{ "backgroundPixmap", XtRPixmap, 00013777777, 01707777715, NULL },
+{ "backgroundStipple", XtRString, 00000000000, 00000200000, NULL },
+{ "backingStore", XtRBackingStore, 00000000000, 00004000000, NULL },
+{ "baseHeight", XtRInt, 00000000000, 00000000010, NULL },
+{ "basePixel", XtRInt, 00000000001, 00000000000, NULL },
+{ "baseWidth", XtRInt, 00000000000, 00000000010, NULL },
+{ "betweenCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "bitmap", XtRBitmap, 00004000000, 00201050400, NULL },
+{ "boldFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "border", XtRPixel, 00004000000, 00000000000, NULL },
+{ "borderColor", XtRPixel, 00010777777, 01707777715, NULL },
+{ "borderPixmap", XtRPixmap, 00013777777, 01707777715, NULL },
+{ "borderWidth", XtRDimension, 00005777777, 01777777715, NULL },
+{ "bottom", XtREdgeType, 00000000000, 01000003000, NULL },
+{ "bottomMargin", XtRDimension, 00000160100, 00004000000, NULL },
+{ "bottomMargin", XtRPosition, 00000000000, 00000000100, NULL },
+{ "bottomShadowColor", XtRPixel, 00000575770, 00000000000, NULL },
+{ "bottomShadowContast", XtRInt, 00001000000, 00000000000, NULL },
+{ "bottomShadowPixel", XtRPixel, 00010000000, 00000000000, NULL },
+{ "bottomShadowPixmap", XtRPixmap, 00010000000, 00000000000, NULL },
+{ "bottomShadowStipple", XtRBitmap, 00000575770, 00000000000, NULL },
+{ "branchPixmap", XtRBitmap, 00002000000, 00000000000, NULL },
+{ "branchOpenPixmap", XtRBitmap, 00002000000, 00000000000, NULL },
+{ "branchCallback", XtRCallback, 00002000000, 00000000000, NULL },
+{ "busyCursor", XtRString, 00000000001, 00000000000, NULL },
+{ "busyCursorBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "busyCursorFgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "cacheRasters", XtRString, 00000000001, 00000000000, NULL },
+{ "callback", XtRCallback, 00001002010, 00271064540, NULL },
+{ "canvasHeight", XtRDimension, 00000000000, 00000200000, NULL },
+{ "canvasWidth", XtRDimension, 00000000000, 00000200000, NULL },
+{ "changedCell", XtRCallback, 00010000000, 00000000000, NULL },
+{ "changedColumnWidth", XtRCallback, 00010000000, 00000000000, NULL },
+{ "changedRowHeight", XtRCallback, 00010000000, 00000000000, NULL },
+{ "children", XtRWidgetList, 00010775776, 01404503210, NULL },
+{ "cmapInitialize", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "cmapInterpolate", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "cmapName", XtRString, 00000000001, 00000000000, NULL },
+{ "cmapShadow", XtRInt, 00000000001, 00000000000, NULL },
+{ "cmapUpdate", XtRInt, 00000000001, 00000000000, NULL },
+{ "color0", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color1", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color2", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color3", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color4", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color5", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color6", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color7", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color8", XtRPixel, 00000000001, 00000000000, NULL },
+{ "color9", XtRPixel, 00000000001, 00000000000, NULL },
+{ "colormap", XtRColormap, 00011777777, 01707777715, NULL },
+{ "columnForeground", XtRPixel, 00010000000, 00000000000, NULL },
+{ "columnMargin", XtRDimension, 00010000000, 00000000000, NULL },
+{ "columnSpacing", XtRDimension, 00000002000, 00000020000, NULL },
+{ "columnWidth", XtRDimension, 00000002000, 00000000000, NULL },
+{ "columns", XtRInt, 00010414400, 00000000000, NULL },
+{ "copyOnResize", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "cornerRoundPercent", XtRDimension, 00000000000, 00201040400, NULL },
+{ "createPopupChildProc", XtRFunction, 00000000000, 00004000010, NULL },
+{ "createTable", XtRCallback, 00010000000, 00000000000, NULL },
+{ "crosshairCursorColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "cursor", XtRCursor, 00004577770, 00307374504, NULL },
+{ "cursorName", XtRString, 00004002000, 00303274504, NULL },
+{ "dashedAnchorUnderlines", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "dashedVisitedAnchorUnderlines", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "dataCompression", XtRBoolean, 00000000000, 00000000140, NULL },
+{ "debug", XtRBoolean, 00000000002, 00000000000, NULL },
+{ "decay", XtRInt, 00000000000, 00001000000, NULL },
+{ "defaultColumns", XtRInt, 00000002000, 00000020000, NULL },
+{ "defaultDistance", XtRInt, 00000000000, 01000003000, NULL },
+{ "defaultMarker", XtRString, 00000000001, 00000000000, NULL },
+{ "defaultScale", XtRDimension, 00000000000, 00000200000, NULL },
+{ "defaultWidth", XtRInt, 00010000000, 00000000000, NULL },
+{ "deiconifyWindow", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "deleteColumn", XtRCallback, 00010000000, 00000000000, NULL },
+{ "deleteRow", XtRCallback, 00010000000, 00000000000, NULL },
+{ "deleteTable", XtRCallback, 00010000000, 00000000000, NULL },
+{ "delayImageLoads", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "depth", XtRInt, 00010777777, 01707777715, NULL },
+{ "destroyCallback", XtRCallback, 00010777777, 01777777777, NULL },
+{ "dialogBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "dialogFgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "dialogFont1", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont2", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont3", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont4", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont5", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont6", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont7", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "dialogFont8", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "direction", XtRAlignment, 00000000010, 00000000000, NULL },
+{ "displayCaret", XtRBoolean, 00000000000, 00000000100, NULL },
+{ "displayNonprinting", XtRBoolean, 00000000000, 00000000120, NULL },
+{ "displayPosition", XtRInt, 00000000000, 00000000100, NULL },
+{ "echo", XtRBoolean, 00000000000, 00000000120, NULL },
+{ "editBackground", XtRPixel, 00010000000, 00000000000, NULL },
+{ "editForeground", XtRPixel, 00010000000, 00000000000, NULL },
+{ "editable", XtRBoolean, 00010000000, 00000000000, NULL },
+{ "editType", XtREditMode, 00000000000, 00000000140, NULL },
+{ "encoding", XtRUnsignedChar, 00010000000, 00201050400, NULL },
+{ "fancySelections", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "fixedFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "fixedboldFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "fixeditalicFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "flash", XtRBoolean, 00000000000, 00001000000, NULL },
+{ "font", XtRFontStruct, 00013166504, 00221070520, NULL },
+{ "footerText", XtRString, 00000000004, 00000000000, NULL },
+{ "forceBars", XtRBoolean, 00000000000, 01000000000, NULL },
+{ "forceColumns", XtRBoolean, 00000002000, 00000020000, NULL },
+{ "foreground", XtRPixel, 00016166514, 00763274520, NULL },
+{ "frameType", XtRFrameType, 00000575770, 00000000000, NULL },
+{ "frameWidth", XtRDimension, 00000575770, 00000000000, NULL },
+{ "fromHoriz", XtRWidget, 00000000000, 01000003000, NULL },
+{ "fromVert", XtRWidget, 00000000000, 01000003000, NULL },
+{ "geometry", XtRString, 00000000000, 00004000010, NULL },
+{ "getValue", XtRCallback, 00000000000, 00100000000, NULL },
+{ "ginmodeBlinkInterval", XtRInt, 00000000001, 00000000000, NULL },
+{ "ginmodeCursor", XtRString, 00000000001, 00000000000, NULL },
+{ "ginmodeCursorBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "ginmodeCursorFgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "gravity", XtRGravity, 00000000000, 00400000000, NULL },
+{ "gripCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "gripIndent", XtRPosition, 00000000000, 00000100000, NULL },
+{ "gripTranslations", XtRTranslationTable, 00000000000, 00000100000, NULL },
+{ "hSpace", XtRDimension, 00000000000, 00400000200, NULL },
+{ "header1Font1Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "header2Font2Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "header3Font3Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "header4Font4Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "header5Font5Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "header6Font6Font", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "headerText", XtRString, 00000000004, 00000000000, NULL },
+{ "height", XtRDimension, 00014777777, 01777777715, NULL },
+{ "heightInc", XtRInt, 00000000000, 00000000010, NULL },
+{ "highlight", XtRPixel, 00000000000, 00100000000, NULL },
+{ "highlightBackground", XtRPixel, 00000002000, 00000000000, NULL },
+{ "highlightCallback", XtRCallback, 00002000000, 00000000000, NULL },
+{ "highlightColor", XtRPixel, 00000775770, 00000000000, NULL },
+{ "highlightForeground", XtRPixel, 00000002000, 00000000000, NULL },
+{ "highlightPixmap", XtRPixmap, 00000775770, 00000000000, NULL },
+{ "highlightThickness", XtRDimension, 00000775770, 00201040400, NULL },
+{ "horizDistance", XtRInt, 00000000000, 01000003000, NULL },
+{ "horizontalBetweenCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "horizontalGripCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "horizontalScroll", XtRWidget, 00010000000, 00000000000, NULL },
+{ "horizontalScrollBar", XtRWidget, 00000000004, 00000000000, NULL },
+{ "horizontalScrollOnTop", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "horizontalSpacing", XtRDimension, 00002000000, 00000000000, NULL },
+{ "hunit", XtRFloat, 00000575570, 00000000000, NULL },
+{ "icon", XtRBitmap, 00000000000, 00000001000, NULL },
+{ "iconMask", XtRBitmap, 00000000000, 00000000010, NULL },
+{ "iconName", XtRString, 00000000000, 00000000010, NULL },
+{ "iconNameEncoding", XtRAtom, 00000000000, 00000000010, NULL },
+{ "iconPixmap", XtRBitmap, 00000000000, 00000000010, NULL },
+{ "iconWindow", XtRWindow, 00000000000, 00000000010, NULL },
+{ "iconX", XtRInt, 00000000000, 00000000010, NULL },
+{ "iconY", XtRInt, 00000000000, 00000000010, NULL },
+{ "iconic", XtRBoolean, 00000000000, 00000000010, NULL },
+{ "idleCursor", XtRString, 00000000001, 00000000000, NULL },
+{ "idleCursorBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "idleCursorFgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "image", XtRIcon, 00000001000, 00000000000, NULL },
+{ "imageBorders", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "increment", XtRFloat, 00000000040, 00000000000, NULL },
+{ "indent", XtRDimension, 00002000000, 00000000000, NULL },
+{ "initialDelay", XtRCardinal, 00000000050, 00000000000, NULL },
+{ "initialDelay", XtRInt, 00000000000, 00001000000, NULL },
+{ "initialState", XtRInitialState, 00000000000, 00000000010, NULL },
+{ "insensitiveContrast", XtRInt, 00001000000, 00000000000, NULL },
+{ "innerOffset", XtRDimension, 00000575770, 00000000000, NULL },
+{ "input", XtRBool, 00000000000, 00000000010, NULL },
+{ "insensitiveBorder", XtRPixmap, 00000002000, 00303274504, NULL },
+{ "insertPosition", XtRFunction, 00000775776, 01404503210, NULL },
+{ "insertPosition", XtRInt, 00000000000, 00000000100, NULL },
+{ "internalBorderColor", XtRPixel, 00000000000, 00000100000, NULL },
+{ "internalBorderWidth", XtRDimension, 00000000000, 00000100000, NULL },
+{ "internalHeight", XtRDimension, 00011000000, 00201070400, NULL },
+{ "internalSpace", XtRDimension, 00000000000, 00000200000, NULL },
+{ "internalWidth", XtRDimension, 00011000000, 00201070400, NULL },
+{ "isIndex", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "italicFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "jumpProc", XtRCallback, 00000000000, 00002000000, NULL },
+{ "jumpScroll", XtRInt, 00000000000, 00100000000, NULL },
+{ "justify", XtRJustify, 00010000000, 00221050400, NULL },
+{ "label", XtRString, 00000164500, 00225051400, NULL },
+{ "labelClass", XtRPointer, 00000000000, 00004000000, NULL },
+{ "labelShadowWidth", XtRDimension, 00010000000, 00000000000, NULL },
+{ "labels", XtRStringArray, 00000004000, 00000000000, NULL },
+{ "layout", XtRLayout, 00000000002, 00000000000, NULL },
+{ "leafPixmap", XtRBitmap, 00002000000, 00000000000, NULL },
+{ "leafOpenPixmap", XtRBitmap, 00002000000, 00000000000, NULL },
+{ "leafCallback", XtRCallback, 00002000000, 00000000000, NULL },
+{ "left", XtREdgeType, 00000000000, 01000003000, NULL },
+{ "leftBitmap", XtRBitmap, 00000000000, 00221050400, NULL },
+{ "leftCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "leftMargin", XtRDimension, 00000160100, 00020000000, NULL },
+{ "leftMargin", XtRPosition, 00000000000, 00000000100, NULL },
+{ "length", XtRDimension, 00000000000, 00002000000, NULL },
+{ "length", XtRInt, 00000000000, 00000000140, NULL },
+{ "lineWidth", XtRDimension, 00002000000, 00440200000, NULL },
+{ "linkCallback", XtRCallback, 00000000004, 00000000000, NULL },
+{ "list", XtRPointer, 00000002000, 00000020000, NULL },
+{ "listingFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "literal", XtRBoolean, 00010000000, 00000000000, NULL },
+{ "literalWidth", XtRInt, 00010000000, 00000000000, NULL },
+{ "location", XtRString, 00000575570, 00000000000, NULL },
+{ "longest", XtRInt, 00000002000, 00000020000, NULL },
+{ "lowerCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "mappedWhenManaged", XtRBoolean, 00014777777, 01707777715, NULL },
+{ "margin", XtRDimension, 00002000000, 00000000000, NULL },
+{ "marginHeight", XtRDimension, 00000000004, 00000000000, NULL },
+{ "marginWidth", XtRDimension, 00000000004, 00000000000, NULL },
+{ "markerBoxKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerBoxKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerBoxLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerCircleKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerCircleKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerCircleLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerCursorBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerCursorFgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerEllipseKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerEllipseKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerEllipseLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerFill", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "markerFillBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerFillColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerFillStyle", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerHighlightColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerHighlightWidth", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerLineKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerLineKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerLineLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerLineStyle", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerLineWidth", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerPgonKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerPgonKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerPgonLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerRectKnotColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerRectKnotSize", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerRectLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerTextBgColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerTextBorder", XtRInt, 00000000001, 00000000000, NULL },
+{ "markerTextColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerTextFont", XtRFontStruct, 00000000001, 00000000000, NULL },
+{ "markerTextLineColor", XtRPixel, 00000000001, 00000000000, NULL },
+{ "markerTextString", XtRString, 00000000001, 00000000000, NULL },
+{ "markerTranslations", XtRString, 00000000001, 00000000000, NULL },
+{ "maskNumber", XtRInt, 00010000000, 00000000000, NULL },
+{ "max", XtRDimension, 00000000000, 00000100000, NULL },
+{ "maxAspectX", XtRInt, 00000000000, 00000000010, NULL },
+{ "maxAspectY", XtRInt, 00000000000, 00000000010, NULL },
+{ "maxColors", XtRInt, 00000000001, 00000000000, NULL },
+{ "maxHeight", XtRInt, 00000000000, 00000000010, NULL },
+{ "maxMappings", XtRInt, 00000000001, 00000000000, NULL },
+{ "maxRasters", XtRInt, 00000000001, 00000000000, NULL },
+{ "maxSelectable", XtRInt, 00000002000, 00000000000, NULL },
+{ "maxWidth", XtRInt, 00000000000, 00000000010, NULL },
+{ "menuName", XtRString, 00000000000, 00000040000, NULL },
+{ "menuOnScreen", XtRBoolean, 00000000000, 00004000000, NULL },
+{ "min", XtRDimension, 00000000000, 00000100000, NULL },
+{ "minAspectX", XtRInt, 00000000000, 00000000010, NULL },
+{ "minAspectY", XtRInt, 00000000000, 00000000010, NULL },
+{ "minHeight", XtRInt, 00000000000, 00000000010, NULL },
+{ "minScale", XtRInt, 00000000000, 00100000000, NULL },
+{ "minWidth", XtRInt, 00000000000, 00000000010, NULL },
+{ "minimumDelay", XtRInt, 00000000000, 00001000000, NULL },
+{ "minimumThumb", XtRDimension, 00000000000, 00002000000, NULL },
+{ "minsize", XtRDimension, 00000000140, 00000000000, NULL },
+{ "nearEdge", XtRInt, 00000000001, 00000000000, NULL },
+{ "nearVertex", XtRInt, 00000000001, 00000000000, NULL },
+{ "nextTop", XtRCallback, 00000775770, 00000000000, NULL },
+{ "numChildren", XtRCardinal, 00010775776, 01404503210, NULL },
+{ "numberStrings", XtRInt, 00000002000, 00000020000, NULL },
+{ "offCallback", XtRCallback, 00000100000, 00000000000, NULL },
+{ "offIcon", XtRIcon, 00000100000, 00000000000, NULL },
+{ "on", XtRBoolean, 00000100000, 00000000000, NULL },
+{ "onCallback", XtRCallback, 00000100000, 00000000000, NULL },
+{ "onIcon", XtRIcon, 00000100000, 00000000000, NULL },
+{ "orientation", XtROrientation, 00000000000, 00002100200, NULL },
+{ "outerOffset", XtRDimension, 00000575770, 00000000000, NULL },
+{ "overrideRedirect", XtRBoolean, 00000000000, 00004000010, NULL },
+{ "pathCallback", XtRCallback, 00002000000, 00000000000, NULL },
+{ "pasteBuffer", XtRBoolean, 00000002000, 00000020000, NULL },
+{ "percentVerticalSpace", XtRInt, 00000000004, 00000000000, NULL },
+{ "pickTop", XtRBoolean, 00000000000, 00002000000, NULL },
+{ "pieceSize", XtRInt, 00000000000, 00000000140, NULL },
+{ "plainFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "plainboldFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "plainitalicFont", XtRFontStruct, 00000000004, 00000000000, NULL },
+{ "pointerColor", XtRPixel, 00000002000, 00303274504, NULL },
+{ "pointerColorBackground", XtRPixel, 00000002000, 00303274504, NULL },
+{ "pointerMotionCallback", XtRPointer, 00000000004, 00000000000, NULL },
+{ "popdownCallback", XtRCallback, 00001000000, 00004000010, NULL },
+{ "popupCallback", XtRCallback, 00001000000, 00004000010, NULL },
+{ "popupOnEntry", XtRWidget, 00000000000, 00004000000, NULL },
+{ "position", XtRInt, 00000000000, 00000100000, NULL },
+{ "preferredPaneSize", XtRDimension, 00000000000, 00000100000, NULL },
+{ "previouslyVisitedTestFunction", XtRPointer, 00000000004, 00000000000, NULL },
+{ "radioData", XtRPointer, 00000000000, 00200000000, NULL },
+{ "radioGroup", XtRWidget, 00000000000, 00200000000, NULL },
+{ "raiseWindow", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "refigureMode", XtRBoolean, 00000000000, 00000100000, NULL },
+{ "rel_height", XtRFloat, 00000575570, 00000000000, NULL },
+{ "rel_width", XtRFloat, 00000575570, 00000000000, NULL },
+{ "rel_x", XtRFloat, 00000575570, 00000000000, NULL },
+{ "rel_y", XtRFloat, 00000575570, 00000000000, NULL },
+{ "repeatDelay", XtRCardinal, 00000000050, 00000000000, NULL },
+{ "repeatDelay", XtRInt, 00000000000, 00001000000, NULL },
+{ "reportCallback", XtRCallback, 00000000000, 01000600000, NULL },
+{ "resizable", XtRBoolean, 00001000000, 01000003000, NULL },
+{ "resize", XtRBoolean, 00000000000, 00201250400, NULL },
+{ "resize", XtRResizeMode, 00000000000, 00000000100, NULL },
+{ "resizeToPreferred", XtRBoolean, 00000000000, 00000100000, NULL },
+{ "resolveDelayedImage", XtRPointer, 00000000004, 00000000000, NULL },
+{ "resolveImageFunction", XtRPointer, 00000000004, 00000000000, NULL },
+{ "right", XtREdgeType, 00000000000, 01000003000, NULL },
+{ "rightBitmap", XtRBitmap, 00000000000, 00020000000, NULL },
+{ "rightCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "rightMargin", XtRDimension, 00000160100, 00020000000, NULL },
+{ "rightMargin", XtRPosition, 00000000000, 00000000100, NULL },
+{ "rowForeground", XtRPixel, 00010000000, 00000000000, NULL },
+{ "rowHeight", XtRDimension, 00000002000, 00004000000, NULL },
+{ "rowHeight", XtRInt, 00010000000, 00000000000, NULL },
+{ "rowOriented", XtRBoolean, 00010000000, 00000000000, NULL },
+{ "rowMargin", XtRDimension, 00010000000, 00000000000, NULL },
+{ "rowSpacing", XtRDimension, 00000002000, 00000020000, NULL },
+{ "rows", XtRInt, 00010414400, 00000000000, NULL },
+{ "rubberBand", XtRBoolean, 00000000000, 00000200000, NULL },
+{ "rvLength", XtRInt, 00000160100, 00000000000, NULL },
+{ "rvStart", XtRInt, 00000160100, 00000000000, NULL },
+{ "saveUnder", XtRBoolean, 00000000000, 00004000010, NULL },
+{ "screen", XtRScreen, 00010777777, 01707777715, NULL },
+{ "scrollCallback", XtRCallback, 00000000140, 00000000000, NULL },
+{ "scrollDCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollHCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollHorizontal", XtRScrollMode, 00000000000, 00000000100, NULL },
+{ "scrollLCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollProc", XtRCallback, 00000000000, 00002000000, NULL },
+{ "scrollRCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollResponse", XtRXTCallbackProc, 00000000140, 00000000000, NULL },
+{ "scrollUCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollVCursor", XtRCursor, 00000000000, 00002000000, NULL },
+{ "scrollVertical", XtRScrollMode, 00000000000, 00000000100, NULL },
+{ "scrollbarForeground", XtRPixel, 00000000040, 00000000000, NULL },
+{ "selectTypes", XtRPointer, 00000000000, 00000000100, NULL },
+{ "selectInsensitive", XtRBoolean, 00001000000, 00000000000, NULL },
+{ "selection", XtRLong, 00000004400, 00000000000, NULL },
+{ "selectionStyle", XtRSelectionType, 00000004400, 00000000000, NULL },
+{ "sensitive", XtRBoolean, 00010777777, 01777777715, NULL },
+{ "sensitiveArray", XtRPointer, 00000002000, 00000000000, NULL },
+{ "shadeSurplus", XtRBoolean, 00000002000, 00000000000, NULL },
+{ "shadow", XtRDimension, 00000000040, 00000000000, NULL },
+{ "shadowColor", XtRPixel, 00000000000, 00000200000, NULL },
+{ "shadowScheme", XtRShadowScheme, 00000575770, 00000000000, NULL },
+{ "shadowThickness", XtRDimension, 00000000000, 00000200000, NULL },
+{ "shadowWidth", XtRDimension, 00010000000, 00000000000, NULL },
+{ "shapeStyle", XtRShapeStyle, 00000000000, 00201040400, NULL },
+{ "showGrip", XtRBoolean, 00000000000, 00000100000, NULL },
+{ "shown", XtRFloat, 00000000000, 00002000000, NULL },
+{ "shrinkToFit", XtRBoolean, 00000574500, 00000000000, NULL },
+{ "skipAdjust", XtRBoolean, 00000000000, 00000100000, NULL },
+{ "sliderHeight", XtRDimension, 00000000000, 00000200000, NULL },
+{ "sliderWidth", XtRDimension, 00000000000, 00000200000, NULL },
+{ "sliderX", XtRPosition, 00000000000, 00000200000, NULL },
+{ "sliderY", XtRPosition, 00000000000, 00000200000, NULL },
+{ "startCallback", XtRCallback, 00000000000, 00001000000, NULL },
+{ "state", XtRBoolean, 00000000000, 00200000000, NULL },
+{ "stipple", XtRBitmap, 00000000000, 00040000000, NULL },
+{ "stopCallback", XtRCallback, 00000000000, 00001000000, NULL },
+{ "storeByRow", XtRBoolean, 00000414400, 00000000000, NULL },
+{ "string", XtRString, 00000000000, 00000000140, NULL },
+{ "submitFormCallback", XtRCallback, 00000000004, 00000000000, NULL },
+{ "tabForeground", XtRPixel, 00001000000, 00000000000, NULL },
+{ "tabLabel", XtRString, 00001000000, 00000000000, NULL },
+{ "tableMargin", XtRDimension, 00010000000, 00000000000, NULL },
+{ "tabLeftBitmap", XtRBitmap, 00001000000, 00000000000, NULL },
+{ "tablist", XtRString, 00000162100, 00000000000, NULL },
+{ "text", XtRString, 00000000004, 00000000000, NULL },
+{ "textSink", XtRWidget, 00000000000, 00000000100, NULL },
+{ "textSource", XtRWidget, 00000000000, 00000000100, NULL },
+{ "thickness", XtRDimension, 00000000000, 00002000000, NULL },
+{ "thumb", XtRBitmap, 00000000000, 00002000000, NULL },
+{ "thumbColor", XtRPixel, 00000000100, 00000000000, NULL },
+{ "thumbFrameType", XtRFrameType, 00000000100, 00000000000, NULL },
+{ "thumbFrameWidth", XtRDimension, 00000000100, 00000000000, NULL },
+{ "thumbPixmap", XtRPixmap, 00000000100, 00000000000, NULL },
+{ "thumbProc", XtRCallback, 00000000000, 00002000000, NULL },
+{ "title", XtRString, 00000000000, 00000000010, NULL },
+{ "titleEncoding", XtRAtom, 00000000000, 00000000010, NULL },
+{ "titleText", XtRString, 00000000004, 00000000000, NULL },
+{ "top", XtREdgeType, 00000000000, 01000003000, NULL },
+{ "topMargin", XtRDimension, 00000160100, 00004000000, NULL },
+{ "topMargin", XtRPosition, 00000000000, 00000000100, NULL },
+{ "topOfThumb", XtRFloat, 00000000000, 00002000000, NULL },
+{ "topShadowColor", XtRPixel, 00000575770, 00000000000, NULL },
+{ "topShadowPixel", XtRPixel, 00010000000, 00000000000, NULL },
+{ "topShadowPixmap", XtRPixmap, 00010000000, 00000000000, NULL },
+{ "topShadowContast", XtRInt, 00001000000, 00000000000, NULL },
+{ "topShadowStipple", XtRBitmap, 00000575770, 00000000000, NULL },
+{ "topWidget", XtRWidget, 00001000000, 00000000000, NULL },
+{ "transient", XtRBoolean, 00000000000, 00000000010, NULL },
+{ "transientFor", XtRWidget, 00000000000, 00000000010, NULL },
+{ "translations", XtRTranslationTable, 00010777777, 01707777715, NULL },
+{ "traversalOn", XtRBoolean, 00000775770, 00000000000, NULL },
+{ "treeGC", XtRGC, 00000000000, 00400000000, NULL },
+{ "treeParent", XtRWidget, 00000000000, 00400000000, NULL },
+{ "type", XtRAsciiType, 00000000000, 00000000140, NULL },
+{ "unrealizeCallback", XtRCallback, 00000000000, 00000000100, NULL },
+{ "update", XtRInt, 00000000000, 00100000000, NULL },
+{ "upperCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "useBottom", XtRBoolean, 00000000000, 01000000000, NULL },
+{ "useRight", XtRBoolean, 00000000000, 01000000000, NULL },
+{ "useStringInPlace", XtRBoolean, 00000000000, 00000000140, NULL },
+{ "useTimers", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "userData", XtRPointer, 00000775770, 00001000000, NULL },
+{ "userData", XtRPixmap, 00010000000, 00000000000, NULL },
+{ "vSpace", XtRDimension, 00000000000, 00400000200, NULL },
+{ "value", XtRString, 00000000000, 00000001000, NULL },
+{ "vertDistance", XtRInt, 00000000000, 01000003000, NULL },
+{ "vertSpace", XtRInt, 00000000000, 00020000000, NULL },
+{ "vertical", XtRBoolean, 00000000040, 00000000000, NULL },
+{ "verticalBetweenCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "verticalGripCursor", XtRCursor, 00000000000, 00000100000, NULL },
+{ "verticalList", XtRBoolean, 00000002000, 00000020000, NULL },
+{ "verticalScroll", XtRWidget, 00010000000, 00000000000, NULL },
+{ "verticalScrollBar", XtRWidget, 00000000004, 00000000000, NULL },
+{ "verticalScrollOnRight", XtRBoolean, 00000000004, 00000000000, NULL },
+{ "verticalSpacing", XtRDimension, 00002000000, 00000000000, NULL },
+{ "view", XtRWidget, 00000000004, 00000000000, NULL },
+{ "visitedAnchorColor", XtRPixel, 00000000004, 00000000000, NULL },
+{ "visitedAnchorUnderlines", XtRInt, 00000000004, 00000000000, NULL },
+{ "visual", XtRVisual, 00000000000, 00004000010, NULL },
+{ "vunit", XtRFloat, 00000575570, 00000000000, NULL },
+{ "waitforwm", XtRBoolean, 00000000000, 00000000010, NULL },
+{ "warpCursor", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "whatCell", XtRCallback, 00010000000, 00000000000, NULL },
+{ "width", XtRDimension, 00014777777, 01777777715, NULL },
+{ "widthInc", XtRInt, 00000000000, 00000000010, NULL },
+{ "winGravity", XtRInt, 00000000000, 00000000010, NULL },
+{ "windowGroup", XtRWindow, 00000000000, 00000000010, NULL },
+{ "wmTimeout", XtRInt, 00000000000, 00000000010, NULL },
+{ "wrap", XtRWrapMode, 00000000000, 00000000100, NULL },
+{ "x", XtRPosition, 00014777777, 01777777715, NULL },
+{ "xorFill", XtRBoolean, 00000000001, 00000000000, NULL },
+{ "xorFillBgColor", XtRInt, 00000000001, 00000000000, NULL },
+{ "xorFillColor", XtRInt, 00000000001, 00000000000, NULL },
+{ "y", XtRPosition, 00014777777, 01777777715, NULL },
diff --git a/vendor/x11iraf/obm/param.c b/vendor/x11iraf/obm/param.c
new file mode 100644
index 00000000..27226330
--- /dev/null
+++ b/vendor/x11iraf/obm/param.c
@@ -0,0 +1,401 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+
+
+/*
+ * UI PARAMETER class.
+ * --------------------------
+ * The UI parameter class is used for client-UI communications. The client
+ * does not control the user interface directly, rather the UI defines a set
+ * of abstract UI parameters, and during execution the client application
+ * assigns values to these parameters. These UI parameters should be thought
+ * of as describing the runtime state of the client as viewed by the GUI.
+ * The GUI is free to interpret this state information in any way, including
+ * ignoring it. Many GUIs can be written which use the same client state
+ * as described by the UI parameters.
+ *
+ * Assigning a value to a UI parameter causes the new value to be stored, and
+ * any parameter action procedures registered by the UI to be called.
+ * The action or actions (if any) taken when a parameter value changes are
+ * arbitrary, e.g. the action might be something as simple as changing a
+ * displayed value of a UI widget, or something more complex like displaying
+ * a popup.
+ *
+ * UI Parameter class commands:
+ *
+ * getValue
+ * setValue <new-value>
+ * addCallback <procedure-name>
+ * deleteCallback <procedure-name>
+ * notify
+ *
+ * The most common usage is for the GUI to post one or more callbacks for
+ * each UI parameter. When the UI parameter value is changed (with setValue,
+ * e.g. by the client) the GUI callback procedures are called with the old
+ * and new UI parameter values on the command line. addCallback is used to
+ * add a callback procedure, and deleteCallback to delete one. Multiple
+ * callbacks may be registered for a single UI parameter. notify is used
+ * to simulate a parameter value change, causing any callback procedures to
+ * be invoked.
+ *
+ * The callback procedure is called as follows:
+ *
+ * user-procedure param-name {old-value} {new-value}
+ *
+ * The important thing to note here is that the old and new value strings
+ * are quoted with braces. This prevents any interpretation of the string
+ * by Tcl when the callback is executed, which is necessary because the
+ * strings can contain arbitrary data. When Tcl calls the callback the
+ * first level of braces will be stripped off, leaving old-value and new-value
+ * each as a single string argument.
+ */
+
+struct parameterPrivate {
+ ObmContext obm;
+ char *value;
+ int len_value;
+ ObmCallback callback;
+};
+
+typedef struct parameterPrivate *ParameterPrivate;
+
+struct parameterObject {
+ struct obmObjectCore core;
+ struct parameterPrivate parameter;
+};
+
+typedef struct parameterObject *ParameterObject;
+
+/* Object message context. */
+struct msgContext {
+ Tcl_Interp *tcl; /* class interpreter */
+ ObmObject object[MAX_LEVELS]; /* object which received last message */
+ int level;
+};
+typedef struct msgContext *MsgContext;
+
+static void ParameterDestroy();
+static int ParameterEvaluate();
+static ObmObject ParameterCreate();
+static void ParameterClassDestroy();
+static int parameterSetValue(), parameterGetValue(), parameterNotify();
+static int parameterAddCallback(), parameterDeleteCallback();
+
+
+/* ParameterClassInit -- Initialize the class record for the parameter class.
+ */
+void
+ParameterClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register Tcl_Interp *tcl;
+ register MsgContext msg;
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = ParameterClassDestroy;
+ classrec->Create = (ObmFunc) ParameterCreate;
+ classrec->Destroy = ParameterDestroy;
+ classrec->Evaluate = ParameterEvaluate;
+
+ /* Since there can be many instances of the parameter object and
+ * they all respond to the same class messages, a single interpreter
+ * is used for all objects.
+ */
+ msg = (MsgContext) XtMalloc (sizeof (struct msgContext));
+ classrec->class_data = (XtPointer) msg;
+ msg->tcl = tcl = Tcl_CreateInterp();
+ msg->level = 0;
+
+ /* Register parameter-object actions. */
+ Tcl_CreateCommand (tcl, "setValue",
+ parameterSetValue, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "getValue",
+ parameterGetValue, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "addCallback",
+ parameterAddCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "deleteCallback",
+ parameterDeleteCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl, "notify",
+ parameterNotify, (ClientData)msg, NULL);
+}
+
+
+/* ParameterClassDestroy -- Custom destroy procedure for the parameter
+ * class.
+ */
+static void
+ParameterClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register MsgContext msg = (MsgContext) classrec->class_data;
+
+ if (msg) {
+ if (msg->tcl)
+ Tcl_DeleteInterp (msg->tcl);
+ XtFree ((char *)msg);
+ classrec->class_data = NULL;
+ }
+}
+
+
+/* ParameterCreate -- Create an instance of a parameter object.
+ */
+static ObmObject
+ParameterCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register ParameterObject obj;
+
+ obj = (ParameterObject) XtCalloc (1, sizeof (struct parameterObject));
+ obj->parameter.obm = obm;
+
+ return ((ObmObject) obj);
+}
+
+
+/* ParameterDestroy -- Destroy an instance of a parameter object.
+ */
+static void
+ParameterDestroy (object)
+ObmObject object;
+{
+ register ParameterObject obj = (ParameterObject) object;
+ register ObmCallback cb, next;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ XtFree ((char *)obj->parameter.value);
+ for (cb = obj->parameter.callback; cb; cb = next) {
+ next = cb->next;
+ XtFree ((char *)cb);
+ }
+}
+
+
+/* ParameterEvaluate -- Evaluate a parameter command or message.
+ */
+static int
+ParameterEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register ParameterObject obj = (ParameterObject) object;
+ register MsgContext msg = (MsgContext) obj->core.classrec->class_data;
+ register ObmContext obm = obj->parameter.obm;
+ int status;
+
+ /* Since the class wide interpreter is used to evaluate the message
+ * we can't pass the object descriptor directly to the class procedure
+ * referenced in the message. Instead we pass the object reference
+ * in the message descriptor.
+ */
+ msg->object[++msg->level] = object;
+ Tcl_SetResult (obm->tcl, "", TCL_VOLATILE);
+
+ if (!obmClientCommand (msg->tcl, command)) {
+ Tcl_SetResult (obm->tcl, "invalid command", TCL_VOLATILE);
+ status = TCL_ERROR;
+ } else {
+ status = Tcl_Eval (msg->tcl, command);
+ if (status == TCL_ERROR) {
+ if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ else {
+ /* Supply a default error message if none was returned. */
+ Tcl_SetResult (obm->tcl, "evaluation error", TCL_VOLATILE);
+ }
+ obm->tcl->errorLine = msg->tcl->errorLine;
+
+ } else if (*msg->tcl->result)
+ Tcl_SetResult (obm->tcl, msg->tcl->result, TCL_VOLATILE);
+ }
+
+ msg->level--;
+ return (status);
+}
+
+
+/* parameterSetValue -- Set the value of a parameter, and notify all clients
+ * via the posted callback procedures that the parameter value has changed.
+ *
+ * Usage: setValue <new-value>
+ */
+static int
+parameterSetValue (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+ char *new_value, *old_value;
+ ObmCallback cb, cbl[128];
+ int ncb, status, i;
+
+ /* Assign new value. */
+ old_value = pp->value;
+ pp->len_value = strlen (argv[1]);
+ pp->value = new_value = XtMalloc (pp->len_value + 1);
+ memmove (pp->value, argv[1], pp->len_value + 1);
+
+ /* Safeguard callback list against changes by callback procs. */
+ for (cb = pp->callback, ncb=0; cb; cb = cb->next)
+ cbl[ncb++] = cb;
+
+ /* Notify clients that value has changed. */
+ for (i=0; i < ncb && (cb = cbl[i]) != NULL; i++) {
+/*printf ("setValue: i=%d obj='%s' cb='%s' new='%s'\n",
+i, obj->core.name, cb->name, new_value);*/
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "{", old_value ? old_value : "", "} ",
+ "{", new_value, "} ",
+ NULL);
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+ }
+
+ XtFree ((char *)old_value);
+ Tcl_SetResult (obm->tcl, "", TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterGetValue -- Get the value of a parameter.
+ *
+ * Usage: getValue
+ */
+static int
+parameterGetValue (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+
+ Tcl_SetResult (obm->tcl, pp->value, TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterNotify -- Notify the registered clients of a parameter as if the
+ * value had changed.
+ *
+ * Usage: notify
+ */
+static int
+parameterNotify (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ObmContext obm = obj->parameter.obm;
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb;
+ int status;
+
+ /* Notify clients. */
+ for (cb = pp->callback; cb; cb = cb->next) {
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ "{", pp->value, "} ",
+ "{", pp->value, "} ",
+ NULL);
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+ }
+
+ Tcl_SetResult (obm->tcl, "", TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* parameterAddCallback -- Add a callback procedure to the callback list for
+ * a parameter.
+ *
+ * Usage: addCallback <procedure-name>
+ */
+static int
+parameterAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb, new_cb;
+
+ /* Create callback record. */
+ new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ strcpy (new_cb->name, argv[1]);
+
+ /* Add callback to tail of callback list. */
+ if (pp->callback) {
+ for (cb = pp->callback; cb->next; cb = cb->next)
+ ;
+ cb->next = new_cb;
+ } else
+ pp->callback = new_cb;
+
+ return (TCL_OK);
+}
+
+
+/* parameterDeleteCallback -- Delete a callback procedure previously registered
+ * for a parameter.
+ *
+ * Usage: deleteCallback <procedure-name>
+ */
+static int
+parameterDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ParameterObject obj = (ParameterObject) msg->object[msg->level];
+ register ParameterPrivate pp = &obj->parameter;
+ ObmCallback cb, prev;
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=pp->callback; cb; prev=cb, cb=cb->next)
+ if (strcmp (cb->name, argv[1]) == 0) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ pp->callback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ }
+
+ return (TCL_OK);
+}
diff --git a/vendor/x11iraf/obm/server.c b/vendor/x11iraf/obm/server.c
new file mode 100644
index 00000000..fa46d2fd
--- /dev/null
+++ b/vendor/x11iraf/obm/server.c
@@ -0,0 +1,3175 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+
+/* The following internal files are needed for some widget level SmeBSB code
+ * included in this file.
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/Xaw/SmeBSBP.h>
+
+/*
+ * SERVER class.
+ * --------------------------
+ * The server, or object manager, is the control center of the user interface.
+ * The server object provides a Tcl interpreter calling custom object manager
+ * commands. These are used to define and initialize the user interface, and
+ * execute UI action procedures at runtime.
+ *
+ * reset-server
+ * appInitialize appname, appclass, resources
+ * appExtend new-resources [overwrite]
+ * createObjects [resource-name]
+ * destroyObject object
+ * queryObject object [class [subclass]]
+ * activate
+ * deactivate [unmap]
+ * synchronize
+ * flush
+ *
+ * value = getResource resource-name [default-value [class]]
+ * getResources resource-list
+ *
+ * createMenu menu-name parent item-list
+ * editMenu menu-name parent item-list
+ * destroyMenu menu-name
+ *
+ * createBitmap name width height data
+ * createCursor name source mask fg_color bg_color x_hot y_hot
+ * createPixmap name width height depth fg_color bg_color data
+ * createXPixmap name widget description
+ *
+ * print arg [arg ...] # debug messages
+ * send object message
+ *
+ * postActivateCallback procedure
+ * postDeactivateCallback procedure
+ *
+ * id = postTimedCallback procedure msec [client-data]
+ * deleteTimedCallback id
+ * id = postWorkProc procedure [client-data]
+ * deleteWorkProc id
+ */
+
+#define CB_WORKPROC 1
+#define CB_TIMER 2
+
+/* Callback structure for timer, workproc callbacks. */
+struct _serverCallback {
+ XtPointer obj;
+ int callback_type;
+ char *userproc;
+ char *client_data;
+ union {
+ XtIntervalId intervalId;
+ XtWorkProcId workProcId;
+ } id;
+ struct _serverCallback *next;
+};
+typedef struct _serverCallback serverCallback;
+typedef struct _serverCallback *ServerCallback;
+
+struct serverPrivate {
+ ObmContext obm;
+ ServerCallback cb_head;
+ ServerCallback cb_tail;
+};
+
+typedef struct serverPrivate *ServerPrivate;
+
+struct serverObject {
+ struct obmObjectCore core;
+ struct serverPrivate server;
+};
+
+typedef struct serverObject *ServerObject;
+
+static ObmObject ServerCreate();
+static void ServerDestroy();
+static int ServerEvaluate(), serverQueryObject();
+static int serverCreateMenu(), serverDestroyMenu();
+static int serverAppInitialize(), serverAppExtend(), serverCreateObjects();
+static int serverSend(), serverPrint(), serverDestroyObject();
+static int serverReset(), serverActivate(), serverDeactivate();
+static int serverCreateBitmap(), serverCreatePixmap(), serverCreateCursor();
+static int serverPostActivateCallback(), serverPostDeactivateCallback();
+static int serverPostTimedCallback(), serverPostWorkProc();
+static int serverDeleteTimedCallback(), serverDeleteWorkProc();
+static int serverCreateXPixmap(), serverSynchronize(), serverFlush();
+static int serverGetResource(), serverGetResources();
+static void link_callback(), unlink_callback();
+static void serverTimedProc();
+static Boolean serverWorkProc();
+
+static int editMenu();
+static void menu_popup(), menu_popdown(), menu_popdown_msgHandler();
+static void createMenu(), menuSelect(), build_colorlist();
+static void menu_classInit(), menu_addEntry(), menu_delEntry();
+static void menu_highlight(), menu_unhighlight();
+static Pixmap menu_pullrightBitmap();
+static MenuPtr findMenu();
+extern long strtol();
+
+/* The pull-right bitmap for menus. */
+#define MB_WIDTH 16
+#define MB_HEIGHT 16
+#define MB1_PIXELS \
+ "0x00, 0x00, 0x30, 0x00, 0xf0, 0x00, 0xf0, 0x03, 0xf0, 0x0f, 0xf0, 0x0f,\
+ 0xf0, 0x03, 0xf0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00"
+#define MB2_PIXELS \
+ "0x00, 0x00, 0x30, 0x00, 0xd0, 0x00, 0x10, 0x03, 0x10, 0x0c, 0x10, 0x0c,\
+ 0x10, 0x03, 0xd0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00"
+
+
+/* ServerClassInit -- Initialize the class record for the server class.
+ */
+void
+ServerClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ classrec->ClassDestroy = obmGenericClassDestroy;
+ classrec->Create = (ObmFunc) ServerCreate;
+ classrec->Destroy = ServerDestroy;
+ classrec->Evaluate = ServerEvaluate;
+}
+
+
+/* ServerCreate -- Create an instance of a server object.
+ */
+static ObmObject
+ServerCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register ServerObject obj;
+ register Tcl_Interp *tcl;
+
+ obj = (ServerObject) XtCalloc (1, sizeof (struct serverObject));
+ obm->tcl = tcl = Tcl_CreateInterp();
+ obj->server.obm = obm;
+
+ /* Register server actions. */
+ Tcl_CreateCommand (tcl,
+ "reset-server", serverReset, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "activate", serverActivate, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "deactivate", serverDeactivate, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "synchronize", serverSynchronize, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "flush", serverFlush, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "postActivateCallback", serverPostActivateCallback,
+ (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "postDeactivateCallback", serverPostDeactivateCallback,
+ (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "appInitialize", serverAppInitialize, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "appExtend", serverAppExtend, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createObjects", serverCreateObjects, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "destroyObject", serverDestroyObject, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "queryObject", serverQueryObject, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "send", serverSend, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "print", serverPrint, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "getResource", serverGetResource, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "getResources", serverGetResources, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "postTimedCallback", serverPostTimedCallback,
+ (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteTimedCallback", serverDeleteTimedCallback,
+ (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "postWorkProc", serverPostWorkProc, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteWorkProc", serverDeleteWorkProc, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createBitmap", serverCreateBitmap, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createPixmap", serverCreatePixmap, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createXPixmap", serverCreateXPixmap, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createCursor", serverCreateCursor, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "createMenu", serverCreateMenu, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "editMenu", serverCreateMenu, (ClientData)obj, NULL);
+ Tcl_CreateCommand (tcl,
+ "destroyMenu", serverDestroyMenu, (ClientData)obj, NULL);
+
+ return ((ObmObject) obj);
+}
+
+
+/* ServerDestroy -- Destroy an instance of a server object.
+ */
+static void
+ServerDestroy (object)
+ObmObject object;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ register ServerCallback cb, next;
+
+ /* Destroy the object in the second final call to Destroy. */
+ if (!obj->core.being_destroyed++)
+ return;
+
+ /* Delete any pending timers or work procs. */
+ for (cb = obj->server.cb_head; cb; cb = next) {
+ next = cb->next;
+ switch (cb->callback_type) {
+ case CB_TIMER:
+ XtRemoveTimeOut (cb->id.intervalId);
+ break;
+ case CB_WORKPROC:
+ XtRemoveWorkProc (cb->id.workProcId);
+ break;
+ }
+ XtFree ((char *)cb);
+ }
+
+ obj->server.cb_head = NULL;
+ obj->server.cb_tail = NULL;
+
+ /* Destroy the server interpreter. */
+ if (obm->tcl) {
+ Tcl_DeleteInterp (obm->tcl);
+ obm->tcl = NULL;
+ }
+}
+
+
+/* ServerEvaluate -- Evaluate a server command or message.
+ */
+static int
+ServerEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ static char reset[] = "reset-server";
+ register char *ip;
+
+ /* The command "reset-server" is a special case. This destroys the
+ * current user interface including all objects and widgets. One
+ * of the objects destroyed is the server object including the tcl
+ * interpreter. We can't use a normal Tcl command to implement this
+ * as the server and Tcl data structures will be freed and the rest
+ * of the input command would be lost. Instead, we check for the
+ * reset-server command, which must be the first command in the input
+ * command string, and manually reset things then call Tcl to process
+ * the remainder of the input command. The reset-server command should
+ * be the first command in the server config file used to define the
+ * user interface for a new application. Comments and blank lines
+ * at the head of the file are ignored.
+ */
+ for (ip=command; *ip; ) {
+ while (isspace (*ip))
+ ip++;
+ if (*ip == '#')
+ while (*ip && *ip != '\n')
+ ip++;
+ if (isspace (*ip))
+ ip++;
+ else
+ break;
+ }
+ if (strncmp (ip, reset, strlen(reset)) == 0) {
+ ObmInitialize (obm);
+ obj = (ServerObject) obmFindObject (obm, "Server");
+ }
+
+ /* Now interpret the full message using Tcl. This re-executes the
+ * reset-server command, which will be ignored since this is a no-op
+ * when it occurs within a script. We want to leave the command in
+ * the script as otherwise the line numbers won't be correct.
+ */
+ return (Tcl_Eval (obm->tcl, command));
+}
+
+
+/* serverAppInitialize -- TCL command to initialize the server for a new
+ * application, setting the application name and loading the application
+ * resources.
+ *
+ * Usage: appInitialize appname, appclass, resources
+ */
+static int
+serverAppInitialize (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ register ObmCallback cb;
+
+ char *resource_buf, *resource_list[MAX_RESOURCES];
+ char *appname, *appclass, *resources;
+ int sv_argc, nresources;
+ char **sv_argv;
+ char *ip, *op;
+
+ /* Get arguments. */
+ if (argc >= 2) {
+ strcpy (obm->appname, appname = argv[1]);
+ strcpy (obm->appclass, appclass = argv[2]);
+ } else {
+ appname = "gterm-iraf";
+ appclass = "Xgterm";
+ }
+
+ if (argc >= 3)
+ resources = argv[3];
+ else
+ resources = "";
+
+ /* Get fallback resources. */
+ resource_buf = op = XtMalloc (strlen(resources) + MAX_RESOURCES);
+ resource_list[0] = op;
+ nresources = 0;
+
+ for (ip=resources; *ip; ip++) {
+ while (*ip && (*ip == ' ' || *ip == '\t'))
+ ip++;
+ if (*ip == '\n') {
+ ;
+ } else if (*ip == '!') {
+ while (*ip && *ip != '\n')
+ ip++;
+ } else {
+ while (*ip && *ip != '\n')
+ *op++ = *ip++;
+ *op++ = '\0';
+ nresources++;
+ resource_list[nresources] = op;
+ }
+ }
+ *op++ = '\0';
+ resource_list[nresources] = NULL;
+
+ /* Set fallback resources. */
+ XtAppSetFallbackResources (obm->app_context, resource_list);
+
+ /* Get local copy of argc and argv. */
+ if ((sv_argc = obm->argc) > 0) {
+ sv_argv = (char **) XtMalloc (obm->argc * sizeof(char *));
+ memmove (sv_argv, obm->argv, obm->argc * sizeof(char *));
+ } else
+ sv_argv = obm->argv;
+
+ /* Open the display (initializes the resource database). A separate
+ * display descriptor is used so that we can specify the application
+ * name, class, and resources independently from those of the
+ * application using the object manager.
+ */
+ obm->display = XtOpenDisplay (obm->app_context, (String)NULL,
+ appname, appclass, NULL, 0, &sv_argc, sv_argv);
+ if (obm->display == (Display *)NULL)
+ XtAppError (obm->app_context, "appInitialize: Can't open display.");
+
+ if (obm->debug > 1)
+ XSynchronize (obm->display, True);
+
+ /* Create the top level shell. */
+ obm->toplevel = XtAppCreateShell (appname, appclass,
+ applicationShellWidgetClass, obm->display, (ArgList)NULL, 0);
+ obm->screen = XtScreen (obm->toplevel);
+
+ /* Call the client's display connection callback if any. */
+ for (cb = obm->callback_list; cb; cb = cb->next)
+ if ((cb->callback_type & OBMCB_connect) && cb->u.fcn)
+ (*cb->u.fcn) (cb->client_data, obm->display, obm->toplevel, 1);
+
+ /* Add the toplevel shell to the application's object list. */
+ obmNewObject (obm, "toplevel", "TopLevelShell", NULL, NULL, 0);
+
+ if (obm->argc > 0)
+ XtFree ((char *)sv_argv);
+ XtFree ((char *)resource_buf);
+ XtAppSetFallbackResources (obm->app_context, NULL);
+
+ obm->specified++;
+ return (TCL_OK);
+}
+
+
+/* serverAppExtend -- TCL command to extend the application resource database
+ * to allow for the creation of new widgets loaded since the application was
+ * first started. The 'overwrite' option, if present, says to allow the new
+ * resource strings to overwrite the existing resources, otherwise the older
+ * ones will not be changed.
+ *
+ * Usage: appExtend new-resources [overwrite]
+ */
+static int
+serverAppExtend (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ XrmDatabase old_db, extended_db;
+ Boolean overwrite = False;
+ char *resources;
+
+
+ if (!obm->specified || !obm->display || argc < 2)
+ return (TCL_ERROR);
+
+ /* Get arguments. */
+ resources = argv[1];
+ overwrite = (argc > 2) ? (strcmp (argv[2], "overwrite") == 0) : False;
+
+ /* Get the current fallback resource database. */
+ old_db = XrmGetDatabase (obm->display);
+ if (old_db == (XrmDatabase) NULL)
+ return (TCL_ERROR);
+
+ /* Create a database structure from the resource string. */
+ extended_db = XrmGetStringDatabase (resources);
+ if (extended_db == (XrmDatabase) NULL)
+ return (TCL_ERROR);
+
+ /* Combine the old an new databases. */
+ XrmCombineDatabase (extended_db, &old_db, overwrite);
+
+ /* Update the application resource database. */
+ XrmSetDatabase (obm->display, old_db);
+
+ return (TCL_OK);
+}
+
+
+/* serverCreateObjects -- TCL command to create the tree of UI objects
+ * comprising the user interface. The object tree is defined by a string
+ * valued resource. If no resource is named the default "objects" resource
+ * will be used.
+ *
+ * Usage: createObjects [resource-name]
+ */
+static int
+serverCreateObjects (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register char *ip, *op;
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char name[SZ_NAME], class[SZ_NAME], parent[SZ_NAME];
+ char *objects = NULL;
+ XtResource r;
+
+ r.resource_name = (argc >= 2) ? argv[1] : "objects";
+ r.resource_class = "Objects";
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) NULL;
+
+ /* Get the UI object list. */
+ XtGetApplicationResources (obm->toplevel, &objects, &r, 1, NULL, 0);
+ /* XrmPutFileDatabase (obm->display->db, "zz.list"); */
+
+ /* Parse the objects list and create the objects. Each entry has
+ * the form "parent object-class object-name" with a newline (or
+ * other whitespace) terminating each entry.
+ */
+ for (ip = objects; ip && *ip; ) {
+ /* Get name of parent object. */
+ while (isspace (*ip))
+ ip++;
+ for (op=parent; *ip && !isspace(*ip); )
+ *op++ = *ip++;
+ *op = '\0';
+
+ /* Get object class. */
+ while (isspace (*ip))
+ ip++;
+ for (op=class; *ip && !isspace(*ip); )
+ *op++ = *ip++;
+ *op = '\0';
+
+ /* Get object name. */
+ while (isspace (*ip))
+ ip++;
+ for (op=name; *ip && !isspace(*ip); )
+ *op++ = *ip++;
+ *op = '\0';
+
+ /* Create the new object. */
+ if (*name && *class && *parent)
+ obmNewObject (obm, name, class, parent, NULL, 0);
+
+ while (isspace (*ip))
+ ip++;
+ }
+
+ return (TCL_OK);
+}
+
+
+/* serverDestroyObject -- Destroy an object and all of its children.
+ *
+ * Usage: destroyObject object-name
+ */
+static int
+serverDestroyObject (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char *object_name;
+ ObmObject killobj;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ object_name = argv[1];
+ if ((killobj = obmFindObject (obm, object_name)) == NULL)
+ return (TCL_ERROR);
+ obmDestroyObject (obm, killobj);
+
+ return (TCL_OK);
+}
+
+
+/* serverQueryObject -- Test if the named object exists.
+ *
+ * Usage: queryObject object-name [class [subclass]]
+ *
+ * A nonzero function value is returned if the named object exists. The
+ * class and subclass of the object are optionally returned in the output
+ * variables given on the command line.
+ */
+static int
+serverQueryObject (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char *object_name, *s_class, *s_subclass;
+ ObjClassRec classrec;
+ ObmObject o;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ object_name = argv[1];
+ s_class = (argc > 2) ? argv[2] : NULL;
+ s_subclass = (argc > 3) ? argv[3] : NULL;
+
+ if (o = obmFindObject (obm, object_name)) {
+ classrec = o->core.classrec;
+ if (s_class) {
+ BaseClassRec bp;
+ int i;
+
+ for (i=0; i < OtNClasses; i++) {
+ bp = &baseClasses[i];
+ if (bp->class == classrec->object_type) {
+ Tcl_SetVar (obm->tcl, s_class, bp->name, 0);
+ break;
+ }
+ }
+ }
+ if (s_subclass)
+ Tcl_SetVar (obm->tcl, s_subclass,
+ (classrec->object_type == OtShell) ?
+ "Shell" : classrec->name, 0);
+
+ Tcl_SetResult (obm->tcl, TRUESTR, TCL_STATIC);
+ } else
+ Tcl_SetResult (obm->tcl, FALSESTR, TCL_STATIC);
+
+ return (TCL_OK);
+}
+
+
+/* serverActivate -- Activate the user interface. When called the first
+ * time the user interface is created and activated, thereafter the UI is
+ * merely reactivated (e.g. mapped if unmapped).
+ *
+ * Usage: activate
+ */
+static int
+serverActivate (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ XWMHints hints;
+ register int i;
+ ObmObject child;
+ Widget w;
+
+
+ /* Activate the interface. */
+ ObmActivate (obm);
+
+
+ /* Now set the WM hints for the toplevel shell and any subwindows
+ * of the UI. Certain ICCCM-compliant window managers make assumptions
+ * about how the client windows will handle input focus if it's not
+ * set explicitly, and often the UI is not given the focus.
+ */
+ hints.flags = InputHint | StateHint;
+ hints.input = True;
+ hints.initial_state = NormalState;
+ hints.icon_pixmap = None;
+ hints.icon_window = None;
+ hints.icon_x = hints.icon_y = 0;
+ hints.icon_mask = None;
+ hints.window_group = None;
+
+ XSetWMHints(obm->display, XtWindow(obm->toplevel), &hints);
+
+ obj = (ServerObject) obmFindObject (obm, "toplevel");
+ for (i=0; i < obj->core.nchildren; i++) {
+ child = obj->core.children[i];
+ if (child->core.classrec->object_type == OtShell) {
+ w = widgetGetPointer (child);
+ XSetWMHints(obm->display, XtWindow(w), &hints);
+ }
+ }
+
+ return (TCL_OK);
+}
+
+
+/* serverDeactivate -- Deactivate the user interface. Optionally unmaps the
+ * UI and calls the Obm client back to let it know that the UI has been
+ * deactivated.
+ *
+ * Usage: deactivate [unmap]
+ */
+static int
+serverDeactivate (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+
+ ObmDeactivate (obm, argc >=2 && strcmp(argv[1],"unmap") == 0);
+ return (TCL_OK);
+}
+
+
+/* serverSynchronize -- Synchronize the user interface.
+ *
+ * Usage: synchronize
+ *
+ * Any buffered output to the display is flushed and execution pauses until
+ * the display has caught up. It is rarely necessary to sychronize the
+ * display with the client and this defeats the purpose of command buffering,
+ * hence should be done only when necessary. Try "flush" below first.
+ */
+static int
+serverSynchronize (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+
+ XSync (obm->display, False);
+ while (XtAppPending (obm->app_context))
+ XtAppProcessEvent (obm->app_context, XtIMAll);
+
+ return (TCL_OK);
+}
+
+
+/* serverFlush -- Flush output to the user interface.
+ *
+ * Usage: flush
+ *
+ * Any buffered output to the display is flushed to the display and
+ * execution continues.
+ */
+static int
+serverFlush (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+
+ XFlush (obm->display);
+
+ return (TCL_OK);
+}
+
+
+/* serverPostActivateCallback -- Post a callback procedure to be called
+ * when the UI is activated. The UI is activated when it is first
+ * downloaded to server, but it may also be activated (reactivated) after
+ * the application has exited and is later restarted, or when the UI
+ * is deactivated and reactivated. Note that the UI state vis-a-vis the
+ * external world (client application) may no longer be accurate after
+ * it has been idle for a time and then reactivated.
+ *
+ * Usage: postActivateCallback <procedure>
+ */
+static int
+serverPostActivateCallback (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ register ObmCallback cb;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if (!(cb = obmAddCallback (&obm->callback_list)))
+ return (TCL_ERROR);
+
+ cb->callback_type = OBMUI_activate;
+ strncpy (cb->name, argv[1], SZ_NAME);
+
+ return (TCL_OK);
+}
+
+
+/* serverPostDeactivateCallback -- Post a callback procedure to be called
+ * when the UI is deactivated.
+ *
+ * Usage: postDeactivateCallback <procedure>
+ */
+static int
+serverPostDeactivateCallback (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ register ObmCallback cb;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ if (!(cb = obmAddCallback (&obm->callback_list)))
+ return (TCL_ERROR);
+
+ cb->callback_type = OBMUI_deactivate;
+ strncpy (cb->name, argv[1], SZ_NAME);
+
+ return (TCL_OK);
+}
+
+
+/* serverSend -- Send a message to an object. The object interprets the
+ * message and returns a function value as the string result of the TCL
+ * command.
+ *
+ * Usage: send <object> <message>
+ */
+static int
+serverSend (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ int status;
+
+ /* The object which interprets the message leaves the string result,
+ * if any, directly in the server tcl result string.
+ */
+ if (argc == 3)
+ status = ObmDeliverMsg (obm, argv[1], argv[2]);
+ else {
+ char *message = Tcl_Merge (argc-2, &argv[2]);
+ status = ObmDeliverMsg (obm, argv[1], message);
+ free ((char *)message);
+ }
+
+ return (status);
+}
+
+
+/* serverPrint -- Print a string on the standard output. This is used mainly
+ * for debugging user interfaces.
+ *
+ * Usage: print arg [arg ...]
+ */
+static int
+serverPrint (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+
+ if (argc >= 2) {
+ char *message = Tcl_Concat (argc-1, &argv[1]);
+ printf ("%s\n", message);
+ fflush (stdout);
+ free ((char *)message);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* serverReset -- The "reset-server" command is implemented as a special
+ * case in ServerEvaluate. After doing a true reset ServerEvaluate calls
+ * Tcl_Eval to evaluate the full message which still contains the reset-server
+ * command. We want to ignore this the second time, so we treat the command
+ * here as a no-op.
+ *
+ * Usage: reset-server
+ *
+ * Note: for reset-server to be recognized by ServerEvaluate and really reset
+ * things, it must be the first command in a message to the server.
+ */
+static int
+serverReset (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ return (TCL_OK);
+}
+
+
+/* serverGetResource -- Get the string value of the specified application
+ * resource (window system parameter). This allows use of the resource
+ * mechanism to supply default values for GUI parameters.
+ *
+ * Usage: value = getResource resource-name [class [default-value]]
+ *
+ * In the simplest case one merely requests a resource by name and the
+ * string value is returned as the function value. If the resource has
+ * an entry in the fallback resources for the application (appInitialize
+ * resource list) then a value is guaranteed to be returned.
+ *
+ * If the Class name for the resource is given then a class default value
+ * will be returned if no entry is found for the name resource instance.
+ * This is useful when there are a number of resources of the same type
+ * (same class). If most or all resources in the same class have the same
+ * default value one need only make one entry for the Class in the application
+ * defaults resource list. It is up to the application developer to define
+ * the class name of a resource - the class name can be any string. Examples
+ * are "Font", "Cursor", etc. By convention the first character of a class
+ * name is capitalized, while instance names begin with a lower case letter.
+ *
+ * If there is an entry for the named resource in the resource list passed
+ * to appInitialize then a value string is guaranteed to be returned. This
+ * will be either the appInitialize default, or a value specified by the
+ * system or the user in an X resources file. If one is not certain a
+ * default value is defined somewhere, a default value should be specified
+ * in the getResource call as shown above.
+ *
+ * See also getResources, used to get multiple resources in one call.
+ */
+static int
+serverGetResource (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char *resource_name, *class_name, *default_value;
+ char *value = NULL;
+ XtResource r;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ resource_name = argv[1];
+ class_name = (argc > 2) ? argv[2] : XtCString;
+ default_value = (argc > 3) ? argv[3] : "";
+
+ r.resource_name = resource_name;
+ r.resource_class = class_name;
+ r.resource_type = XtRString;
+ r.resource_size = sizeof (char *);
+ r.resource_offset = 0;
+ r.default_type = XtRString;
+ r.default_addr = (caddr_t) default_value;
+
+ XtGetApplicationResources (obm->toplevel, &value, &r, 1, NULL, 0);
+ Tcl_SetResult (tcl, value, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* serverGetResources -- Get the string values of a list of resources.
+ *
+ * Usage: getResources resource-list
+ * e.g.
+ * getResources {
+ * { resource [variable class [default-value]]] }
+ * { resource [variable class [default-value]]] }
+ * (etc.)
+ * }
+ *
+ * The resource list is a list of resource descriptions. Each resource
+ * entry must give at least the resource name. If no Tcl variable is named
+ * the resource name will be used and this variable will be set to the
+ * resource value. The class name and default value fields are optional.
+ */
+static int
+serverGetResources (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ register XtResource *r;
+ XtResource resources[MAX_RESOURCES];
+ char *resource_name, *class_name, *default_value;
+ char *resource_list, *variable;
+ char **items, **fields;
+ int nitems, nfields;
+ char buf[SZ_NUMBER];
+ int item, i;
+
+ typedef struct {
+ char *variable;
+ char *value;
+ char *item_list;
+ } Value;
+ Value values[MAX_RESOURCES];
+
+ if (argc < 2) {
+ tcl->result = "missing resource-list argument";
+ return (TCL_ERROR);
+ } else
+ resource_list = argv[1];
+
+ if (Tcl_SplitList (tcl, resource_list, &nitems, &items) != TCL_OK) {
+ tcl->result = "could not parse resource list";
+ return (TCL_ERROR);
+ } else if (nitems > MAX_MENUITEMS)
+ nitems = MAX_MENUITEMS;
+
+ for (item=0; item < nitems; item++) {
+ if (Tcl_SplitList (tcl, items[item], &nfields, &fields) != TCL_OK) {
+err: sprintf (buf, "bad item '%d' in resource list", item + 1);
+ Tcl_AppendResult (tcl, buf, NULL);
+ for (i=0; i < item; i++)
+ free (values[item].item_list);
+ return (TCL_ERROR);
+ }
+
+ if (nfields < 1)
+ goto err;
+
+ resource_name = fields[0];
+ variable = (nfields > 1) ? fields[1] : fields[0];
+ class_name = (nfields > 2) ? fields[2] : XtCString;
+ default_value = (nfields > 3) ? fields[3] : "";
+
+ r = &resources[item];
+ r->resource_name = resource_name;
+ r->resource_class = class_name;
+ r->resource_type = XtRString;
+ r->resource_size = sizeof (char *);
+ r->resource_offset = (unsigned int) &(((Value *)NULL)[item].value);
+ r->default_type = XtRString;
+ r->default_addr = (caddr_t) default_value;
+
+ values[item].variable = variable;
+ values[item].item_list = (char *) fields;
+ }
+
+ XtGetApplicationResources (obm->toplevel,
+ (XtPointer) values, resources, nitems, NULL, 0);
+
+ for (item=0; item < nitems; item++) {
+ if (Tcl_SetVar (tcl,
+ values[item].variable, values[item].value, 0) == NULL) {
+ fprintf (stderr,
+ "Warning (getResources): cannot set value of %s\n",
+ values[item].variable);
+ }
+ free (values[item].item_list);
+ }
+ free ((char *) items);
+
+ return (TCL_OK);
+}
+
+
+/* serverPostTimedCallback -- Post a callback to call the named procedure
+ * back after a specified delay in milliseconds.
+ *
+ * Usage: id = postTimedCallback procedure msec [client-data]
+ *
+ * After the specified delay the user callback procedure will be called
+ * with client_data (if given) as the single argument. Only one call will
+ * be made; the client must repost the callback in each call if the procedure
+ * is to be repeatedly executed.
+ *
+ * An ID value is returned which may be passed to deleteTimedCallback to
+ * delete the timer. If a zero or negative time interval is requested no
+ * timer will be set and zero will be returned as the timer ID.
+ *
+ */
+static int
+serverPostTimedCallback (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char *userproc, *client_data;
+ unsigned long interval;
+ char buf[SZ_NUMBER];
+ ServerCallback cb;
+ int nchars;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ /* Get arguments. */
+ userproc = argv[1];
+ interval = atoi (argv[2]);
+ client_data = (argc > 3) ? argv[3] : NULL;
+
+ if (interval > 0) {
+ /* Allocate and initialize the callback structure. */
+ nchars = sizeof(serverCallback) + strlen(userproc)+1 +
+ (client_data ? strlen(client_data)+1 : 0);
+ if (!(cb = (ServerCallback) XtCalloc (nchars,1)))
+ return (TCL_ERROR);
+
+ cb->obj = (XtPointer) obj;
+ cb->userproc = (char *)cb + sizeof(serverCallback);
+ cb->client_data = client_data ?
+ cb->userproc+strlen(userproc)+1 : NULL;
+ cb->callback_type = CB_TIMER;
+ cb->next = NULL;
+
+ strcpy (cb->userproc, userproc);
+ if (client_data)
+ strcpy (cb->client_data, client_data);
+
+ cb->id.intervalId = XtAppAddTimeOut (obm->app_context,
+ interval, serverTimedProc, (XtPointer)cb);
+ link_callback (&obj->server, cb);
+ } else
+ cb = NULL;
+
+ sprintf (buf, "0x%lx", cb);
+ Tcl_SetResult (tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* serverTimedProc -- Xt callback procedure for interval timers.
+ */
+static void
+serverTimedProc (cb_ptr, id)
+XtPointer cb_ptr;
+XtIntervalId *id;
+{
+ register ServerCallback cb = (ServerCallback) cb_ptr;
+ register ServerObject obj = (ServerObject) cb->obj;
+ ObmContext obm = obj->server.obm;
+ int status;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->userproc, " ",
+ cb->client_data ? cb->client_data : " ",
+ NULL);
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->userproc,
+ errstr ? errstr : obm->tcl->result);
+ }
+
+ unlink_callback (&obj->server, cb);
+/* XtFree ((char *)cb);*/
+}
+
+
+/* serverDeleteTimedCallback -- Delete a timer callback procedure. This
+ * procedure is typically used to break a timer loop, where the timer
+ * procedure repeatedly reposts itself at the end of each interval.
+ *
+ * Usage: deleteTimedCallback id
+ *
+ * The ID string is returned by postTimedCallback when a timer is posted.
+ */
+static int
+serverDeleteTimedCallback (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ ServerCallback cb;
+ XtIntervalId id;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ if (cb = (ServerCallback) strtol (argv[1], (char **)NULL, 16)) {
+ XtRemoveTimeOut (cb->id.intervalId);
+ unlink_callback (&obj->server, cb);
+ XtFree ((char *)cb);
+ }
+ return (TCL_OK);
+}
+
+
+/* serverPostWorkProc -- Post a callback for a procedure to be called when
+ * the server is idle. Work procedures are used to perform computations in
+ * the background while the user interface remains active and able to respond
+ * to input events. This works only if the user work procedure does its job
+ * in small increments, doing only a small amount of processing in each call.
+ * The work procedure will be called repeatedly until it returns a status
+ * indicating that it has finished its task.
+ *
+ * Usage: id = postWorkProc procedure [client-data]
+ *
+ * When the server has nothing else to do the user work procedure will be
+ * called with client_data (if given) as the single argument. The work
+ * procedure should return the string "done" when all processing is finished,
+ * or any other string if the procedure is to be called again.
+ *
+ * An ID value is returned which may be passed to deleteWorkProc to
+ * delete the work procedure.
+ */
+static int
+serverPostWorkProc (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ register ObmContext obm = obj->server.obm;
+ char *userproc, *client_data;
+ char buf[SZ_NUMBER];
+ ServerCallback cb;
+ int nchars;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ /* Get arguments. */
+ userproc = argv[1];
+ client_data = (argc > 2) ? argv[2] : NULL;
+
+ /* Allocate and initialize the callback structure. */
+ nchars = sizeof(serverCallback) + strlen(userproc)+1 +
+ (client_data ? strlen(client_data)+1 : 0);
+ if (!(cb = (ServerCallback) XtMalloc (nchars)))
+ return (TCL_ERROR);
+
+ cb->obj = (XtPointer) obj;
+ cb->userproc = (char *)cb + sizeof(serverCallback);
+ cb->client_data = client_data ? cb->userproc+strlen(userproc)+1 : NULL;
+ cb->callback_type = CB_WORKPROC;
+ cb->next = NULL;
+
+ strcpy (cb->userproc, userproc);
+ if (client_data)
+ strcpy (cb->client_data, client_data);
+
+ cb->id.workProcId = XtAppAddWorkProc (obm->app_context,
+ serverWorkProc, (XtPointer)cb);
+ link_callback (&obj->server, cb);
+
+ sprintf (buf, "0x%lx", cb);
+ Tcl_SetResult (tcl, buf, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* serverWorkProc -- Xt callback procedure for work procedures.
+ */
+static Boolean
+serverWorkProc (cb_ptr)
+XtPointer cb_ptr;
+{
+ register ServerCallback cb = (ServerCallback) cb_ptr;
+ register ServerObject obj = (ServerObject) cb->obj;
+ register ObmContext obm = obj->server.obm;
+ Boolean done;
+ int status;
+
+ status = Tcl_VarEval (obm->tcl,
+ cb->userproc, " ",
+ cb->client_data ? cb->client_data : " ",
+ NULL);
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->userproc,
+ errstr ? errstr : obm->tcl->result);
+ done = True;
+ } else
+ done = (strcmp (obm->tcl->result, "done") == 0) ? True : False;
+
+ if (done) {
+ unlink_callback (&obj->server, cb);
+ XtFree ((char *)cb);
+ }
+
+ return (done);
+}
+
+
+/* serverDeleteWorkProc -- Delete a work callback procedure.
+ *
+ * Usage: deleteWorkProc id
+ *
+ * The ID string is returned by postWorkProc when a work procedure is
+ * posted.
+ */
+static int
+serverDeleteWorkProc (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register ServerObject obj = (ServerObject) object;
+ ServerCallback cb;
+ XtIntervalId id;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ cb = (ServerCallback) strtol (argv[1], (char **)NULL, 16);
+ XtRemoveWorkProc (cb->id.workProcId);
+ unlink_callback (&obj->server, cb);
+ XtFree ((char *)cb);
+ return (TCL_OK);
+}
+
+
+/* link_callback -- Link a callback descriptor into the global server
+ * callback list.
+ */
+static void
+link_callback (server, cb)
+register ServerPrivate server;
+register ServerCallback cb;
+{
+ if (!server->cb_head) {
+ server->cb_head = cb;
+ server->cb_tail = cb;
+ } else {
+ server->cb_tail->next = cb;
+ server->cb_tail = cb;
+ }
+}
+
+
+/* unlink_callback -- Unlink a callback descriptor from the global server
+ * callback list.
+ */
+static void
+unlink_callback (server, cb)
+register ServerPrivate server;
+register ServerCallback cb;
+{
+ register ServerCallback cp;
+
+ if (cb == server->cb_head) {
+ if (!(server->cb_head = cb->next))
+ server->cb_tail = NULL;
+ } else {
+ for (cp = server->cb_head; cp && cp->next != cb; cp = cp->next)
+ ;
+ if (cp) {
+ cp->next = cb->next;
+ if (cb == server->cb_tail)
+ server->cb_tail = cp;
+ }
+ }
+}
+
+
+/* serverCreateBitmap -- Create a named bitmap. This replaces any old bitmap
+ * of the same name. The new bitmap is cached in server memory; when a widget
+ * bitmap resource is set, the bitmap cache will be searched for the named
+ * bitmap before asking Xlib to find the bitmap.
+ *
+ * Usage: createBitmap name width height data
+ *
+ * e.g.,
+ * createBitmap foo 16 16 {
+ * 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ * 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ * 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+ */
+static int
+serverCreateBitmap (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ char *name, *pixels;
+ int width, height;
+ int status;
+
+ if (argc < 5)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ width = atoi (argv[2]);
+ height = atoi (argv[3]);
+ pixels = argv[4];
+
+ status = createBitmap (obm, name, width, height, pixels);
+ return (status == OK ? TCL_OK : TCL_ERROR);
+}
+
+
+/* createBitmap -- Create a bitmap of the indicated size and add it to the
+ * pixmap cache.
+ */
+createBitmap (obm, name, width, height, pixels)
+ObmContext obm;
+char *name;
+int width, height;
+char *pixels;
+{
+ register char *ip, *op;
+ register ObjList lp, last_lp;
+ char numbuf[32], *data, *dp;
+ Icon *icon;
+ int nchars;
+
+ if (!obm->specified || !obm->display)
+ return (TCL_ERROR);
+
+ /* Check if bitmap is already in cache. */
+ for (last_lp = lp = obm->pixmap_cache; lp; lp = lp->next) {
+ if (strcmp (name, lp->name) == 0)
+ break;
+ last_lp = lp;
+ }
+
+ /* Get an empty bitmap descriptor. */
+ if (lp) {
+ if (lp->ptr)
+ freeIcon (obm, (Icon *) lp->ptr);
+ } else {
+ lp = (ObjList) XtMalloc (sizeof (struct objList));
+ if (last_lp)
+ last_lp->next = lp;
+ else
+ obm->pixmap_cache = lp;
+ strcpy (lp->name, name);
+ lp->next = NULL;
+ }
+
+ /* Get bitmap data. */
+ data = (char *) XtCalloc (nchars = (width * height), 1);
+ for (dp=data, ip=pixels; *ip; ) {
+ while (isspace(*ip) || *ip == ',')
+ ip++;
+ for (op=numbuf; *ip && !(isspace(*ip) || *ip == ','); )
+ *op++ = *ip++;
+ *op++ = '\0';
+ if (--nchars >= 0)
+ *dp++ = strtol (numbuf, NULL, 0);
+ }
+
+ /* Create the bitmap. */
+ if (!(icon = (Icon *) XtCalloc (1, sizeof (*icon))))
+ return (TCL_ERROR);
+ icon->pixmap = XCreateBitmapFromData (obm->display,
+ RootWindowOfScreen (obm->screen), data, width, height);
+ lp->ptr = (caddr_t) icon;
+
+ XtFree ((char *)data);
+ return (OK);
+}
+
+
+/* findBitmap -- Search the bitmap cache for the named bitmap. Note that
+ * a bitmap is a pixmap of depth one, hence bitmaps are stored in the pixmap
+ * cache.
+ */
+Pixmap
+findBitmap (obm, name)
+ObmContext obm;
+char *name;
+{
+ return (findPixmap (obm, name));
+}
+
+
+/* serverCreatePixmap -- Create a named pixmap. This replaces any old pixmap
+ * of the same name. The new pixmap is cached in server memory; when a widget
+ * pixmap resource is set, the pixmap cache will be searched for the named
+ * pixmap before asking Xlib to find the pixmap.
+ *
+ * Usage: createPixmap name width height depth fg_color bg_color data
+ *
+ * e.g.,
+ * createPixmap foo 16 16 8 black white {
+ * 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
+ * 0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
+ * 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
+ */
+static int
+serverCreatePixmap (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ int width, height, depth;
+ char *name, *pixels;
+ unsigned long fg, bg;
+ int status;
+
+ if (argc < 8)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ width = atoi (argv[2]);
+ height = atoi (argv[3]);
+ depth = atoi (argv[4]);
+ pixels = argv[7];
+
+ /* Get fg_color pixel value. */
+ if (isdigit (*argv[5]))
+ fg = strtol (argv[5], NULL, 0);
+ else {
+ XrmValue from, to;
+ from.size = strlen (argv[5]) + 1;
+ from.addr = argv[5];
+ to.addr = (caddr_t) &fg;
+ to.size = sizeof(fg);
+
+ if (!XtConvertAndStore (obm->toplevel,
+ XtRString, &from, XtRPixel, &to))
+ fg = BlackPixelOfScreen (obm->screen);
+ }
+
+ /* Get bg_color pixel value. */
+ if (isdigit (*argv[6]))
+ bg = strtol (argv[6], NULL, 0);
+ else {
+ XrmValue from, to;
+ from.size = strlen (argv[6]) + 1;
+ from.addr = argv[6];
+ to.addr = (caddr_t) &bg;
+ to.size = sizeof(bg);
+
+ if (!XtConvertAndStore (obm->toplevel,
+ XtRString, &from, XtRPixel, &to))
+ bg = WhitePixelOfScreen (obm->screen);
+ }
+
+ status = createPixmap (obm, name, width,height,8, NULL, pixels, fg,bg);
+ return (status == OK ? TCL_OK : TCL_ERROR);
+}
+
+
+/* createPixmap -- Create a pixmap of the indicated size and add it to the
+ * pixmap cache. If PIXMAP is non-null the existing pixmap is merely entered
+ * into the pixmap cache. Otherwise, if PIXELS is NULL an empty pixmap is
+ * created, otherwise PIXELS points to a character string containing the
+ * pixmap data in bitmap format, and BG and FG give the background and
+ * foreground colors.
+ */
+createPixmap (obm, name, width, height, depth, pixmap, pixels, bg, fg)
+ObmContext obm;
+char *name;
+int width, height, depth;
+Pixmap pixmap;
+char *pixels;
+unsigned long fg, bg;
+{
+ register char *ip, *op;
+ register ObjList lp, last_lp;
+ char numbuf[32], *data, *dp;
+ Icon *icon;
+ int nchars;
+
+ if (!obm->specified || !obm->display)
+ return (TCL_ERROR);
+
+ /* Check if pixmap is already in cache. */
+ for (last_lp = lp = obm->pixmap_cache; lp; lp = lp->next) {
+ if (strcmp (name, lp->name) == 0)
+ break;
+ last_lp = lp;
+ }
+
+ /* Get an empty pixmap descriptor. */
+ if (lp) {
+ if (lp->ptr)
+ freeIcon (obm, (Icon *) lp->ptr);
+ } else {
+ lp = (ObjList) XtMalloc (sizeof (struct objList));
+ if (last_lp)
+ last_lp->next = lp;
+ else
+ obm->pixmap_cache = lp;
+ strcpy (lp->name, name);
+ lp->next = NULL;
+ }
+
+ if (!(icon = (Icon *) XtCalloc (1, sizeof (*icon))))
+ return (TCL_ERROR);
+
+ /* Get pixmap data. */
+ if (pixmap) {
+ icon->pixmap = pixmap;
+ } else {
+ if (pixels) {
+ data = (char *) XtCalloc (nchars = (width * height), 1);
+ for (dp=data, ip=pixels; *ip; ) {
+ while (isspace(*ip) || *ip == ',')
+ ip++;
+ for (op=numbuf; *ip && !(isspace(*ip) || *ip == ','); )
+ *op++ = *ip++;
+ *op++ = '\0';
+ if (--nchars >= 0)
+ *dp++ = strtol (numbuf, NULL, 0);
+ }
+
+ /* Create the pixmap. */
+ icon->pixmap = XCreatePixmapFromBitmapData (obm->display,
+ RootWindowOfScreen(obm->screen), data, width,height, fg,bg,
+ depth);
+
+ } else {
+ /* Create the pixmap. */
+ icon->pixmap = XCreatePixmap (obm->display,
+ RootWindowOfScreen(obm->screen), width, height, depth);
+ }
+ }
+
+ lp->ptr = (caddr_t) icon;
+ XtFree ((char *)data);
+
+ return (OK);
+}
+
+
+/* serverCreateXPixmap -- Create a pixmap of the given name. The pixmap is
+ * specified in XPM format which provides much better support for color than
+ * the simpler format used by createPixmap.
+ *
+ * The new pixmap replaces any old pixmap of the same name. The new pixmap
+ * is cached in server memory; when a widget pixmap resource is set, the
+ * pixmap cache will be searched for the named pixmap before asking Xlib to
+ * find the pixmap.
+ *
+ * Usage: createXPixmap name widget description
+ *
+ * where "name" is the name of the pixmap to be created, "widget" is the
+ * name of a widget object to be used to search for pixel resources (to color
+ * the pixmap), and "description" is the XPM format description of the pixmap.
+ *
+ * For example:
+ *
+ * createXPixmap empty_diamond font1 {
+ * [* XPM *]
+ * static char * diamond0c [] = {
+ * [* width height ncolors cpp [x_hot y_hot] *]
+ * "17 17 3 1 0 0",
+ * [* colors *]
+ * " s none m none c none",
+ * ". s topShadowColor m white c #c8c8c8c8c8c8",
+ * "X s bottomShadowColor m black c #646464646464",
+ * [* pixels *]
+ * " ",
+ * " ",
+ * " ... ",
+ * " .. .. ",
+ * " .. .. ",
+ * " .. .. ",
+ * " .. .. ",
+ * " .. .. ",
+ * " . . ",
+ * " XX XX ",
+ * " XX XX ",
+ * " XX XX ",
+ * " XX XX ",
+ * " XX XX ",
+ * " XXX ",
+ * " ",
+ * " "};
+ * }
+ *
+ * In the above the C style comments have been replaced by [* ... *] to avoid
+ * prematurely terminating the C comment you are reading. The actual text
+ * input to createXPixmap should use C style comments, exactly as in the XPM
+ * file.
+ *
+ * The pixmap is specified in XPM format as an array of strings. C style
+ * coments, commas, and whitespace are ignored (but are permitted, to allow
+ * XPM files to be directly included). The XPM format is fully defined in
+ * the XPM documentation, but there is not really that much to it, so we
+ * summarize it here. The advantage of the XPM format is that it uses a
+ * visual ascii representation of the pixmap, and it provides good support
+ * for colored pixmaps, using characters to indicate the color. The fields
+ * of the color description are as follows:
+ *
+ * character character used in "pixels" to signify color (arbitrary)
+ * s resource name used in application to override color
+ * m default color on monochrome screens
+ * g4 for 4-level grayscale screens
+ * g for grayscale with more than 4 levels
+ * c for color screens
+ *
+ * An important feature of createXPixmap is the reference widget. When the
+ * pixmap is created the resource list of the named reference widget will be
+ * searched for any resources that specify colors. If the resource name for
+ * a color resource matches the "s" name given for a color in the XPM pixmap
+ * description, then the widget-specific color will be used. This allows
+ * resources to be used to specify the colors for a pixmap on a per-widget
+ * basis. If a dummy widget-object name is given (e.g. "none") or no matching
+ * resources are found, the default colors will be used. Any widget object
+ * that has color resources may be used for the reference widget (it doesn't
+ * have to be the widget which will later use the pixmap).
+ *
+ * A pixmap created with createXPixmap may be used with the widget-class "set"
+ * command to set the value of any Pixmap or Icon class widget resource.
+ */
+static int
+serverCreateXPixmap (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ char *name, *widget, *description;
+ int status;
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ widget = argv[2];
+ description = argv[3];
+ while (isspace (*description))
+ description++;
+
+ status = createXPixmap (obm, name, widget, description);
+ return (status == OK ? TCL_OK : TCL_ERROR);
+}
+
+
+/* createXPixmap -- Create a pixmap defined in an XPM format description and
+ * add it to the pixmap cache. DESCRIPTION points to a character string
+ * containing the pixmap description in XPM format. A reference widget object
+ * may be given to associate color resources with the pixmap.
+ */
+createXPixmap (obm, name, widget, description)
+ObmContext obm;
+char *name;
+char *widget;
+char *description;
+{
+ register char *ip, *op;
+ register ObjList lp, last_lp;
+ XpmImage image;
+ ObmObject obj;
+ String *data;
+ Icon *icon;
+ int status;
+ Widget w;
+
+ if (!obm->specified || !obm->display)
+ return (TCL_ERROR);
+
+ /* Get reference widget if any. */
+ w = NULL;
+ if (obj = obmFindObject (obm, widget, obm->toplevel))
+ w = widgetGetPointer (obj);
+
+ /* Create the pixmap (actually icon).
+ */
+ status = XpmCreateXpmImageFromBuffer (description, &image, NULL, NULL);
+ if (status != XpmSuccess)
+ return (TCL_ERROR);
+ XpmCreateDataFromXpmImage (&data, &image, NULL);
+
+ if (data) {
+ static XpmColorSymbol table[MAXCOLORSYM];
+ Cardinal n;
+
+ if (!(icon = (Icon *) XtCalloc (1, sizeof(*icon))))
+ return (TCL_ERROR);
+
+ build_colorlist (w, table, XtNumber(table), &n);
+ icon->attributes.colorsymbols = table;
+ icon->attributes.numsymbols = n;
+ icon->attributes.valuemask = XpmColorSymbols;
+
+ XpmCreatePixmapFromData (obm->display,
+ RootWindowOfScreen(obm->screen), data,
+ &icon->pixmap, &icon->mask, &icon->attributes);
+
+ XtFree ((String) data);
+/* XtFree ((String) table);*/
+ XpmFreeXpmImage (&image);
+
+ } else {
+ XpmFreeXpmImage (&image);
+ return (TCL_ERROR);
+ }
+
+ /* Check if pixmap is already in cache. */
+ for (last_lp = lp = obm->pixmap_cache; lp; lp = lp->next) {
+ if (strcmp (name, lp->name) == 0)
+ break;
+ last_lp = lp;
+ }
+
+ /* Get an empty pixmap descriptor. */
+ if (lp) {
+ if (lp->ptr)
+ freeIcon (obm, (Icon *) lp->ptr);
+ } else {
+ lp = (ObjList) XtMalloc (sizeof (struct objList));
+ if (last_lp)
+ last_lp->next = lp;
+ else
+ obm->pixmap_cache = lp;
+ strcpy (lp->name, name);
+ lp->next = NULL;
+ }
+
+ lp->ptr = (caddr_t) icon;
+ return (OK);
+}
+
+
+/* build_colorlist -- Get a list of all the color resources defined by a
+ * widget. This looks through all the resources for resources that specify
+ * a color (Pixel). All such resources and their values are entered in the
+ * output table.
+ *
+ * To get at the resource value, the resource_offset (an unsigned int) must be
+ * added to the base address of the widget. The widget pointer is first
+ * converted to an unsigned long, tehn the offset is added to it and the result
+ * is converted back to a pointer, in this case a pointer to a Pixel.
+ *
+ * This code is based on build_colortable from icon.c in the FWF sources.
+ */
+static void
+build_colorlist (w, table, size, n)
+Widget w;
+register XpmColorSymbol *table;
+Cardinal size;
+Cardinal *n;
+{
+ Cardinal nres, i;
+ XtResourceList res;
+
+ *n = 0;
+ XtGetResourceList (XtClass(w), &res, &nres);
+ for (i=0; i < nres; i++)
+ if (strcmp(res[i].resource_type, XtRPixel) == 0 && *n < size) {
+ table[*n].name = res[i].resource_name;
+ table[*n].value = NULL;
+ table[*n].pixel =
+ * (Pixel*) ((unsigned long) w + res[i].resource_offset);
+ (*n)++;
+ }
+ if (res)
+ XtFree ((char *)res); /* MF037 */
+}
+
+
+/* findPixmap -- Search the pixmap cache for the named pixmap.
+ */
+Pixmap
+findPixmap (obm, name)
+ObmContext obm;
+char *name;
+{
+ register ObjList lp;
+
+ for (lp = obm->pixmap_cache; lp; lp = lp->next)
+ if (lp->ptr && strcmp (name, lp->name) == 0)
+ return (((Icon *)lp->ptr)->pixmap);
+
+ return ((Pixmap) NULL);
+}
+
+
+/* findIcon -- Search the pixmap cache for the named icon.
+ */
+Icon *
+findIcon (obm, name)
+ObmContext obm;
+char *name;
+{
+ register ObjList lp;
+
+ for (lp = obm->pixmap_cache; lp; lp = lp->next)
+ if (lp->ptr && strcmp (name, lp->name) == 0)
+ return ((Icon *) lp->ptr);
+
+ return ((Icon *) NULL);
+}
+
+
+/* freeIcon -- Free an icon descriptor (pixmap list).
+ */
+void
+freeIcon (obm, icon)
+register ObmContext obm;
+register Icon *icon;
+{
+ if (icon->pixmap)
+ XFreePixmap (obm->display, icon->pixmap);
+ if (icon->mask)
+ XFreePixmap (obm->display, icon->mask);
+ XtFree ((char *) icon);
+}
+
+
+/* serverCreateCursor -- Create a cursor from bitmap data. The cursor is
+ * entered into the server's cursor cache and will override any existing
+ * entry of the same name.
+ *
+ * Usage: createCursor name source mask fg_color bg_color x_hot y_hot
+ * e.g.,
+ * createCursor foo bitmap1 bitmap2 black white 8 8
+ *
+ * The named bitmaps must be created first with createBitmap.
+ */
+static int
+serverCreateCursor (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ register ObjList lp, last_lp;
+ XColor fg_color, bg_color;
+ unsigned long fg, bg;
+ Pixmap source, mask;
+ Colormap colormap;
+ int x_hot, y_hot;
+ char *name;
+
+ if (!obm->specified || !obm->display)
+ return (TCL_ERROR);
+
+ if (argc < 8)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ source = findPixmap (obm, argv[2]);
+ mask = findPixmap (obm, argv[3]);
+ x_hot = atoi (argv[6]);
+ y_hot = atoi (argv[7]);
+
+ if (!source)
+ return (TCL_ERROR);
+
+ colormap = XDefaultColormapOfScreen (obm->screen);
+
+ /* Get fg_color pixel value. */
+ if (isdigit (*argv[4]))
+ fg = strtol (argv[4], NULL, 0);
+ else {
+ XrmValue from, to;
+ from.size = strlen (argv[4]) + 1;
+ from.addr = argv[4];
+ to.addr = (caddr_t) &fg;
+ to.size = sizeof(fg);
+
+ if (!XtConvertAndStore (obm->toplevel,
+ XtRString, &from, XtRPixel, &to))
+ fg = BlackPixelOfScreen (obm->screen);
+
+ fg_color.pixel = fg;
+ XQueryColor (obm->display, colormap, &fg_color);
+ }
+
+ /* Get bg_color pixel value. */
+ if (isdigit (*argv[5]))
+ bg = strtol (argv[5], NULL, 0);
+ else {
+ XrmValue from, to;
+ from.size = strlen (argv[5]) + 1;
+ from.addr = argv[5];
+ to.addr = (caddr_t) &bg;
+ to.size = sizeof(bg);
+
+ if (!XtConvertAndStore (obm->toplevel,
+ XtRString, &from, XtRPixel, &to))
+ bg = WhitePixelOfScreen (obm->screen);
+
+ bg_color.pixel = bg;
+ XQueryColor (obm->display, colormap, &bg_color);
+ }
+
+ /* Check if cursor is already in cache. */
+ for (last_lp = lp = obm->cursor_cache; lp; lp = lp->next) {
+ if (strcmp (name, lp->name) == 0)
+ break;
+ last_lp = lp;
+ }
+
+ /* Get an empty cursor descriptor. */
+ if (lp) {
+ if (lp->ptr)
+ XFreeCursor (obm->display, (Cursor)lp->ptr);
+ } else {
+ lp = (ObjList) XtMalloc (sizeof (struct objList));
+ if (last_lp)
+ last_lp->next = lp;
+ else
+ obm->cursor_cache = lp;
+ strcpy (lp->name, name);
+ lp->next = NULL;
+ }
+
+ /* Create the cursor. */
+ lp->ptr = (caddr_t) XCreatePixmapCursor (obm->display,
+ source, mask, &fg_color, &bg_color, x_hot, y_hot);
+
+ return (TCL_OK);
+}
+
+
+/* findCursor -- Search the cursor cache for the named cursor.
+ */
+Cursor
+findCursor (obm, name)
+ObmContext obm;
+char *name;
+{
+ register ObjList lp;
+
+ for (lp = obm->cursor_cache; lp; lp = lp->next)
+ if (lp->ptr && strcmp (name, lp->name) == 0)
+ return ((Cursor) lp->ptr);
+
+ return ((Cursor) NULL);
+}
+
+
+/* serverCreateMenu, serverEditMenu -- Create or modify a menu.
+ * The editMenu function is an alias for createMenu.
+ *
+ * Usage: createMenu menu-name parent item-list
+ *
+ * e.g., createMenu menu-name parent {
+ * { label function data [options...] }
+ * { label function data [options...] }
+ * (etc.)
+ * }
+ * where
+ *
+ * menu-name is the object name for the menu popup shell
+ * parent is the parent widget of the menu shell
+ *
+ * label is a menu item label
+ *
+ * function is the function to be performed when the menu
+ * item is selected, e.g., f.exec, f.data, f.space,
+ * or f.line.
+ *
+ * data is function dependent data
+ *
+ * options are option-name option-value pairs, as specified
+ * below.
+ *
+ * In the item list the fields label and option-value may be any Tcl
+ * expression. Expressions are evaluated in the server context. The data
+ * field is a Tcl script to be executed when the menu item is selected.
+ *
+ * Options are specified as "option option-value". The menu item options
+ * are as follows.
+ *
+ * foreground Foreground color.
+ *
+ * background Background color.
+ *
+ * bitmap A bitmap to be displayed left justified in the
+ * label field (e.g. to indicate a parameter setting).
+ *
+ * justify Type of text alignment: left, center, right.
+ *
+ * sensitive Specifies whether the menu item is active (sensitive=
+ * true) or inactive (sensitive=false, item grayed out).
+ *
+ * accelerator Specifies an input translation (accelerator, e.g.,
+ * keyboard event) which can be used to execute the
+ * menu item.
+ *
+ * The option-value field may be any Tcl expression.
+ *
+ * Example: createMenu fileMenu toplevel {
+ * { "File Menu" f.title }
+ * { Open f.exec openFile }
+ * { Save f.exec saveFile }
+ * { Load f.menu loadMenu }
+ * { no-label f.line }
+ * { Quit f.exec "send client Quit" }
+ * }
+ *
+ * The first createMenu is called for a given menu the menu is created,
+ * added to the menu list, and all window system widgets are created for
+ * the menu. Subsequent calls will result in only the changed parts of the
+ * menu being altered provided the changes are not great. Hence this routine
+ * can be called to efficiently modify a menu when minor runtime changes
+ * occur, e.g., an item label or action changes, the item value changes state,
+ * and so on, without need for the GUI code to know how to make the necessary
+ * detailed changes to the widgets used to implement the menu.
+ */
+static int
+serverCreateMenu (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ register MenuPtr mp, o_mp;
+ register MenuItem ip;
+ register ObjList lp, newobj;
+ char *menu_name, *menu_label;
+ char *parent, *item_list;
+ char **items, **fields;
+ int nitems, nfields;
+ int field, item;
+ ObmObject pobj;
+ Widget w, pw;
+
+ if (obm->being_destroyed)
+ return (TCL_OK);
+ if (!obm->specified || !obm->display)
+ return (TCL_ERROR);
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ menu_name = argv[1];
+ parent = argv[2];
+ item_list = argv[3];
+
+ /* Locate the parent widget. */
+ if ((pobj = (ObmObject) obmFindObject (obm, parent)) == NULL) {
+ fprintf (stderr, "obm: cannot find parent widget %s for menu %s\n",
+ parent, menu_name);
+ return (TCL_ERROR);
+ } else
+ pw = widgetGetPointer (pobj);
+
+ /* Ignore request if parent is being destroyed. */
+ if (pobj->core.being_destroyed)
+ return (TCL_OK);
+
+ /* Get the list of menu item specifier strings. */
+ if (Tcl_SplitList (tcl, item_list, &nitems, &items) != TCL_OK) {
+ fprintf (stderr, "obm: error parsing menu for %s\n", menu_name);
+ return (TCL_ERROR);
+ } else if (nitems > MAX_MENUITEMS)
+ nitems = MAX_MENUITEMS;
+
+ /* Allocate a new, empty menu descriptor. */
+ mp = (MenuPtr) XtCalloc (1, sizeof (Menu));
+
+ /* Process each item and add it to the menu descriptor. */
+ for (item=0; item < nitems; item++) {
+ if (Tcl_SplitList (tcl, items[item], &nfields, &fields) != TCL_OK) {
+ fprintf (stderr, "obm: error parsing menu item %d of %s\n",
+ item + 1, menu_name);
+ continue;
+ }
+
+ ip = &mp->items[mp->nitems++];
+
+ /* The first three fields label,type,data have a fairly strict
+ * syntax and must be in order. Try to interpret the label field
+ * as a string expression; if this fails, assume it is a literal
+ * label string.
+ */
+ field = 0;
+ if (strncmp (fields[field], "f.", 2) == 0)
+ ip->label = NULL;
+ else {
+ char *cp = fields[field++];
+
+ if (Tcl_ExprString (tcl, cp) != TCL_OK)
+ ip->label = cp;
+ else {
+ ip->label = XtMalloc (strlen(tcl->result) + 1);
+ strcpy (ip->label, tcl->result);
+ ip->flags |= M_FreeLabel;
+ }
+ }
+
+ /* Determine menu item type. */
+ if (strcmp (fields[field], "f.exec") == 0) {
+ ip->type = MI_EXEC;
+ ip->data = fields[++field];
+ } else if (strcmp (fields[field], "f.line") == 0) {
+ ip->type = MI_LINE;
+ ip->data = NULL;
+ } else if (strcmp (fields[field], "f.dblline") == 0) {
+ ip->type = MI_DBLLINE;
+ ip->data = NULL;
+ } else if (strcmp (fields[field], "f.menu") == 0) {
+ ip->type = MI_MENU;
+ ip->data = fields[++field];
+ } else if (strcmp (fields[field], "f.space") == 0) {
+ ip->type = MI_SPACE;
+ ip->data = fields[++field];
+ } else if (strcmp (fields[field], "f.title") == 0) {
+ ip->type = MI_TITLE;
+ ip->data = NULL;
+ } else {
+ fprintf (stderr, "obm: bad menu item type `%s'\n",
+ fields[field]);
+ ip->type = MI_IGNORE;
+ ip->data = NULL;
+ }
+ field++;
+
+ /* Process any optional menu item attributes. */
+ for ( ; field < nfields; field++) {
+ if (strcmp (fields[field], "background") == 0) {
+ ip->background = fields[++field];
+
+ } else if (strcmp (fields[field], "foreground") == 0) {
+ ip->foreground = fields[++field];
+
+ } else if (strcmp (fields[field], "bitmap") == 0) {
+ char *cp = fields[++field];
+
+ if (Tcl_ExprString (tcl, cp) != TCL_OK)
+ ip->pixmap = findBitmap (obm, cp);
+ else
+ ip->pixmap = findBitmap (obm, tcl->result);
+
+ } else if (strcmp (fields[field], "justify") == 0) {
+ char *justify = fields[++field];
+ if (strcmp (justify, "left") == 0)
+ ip->justify = XtJustifyLeft;
+ else if (strcmp (justify, "center") == 0)
+ ip->justify = XtJustifyCenter;
+ else if (strcmp (justify, "right") == 0)
+ ip->justify = XtJustifyRight;
+
+ } else if (strcmp (fields[field], "sensitive") == 0) {
+ int ch = fields[++field][0];
+ int bval;
+
+ if (ch == 'f' || ch == 'F')
+ ip->flags |= M_Insensitive;
+ else if (ch == 't' || ch == 'T')
+ ip->flags &= ~M_Insensitive;
+ else {
+ if (Tcl_ExprBoolean (tcl,
+ fields[field], &bval) != TCL_OK) {
+ fprintf (stderr,
+ "menu %s.%d sensitive option: %s\n",
+ menu_name, item, tcl->result);
+ } else if (!bval)
+ ip->flags |= M_Insensitive;
+ }
+
+ } else if (strncmp (fields[field], "accelerator", 5) == 0) {
+ ip->accelerator = fields[++field];
+
+ } else {
+ fprintf (stderr, "obm: bad menu item parameter `%s'\n",
+ fields[field]);
+ }
+ }
+
+ /* Save the string buffer pointer to be freed by menuFree. */
+ ip->sbuf = (char *) fields;
+ }
+
+ /* Free list of menu item specification strings. */
+ free ((char *) items);
+
+ /* Search the menu list and see if there is already a menu with
+ * the given menu name.
+ */
+ for (lp = obm->menu_list, o_mp=NULL; lp; lp = lp->next)
+ if (strcmp (lp->name, menu_name) == 0) {
+ o_mp = (MenuPtr) lp->ptr;
+ break;
+ }
+
+ /* If the menu already exists try to edit it, otherwise delete any
+ * existing menu and create a new one from scratch.
+ */
+ if (o_mp && editMenu (o_mp, mp) == 0) {
+ /* The edit succeeded. Discard the request descriptor. */
+ freeMenu (mp);
+
+ } else if (o_mp) {
+ /* Replace an existing menu. */
+ obmDestroyObject (obm, o_mp->obj);
+ freeMenu (o_mp);
+ createMenu (obm, mp, menu_name, parent, pw);
+ lp->ptr = (caddr_t) mp;
+
+ } else {
+ /* Create a new menu. */
+ createMenu (obm, mp, menu_name, parent, pw);
+
+ newobj = (ObjList) XtMalloc (sizeof (struct objList));
+ strcpy (newobj->name, menu_name);
+ newobj->ptr = (caddr_t) mp;
+ newobj->next = NULL;
+
+ if (obm->menu_list == NULL)
+ obm->menu_list = newobj;
+ else {
+ for (lp = obm->menu_list; lp->next; lp = lp->next)
+ ;
+ lp->next = newobj;
+ }
+ }
+
+ return (TCL_OK);
+}
+
+
+/* serverDestroyMenu -- Destroy a menu. This can be used to free up the
+ * resources used by a menu, e.g., if the menu is not expected to be needed
+ * again for a while.
+ *
+ * Usage: destroyMenu menu-name
+ */
+static int
+serverDestroyMenu (object, tcl, argc, argv)
+ObmObject object;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ ServerObject obj = (ServerObject) object;
+ ObmContext obm = (ObmContext) obj->server.obm;
+ register ObjList lp, lpp;
+ register MenuPtr mp;
+ char *menu_name;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+ else
+ menu_name = argv[1];
+
+ /* Locate the menu descriptor. */
+ for (lp = obm->menu_list, lpp=NULL, mp=NULL; lp; lpp=lp, lp=lp->next)
+ if (strcmp (lp->name, menu_name) == 0) {
+ mp = (MenuPtr) lp->ptr;
+ break;
+ }
+ if (mp == NULL)
+ return (TCL_OK);
+
+ /* Unlink the menu from the menu list. */
+ if (lpp == NULL)
+ obm->menu_list = lp->next;
+ else
+ lpp->next = lp->next;
+
+ /* Destroy the menu object and any descendents. */
+ obmDestroyObject (obm, mp->obj);
+ freeMenu (mp);
+
+ return (TCL_OK);
+}
+
+
+/* createMenu -- Create a new menu from a menu descriptor.
+ */
+static void
+createMenu (obm, mp, menu_name, parent, pw)
+ObmContext obm;
+register MenuPtr mp;
+char *menu_name;
+char *parent;
+Widget pw;
+{
+ register MenuItem ip;
+ int itemno, menuno, lineno, spaceno;
+ Widget menu, entry;
+ char name[SZ_NAME];
+ XrmValue from, to[2];
+ Pixel value[2];
+ Arg args[10];
+ int nargs, i;
+
+ menu_classInit();
+
+ /* The following resources are statically defined for all menus. */
+ nargs = 0;
+ if (mp->items[0].type == MI_TITLE) {
+ XtSetArg (args[nargs], XtNlabel, mp->items[0].label);
+ nargs++;
+ }
+
+ /* Create the menu shell. */
+ obmNewObject (obm, menu_name, "SimpleMenu", parent, args, nargs);
+ mp->obj = obmFindObject (obm, menu_name);
+ mp->menuShell = menu = widgetGetPointer (mp->obj);
+ mp->obm = (XtPointer) obm;
+
+ XtAddCallback (menu, XtNpopupCallback, menu_popup, (XtPointer)mp);
+ XtAddCallback (menu, XtNpopdownCallback, menu_popdown, (XtPointer)mp);
+
+ ip = &mp->items[0];
+ itemno = menuno = lineno = spaceno = 1;
+
+ /* Create each menu item. */
+ for (i=0; i < mp->nitems; i++) {
+ ip->menu = (XtPointer)mp;
+
+ /* Create the menu item widget. */
+ switch (ip->type) {
+ case MI_EXEC:
+ sprintf (name, "item%d", itemno++);
+ obmNewObject (obm, name, "SmeBSB", menu_name, NULL, 0);
+ entry = XtNameToWidget (menu, name);
+ XtAddCallback (entry, XtNcallback, menuSelect, (XtPointer)mp);
+ break;
+
+ case MI_LINE:
+ sprintf (name, "line%d", lineno++);
+ obmNewObject (obm, name, "SmeLine", menu_name, NULL, 0);
+ entry = XtNameToWidget (menu, name);
+ break;
+
+ case MI_DBLLINE:
+ nargs = 0;
+ XtSetArg (args[nargs], XtNheight, 2);
+ nargs++;
+ sprintf (name, "line%d", lineno++);
+ obmNewObject (obm, name, "SmeLine", menu_name, args, nargs);
+ sprintf (name, "line%d", lineno++);
+ obmNewObject (obm, name, "SmeLine", menu_name, args, nargs);
+ entry = XtNameToWidget (menu, name);
+ break;
+
+ case MI_MENU:
+ sprintf (name, "menu%d", menuno++);
+ obmNewObject (obm, name, "SmeBSB", menu_name, NULL, 0);
+ entry = XtNameToWidget (menu, name);
+ XtAddCallback (entry, XtNcallback, menuSelect, (XtPointer)mp);
+
+ menu_addEntry (entry, menu_name, ip->data, obm);
+ XtAddCallback (entry, XtNdestroyCallback, menu_delEntry,
+ (XtPointer)NULL);
+ break;
+
+ case MI_SPACE:
+ nargs = 0;
+ XtSetArg (args[nargs], XtNheight, atoi(ip->data));
+ nargs++;
+ sprintf (name, "line%d", lineno++);
+ obmNewObject (obm, name, "Sme", menu_name, args, nargs);
+ entry = XtNameToWidget (menu, name);
+ break;
+
+ case MI_TITLE:
+ if (i > 0)
+ fprintf (stderr,
+ "obm: menu title must be first item in menu\n");
+ ip++;
+ continue;
+
+ default:
+ /* ignore */
+ fprintf (stderr, "obm: unknown menu item type %s[%d]\n",
+ menu_name, i + 1);
+ ip++;
+ continue;
+ }
+
+ /* Set the item specific resources. */
+ nargs = 0;
+ if (ip->label) {
+ XtSetArg (args[nargs], XtNlabel, ip->label);
+ nargs++;
+ }
+ if (ip->background || ip->foreground) {
+ char *s[3];
+ int i=0;
+
+ if (ip->background)
+ s[i++] = ip->background;
+ if (ip->foreground)
+ s[i++] = ip->foreground;
+ s[i++] = NULL;
+
+ for (i=0; s[i]; i++) {
+ from.size = strlen(s[i]) + 1;
+ from.addr = s[i];
+ to[i].addr = (caddr_t) &value[i];
+ to[i].size = sizeof(value[i]);
+
+ if (XtConvertAndStore (entry,
+ XtRString, &from, XtRPixel, &to[i])) {
+ XtSetArg (args[nargs], s[i] == ip->background ?
+ XtNbackground : XtNforeground, value[i]);
+ nargs++;
+ }
+ }
+ }
+ if (ip->justify) {
+ XtSetArg (args[nargs], XtNjustify, ip->justify);
+ nargs++;
+ }
+ if (ip->pixmap) {
+ XtSetArg (args[nargs], XtNleftBitmap, ip->pixmap);
+ nargs++;
+ }
+ if (ip->type == MI_MENU) {
+ XtSetArg (args[nargs], XtNrightBitmap,
+ menu_pullrightBitmap (obm, 0));
+ nargs++;
+ XtSetArg (args[nargs], XtNrightMargin, MB_WIDTH);
+ nargs++;
+ }
+ if (ip->flags & M_Insensitive) {
+ XtSetArg (args[nargs], XtNsensitive, False);
+ nargs++;
+ }
+ if (ip->accelerator) {
+ char buf[SZ_MESSAGE];
+ sprintf (buf, "%s: notify()", ip->accelerator);
+ XtSetArg (args[nargs], XtNaccelerators, buf);
+ nargs++;
+ }
+
+ if (nargs)
+ XtSetValues (entry, args, nargs);
+ ip->entry = entry;
+ ip++;
+ }
+}
+
+
+/* editMenu -- Edit a menu given descriptors for the current menu and the
+ * new version. Zero is returned if the edit succeeds. If the menus are
+ * too different editMenu will play it safe and return nonzero, and the
+ * caller should delete the old one and create a new menu from scratch.
+ */
+static int
+editMenu (mp, request)
+register MenuPtr mp; /* existing menu */
+MenuPtr request; /* requested values */
+{
+ register MenuItem old, new;
+ register int i;
+ int ncolors=0, nargs=0;
+ XrmValue from, to[2];
+ Pixel value[2];
+ Arg args[10];
+
+ /* Make a quick comparision of the old and new menu descriptors to
+ * see if they are similar enough for the edit to make sense.
+ */
+ if (mp->nitems != request->nitems)
+ return (-1);
+ for (i=0; i < mp->nitems; i++) {
+ if (mp->items[i].type != request->items[i].type)
+ return (-1);
+ }
+
+ /* Edit each menu item. */
+ for (i=0; i < mp->nitems; i++) {
+ old = &mp->items[i];
+ new = &request->items[i];
+
+ nargs = 0;
+ if (new->label &&
+ (!old->label || strcmp (old->label, new->label))) {
+ if (old->flags & M_FreeLabel)
+ old->label = XtRealloc (old->label, strlen(new->label)+1);
+ else {
+ old->label = XtMalloc (strlen(new->label) + 1);
+ old->flags |= M_FreeLabel;
+ }
+ strcpy (old->label, new->label);
+ XtSetArg (args[nargs], XtNlabel, old->label);
+ nargs++;
+ }
+
+ if (new->data && (!old->data || strcmp (old->data, new->data))) {
+ if (old->flags & M_FreeData)
+ old->data = XtRealloc (old->data, strlen(new->data)+1);
+ else {
+ old->data = XtMalloc (strlen(new->data) + 1);
+ old->flags |= M_FreeData;
+ }
+ strcpy (old->data, new->data);
+ }
+
+ if (new->background && (!old->background ||
+ strcmp (old->background, new->background))) {
+
+ int nchars = strlen (new->background) + 1;
+ char *s;
+
+ if (old->flags & M_FreeBackground)
+ old->background = XtRealloc (old->background, nchars);
+ else {
+ old->background = XtMalloc (nchars);
+ old->flags |= M_FreeBackground;
+ }
+ strcpy (s = old->background, new->background);
+
+ from.size = strlen(s) + 1;
+ from.addr = s;
+ to[ncolors].addr = (caddr_t) &value[ncolors];
+ to[ncolors].size = sizeof(value[ncolors]);
+
+ if (XtConvertAndStore (old->entry,
+ XtRString, &from, XtRPixel, &to[ncolors])) {
+ XtSetArg (args[nargs], XtNbackground, value[ncolors]);
+ nargs++;
+ ncolors++;
+ }
+ }
+
+ if (new->foreground && (!old->foreground ||
+ strcmp (old->foreground, new->foreground))) {
+
+ int nchars = strlen (new->foreground) + 1;
+ char *s;
+
+ if (old->flags & M_FreeForeground)
+ old->foreground = XtRealloc (old->foreground, nchars);
+ else {
+ old->foreground = XtMalloc (nchars);
+ old->flags |= M_FreeForeground;
+ }
+ strcpy (s = old->foreground, new->foreground);
+
+ from.size = strlen(s) + 1;
+ from.addr = s;
+ to[ncolors].addr = (caddr_t) &value[ncolors];
+ to[ncolors].size = sizeof(value[ncolors]);
+
+ if (XtConvertAndStore (old->entry,
+ XtRString, &from, XtRPixel, &to[ncolors])) {
+ XtSetArg (args[nargs], XtNforeground, value[ncolors]);
+ nargs++;
+ ncolors++;
+ }
+ }
+
+ if (old->justify != new->justify) {
+ old->justify = new->justify;
+ XtSetArg (args[nargs], XtNjustify, old->justify);
+ nargs++;
+ }
+
+ if (new->accelerator && (!old->accelerator ||
+ strcmp (old->accelerator, new->accelerator))) {
+ char buf[SZ_MESSAGE];
+ int nchars = strlen (new->accelerator) + 1;
+ sprintf (buf, "%s: notify()", new->accelerator);
+
+ if (old->flags & M_FreeAccel)
+ old->accelerator = XtRealloc (old->accelerator, nchars);
+ else {
+ old->accelerator = XtMalloc (nchars);
+ old->flags |= M_FreeAccel;
+ }
+ strcpy (old->accelerator, new->accelerator);
+ XtSetArg (args[nargs], XtNaccelerators, buf);
+ nargs++;
+ }
+
+ if (old->pixmap != new->pixmap) {
+ old->pixmap = new->pixmap;
+ XtSetArg (args[nargs], XtNleftBitmap, new->pixmap);
+ nargs++;
+ }
+
+ if ((old->flags & M_Insensitive) != (new->flags & M_Insensitive)) {
+ if (new->flags & M_Insensitive) {
+ old->flags |= M_Insensitive;
+ XtSetArg (args[nargs], XtNsensitive, False);
+ } else {
+ old->flags &= ~M_Insensitive;
+ XtSetArg (args[nargs], XtNsensitive, True);
+ }
+ nargs++;
+ }
+
+ if (old->entry && nargs > 0)
+ XtSetValues (old->entry, args, nargs);
+ }
+
+ return (0);
+}
+
+
+/* freeMenu -- Free a menu descriptor.
+ */
+void
+freeMenu (mp)
+register MenuPtr mp;
+{
+ register MenuItem ip;
+ register int i;
+
+ for (i=0; i < mp->nitems; i++) {
+ ip = &mp->items[i];
+ if (ip->type == MI_MENU && ip->entry)
+ menu_delEntry (ip->entry);
+
+ if ((ip->flags & M_FreeBackground) && ip->background)
+ XtFree (ip->background);
+ if ((ip->flags & M_FreeForeground) && ip->foreground)
+ XtFree (ip->foreground);
+ if ((ip->flags & M_FreeAccel) && ip->accelerator)
+ XtFree (ip->accelerator);
+ if ((ip->flags & M_FreeLabel) && ip->label)
+ XtFree (ip->label);
+ if ((ip->flags & M_FreeData) && ip->data)
+ XtFree (ip->data);
+
+ XtFree (ip->sbuf);
+ }
+
+ XtFree ((char *)mp);
+}
+
+
+/* menuSelect -- Callback routine, called when a menu item is selected.
+ */
+static void
+menuSelect (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data;
+{
+ register MenuPtr mp = (MenuPtr) client_data;
+ register MenuItem ip;
+ register int i;
+ ObmContext obm = (ObmContext) mp->obm;
+
+ /* Locate the menu item to which the callback refers. */
+ for (i=0, ip=NULL; i < mp->nitems; i++) {
+ ip = &mp->items[i];
+ if (ip->entry == w)
+ break;
+ }
+
+ /* Ignore callbacks other than for command type menu entries (MI_EXEC).
+ * In the case of a command entry the data field of the menu item
+ * descriptor contains the server command to be executed.
+ */
+
+ if (ip && ip->type == MI_EXEC)
+ if (Tcl_Eval (obm->tcl, ip->data) != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error %s.%s line %d: %s\n",
+ mp->obj->core.name, XtName(ip->entry), obm->tcl->errorLine,
+ errstr ? errstr : obm->tcl->result);
+ }
+}
+
+
+/*
+ * The following code is used to interpose special highlight() and
+ * unhighlight() SmeBSB class procedures, to allow menu entries which point to
+ * submenus to automatically popup and popdown the submenu when the menu entry
+ * which points to it is highlighted or unhighlighted. It is a bit of a trick
+ * to replace the standard class procedure as we do here, but this is a lot
+ * simpler than subclassing the entire SmeBSB widget, and works for both the
+ * standard Athena and Xaw3D versions of the widget. Tying the submenu
+ * popup/popdown to the simpleMenu highlight/unhighlight actions allows us
+ * to let the simpleMenu widget track the pointer and determine when the
+ * submenu should be displayed.
+ *
+ * [Note added later]. Having now implemented this technique for cascaded
+ * menus I am not sure it was the best way to do this - it might have been
+ * better to just use motion events. There were a number of subtle problems
+ * to be solved to get this to work. It is true though, that most of these
+ * don't have much to do with the interpose-highlight technique, so maybe
+ * I would have run into the problems anyway. The problems were things like
+ * state changes when the pointer crosses from a menu pane into a submenu,
+ * the need to explicitly popdown submenus when the main window is popped
+ * down or when a nonmenu item in the main menu is entered, getting the
+ * grabs right, an annoying warning message about trying to remove a grab
+ * which no longer existed, and so on. Getting the pull-right bitmap to
+ * look right took a lot of fiddling and it appeared that there might be a
+ * positioning bug in the Xaw3d code related to this. The one problem that
+ * was clearly specific to the highlight/unhighlight technique was that
+ * SmeBSB uses a toggle type function for highlight/unhighlight. This
+ * assumes that the toggle is always in a known state. This works for a
+ * single menu, but it appears that there is a bug in the SmeBSB code when
+ * a pull-right menu obscures the parent menu, causing the toggle to get
+ * out of phase when moving into the submenu band back out (out of phase
+ * means that when one calls the unhighlight class procedure, the toggle
+ * actually highlights, and vice versa). I had to disable highlighting of
+ * submenu items in a menu to avoid this problem.
+ */
+
+/* The following describes a menu entry widget which calls a submenu. */
+struct _menuEntry {
+ Widget w; /* this widget */
+ char name[SZ_NAME]; /* name of menu containing widget */
+ char child[SZ_NAME]; /* submenu name */
+ Widget menu; /* shell widget of submenu */
+ ObmContext obm; /* obm context */
+ struct _menuEntry *next; /* next menuEntry on list */
+};
+typedef struct _menuEntry menuEntry, *MenuEntry;
+
+MenuEntry menuWidgetList;
+static char menu_bitmap1[] = "BSB_pullright1";
+static char menu_bitmap2[] = "BSB_pullright2";
+static void (*BSB_highlight)();
+static void (*BSB_unhighlight)();
+
+
+/* menu_classInit -- Edit the SME class record to interpose our custom
+ * highlight/unhighlight class procedures.
+ */
+static void
+menu_classInit()
+{
+ register SmeClassPart *sme = &smeBSBClassRec.sme_class;
+
+ if (sme->highlight != menu_highlight) {
+ BSB_highlight = sme->highlight;
+ sme->highlight = menu_highlight;
+ }
+ if (sme->unhighlight != menu_unhighlight) {
+ BSB_unhighlight = sme->unhighlight;
+ sme->unhighlight = menu_unhighlight;
+ }
+}
+
+
+/* menu_pullrightBitmap -- Return the bitmap id of the pullright bitmap
+ * displayed on the right side of a menu entry that brings up a submenu.
+ */
+static Pixmap
+menu_pullrightBitmap (obm, state)
+ObmContext obm;
+int state;
+{
+ Pixmap bitmap;
+
+ if (bitmap = findBitmap (obm, state ? menu_bitmap2 : menu_bitmap1))
+ return (bitmap);
+
+ createBitmap (obm, menu_bitmap1, MB_WIDTH, MB_HEIGHT, MB1_PIXELS);
+ createBitmap (obm, menu_bitmap2, MB_WIDTH, MB_HEIGHT, MB2_PIXELS);
+
+ if (bitmap = findBitmap (obm, state ? menu_bitmap2 : menu_bitmap1))
+ return (bitmap);
+ else
+ return ((Pixmap)NULL);
+}
+
+
+/* menu_addEntry -- Add a widget to the menuWidgetList list.
+ */
+static void
+menu_addEntry (w, name, child, obm)
+Widget w; /* menu entry which calls submenu */
+char *name; /* name of menu containing this widget */
+char *child; /* name of submenu shell widget */
+ObmContext obm;
+{
+ register MenuEntry mw, new;
+
+ for (mw=menuWidgetList; mw && mw->next; mw = mw->next)
+ if (mw->w == w)
+ return;
+
+ if ((new = (MenuEntry) XtCalloc (1, sizeof (menuEntry))) == NULL)
+ return;
+
+ new->w = w;
+ strcpy (new->name, name);
+ strcpy (new->child, child);
+ new->obm = obm;
+
+ if (mw)
+ mw->next = new;
+ else
+ menuWidgetList = new;
+}
+
+
+/* menu_delEntry -- Delete a widget from the menuWidgetList list.
+ */
+static void
+menu_delEntry (w, client_data, call_data)
+register Widget w;
+XtPointer client_data; /* not used */
+XtPointer call_data; /* not used */
+{
+ register MenuEntry mw, prev_mw;
+
+ for (mw=menuWidgetList, prev_mw=NULL; mw; prev_mw=mw, mw=mw->next)
+ if (mw->w == w)
+ break;
+
+ if (mw) {
+ if (prev_mw)
+ prev_mw->next = mw->next;
+ else
+ menuWidgetList = NULL;
+ XtFree ((char *)mw);
+ }
+}
+
+
+/* menu_popup -- Called when a menu is popped up.
+ */
+static void
+menu_popup (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data; /* not used */
+{
+ register MenuPtr mp = (MenuPtr) client_data;
+ mp->popped_up = True;
+}
+
+
+/* menu_popdown -- Called when a menu is popped down. Make sure any
+ * child menus are popped down before popping down the parent.
+ */
+static void
+menu_popdown (w, client_data, call_data)
+Widget w;
+XtPointer client_data;
+XtPointer call_data; /* not used */
+{
+ register MenuPtr mp = (MenuPtr) client_data;
+ ObmContext obm = (ObmContext) mp->obm;
+ register MenuEntry mw;
+ register MenuPtr mm;
+ MenuItem mi;
+ int i;
+
+ /* This routine is called with w=NULL to popdown any child menus.
+ * If w is not NULL that means we are being called as a
+ * popdownCallback for the menu shell.
+ */
+ if (w)
+ mp->popped_up = False;
+
+ for (i=0; i < mp->nitems; i++) {
+ mi = &mp->items[i];
+ if (mi->type == MI_MENU) {
+ /* Locate menu descriptor for named menu. */
+ mm = findMenu (obm, mi->data);
+
+ /* Popdown the child menu (if necessary). The temporary dummy
+ * warning message handler appears to be the only way to avoid
+ * a warning messages about an attempt to remove a grab for a
+ * widget on the grab list. What happens is that when
+ * XtPopdown is called on the main menu this calls
+ * XtRemoveGrab on the window, which removes any grabs for the
+ * main window _and any later grabs_, i.e., for the submenus.
+ * XtPopdown then calls the menu_popdown popdown callback,
+ * which is necessary to popdown any child menus as XtPopdown
+ * does not do this. The XtPopdown called in this routine
+ * tries to remove a grab which has already been removed,
+ * causing the warning message. The situation itself appears
+ * to be harmless, so the best thing to do is just disable the
+ * warning message.
+ */
+ if (mm && mm->menuShell) {
+ XtErrorMsgHandler old_handler;
+
+ old_handler = XtAppSetWarningMsgHandler (obm->app_context,
+ (XtErrorMsgHandler) menu_popdown_msgHandler);
+ XtPopdown (mm->menuShell);
+ XtAppSetWarningMsgHandler (obm->app_context, old_handler);
+ }
+ }
+ }
+}
+
+
+/* menu_popdown_msgHandler -- Dummy warning message handler used in menu
+ * popdown above.
+ */
+static void
+menu_popdown_msgHandler (name,type,class,defaultp,params,num_params)
+String name,type,class,defaultp;
+String* params;
+Cardinal* num_params;
+{
+}
+
+
+/* menu_highlight -- Custom version of the simpleMenu class action highlight
+ * procedure, called when a menu entry is highlighted. This is identical to
+ * the standard class procedure (in fact we call the standard class highlight
+ * procedure) except that we check to see if the widget being highlighted
+ * is a submenu, and if so, popup the submenu.
+ */
+static void
+menu_highlight (w)
+register Widget w;
+{
+ register MenuEntry mw, sm;
+ ObmContext obm = global_obm_handle;
+ MenuPtr mp;
+
+ /* If we are highlighting an entry in a menu then any pull-right
+ * submenus which are still up should not be, so get rid of them.
+ */
+ if (mp = findMenu (obm, XtName(w->core.parent)))
+ menu_popdown ((Widget)NULL, (XtPointer)mp, (XtPointer)NULL);
+
+ /* Is the menu entry being highlighted on our list of call-submenu
+ * widgets?
+ */
+ for (mw=menuWidgetList; mw; mw = mw->next)
+ if (mw->w == w)
+ break;
+
+ /* If the menu item is for a submenu, popup the submenu. */
+ if (mw) {
+ Position x, y;
+ Position menu_x, menu_y;
+ Dimension parent_width;
+ Dimension menu_width, menu_height;
+ char target[SZ_NAME];
+ ObmContext obm = mw->obm;
+ Widget menu;
+
+ /* If the parent menu is not popped up, do not pop up the
+ * child. This doesn't sound likely but it can happen when
+ * menu_highlight is called after a button-up event which
+ * pops down the main menu.
+ */
+ if (mp && mp->popped_up == False)
+ return;
+
+ /* Get shell widget of submenu. */
+ if (!(mp && (mw->menu = XtNameToWidget (mp->menuShell, target)))) {
+ sprintf (target, "*%s", mw->child);
+ if (!(mw->menu = XtNameToWidget (obm->toplevel, target)))
+ return;
+ }
+
+ menu = mw->menu;
+ XtTranslateCoords (w, 0, 0, &x, &y);
+ XtVaGetValues (w, XtNwidth, &parent_width, NULL);
+
+ menu_width = menu->core.width + 2 * menu->core.border_width;
+ menu_height = menu->core.height + 2 * menu->core.border_width;
+ menu_x = x + parent_width - 5;
+ menu_y = y - 5;
+
+ if (menu_x >= 0) {
+ int scr_width = WidthOfScreen(XtScreen(menu));
+ if ((int)(menu_x + menu_width) > (int)scr_width)
+ menu_x = scr_width - menu_width;
+ }
+ if (menu_x < 0)
+ menu_x = 0;
+
+ if (menu_y >= 0) {
+ int scr_height = HeightOfScreen(XtScreen(menu));
+ if ((int)(menu_y + menu_height) > (int)scr_height)
+ menu_y = scr_height - menu_height;
+ }
+ if (menu_y < 0)
+ menu_y = 0;
+
+ XtVaSetValues (menu,
+ XtNx, menu_x,
+ XtNy, menu_y,
+ NULL);
+ /*
+ * This appears to bring out a bug in the Xaw|Xaw3d SmeBSB.
+ *
+ XtVaSetValues (w,
+ XtNrightBitmap, menu_pullrightBitmap (obm, 1),
+ NULL);
+ */
+
+ /* Popup the pull-right menu. */
+ XtPopup (menu, XtGrabNonexclusive);
+
+ } else {
+ /* Call the standard simplemenu highlight method. */
+ BSB_highlight (w);
+ }
+}
+
+
+/* menu_unhighlight -- Custom unhighlight class procedure, interposed in
+ * front of the standard class procedure.
+ */
+static void
+menu_unhighlight (w)
+register Widget w;
+{
+ register MenuEntry mw;
+
+ /* Is the menu entry being unhighlighted on our list of call-submenu
+ * widgets?
+ */
+ for (mw=menuWidgetList; mw; mw = mw->next)
+ if (mw->w == w)
+ break;
+
+ if (mw == NULL) {
+ /* Now call the standard class unhighlight procedure. */
+ BSB_unhighlight (w);
+
+ } else if (mw->menu) {
+ /* Popdown the submenu.
+ */
+ ObmContext obm = mw->obm;
+ Dimension width, height;
+ int in_window, i;
+ XMotionEvent *ev;
+ XEvent event;
+ Position x, y;
+ Widget wl[2];
+
+ /* Get the next window event. All we are looking for here is
+ * the pointer coordinates.
+ */
+ ev = (XMotionEvent *) &event;
+ while (!XtAppPeekEvent (obm->app_context, &event))
+ ;
+
+ wl[0] = w;
+ wl[1] = mw->menu;
+ in_window = 0;
+
+ /* Check if the pointer is in either the pull-right pane of
+ * the parent menu, or the pull-right menu itself.
+ */
+ for (i=0; i < 2; i++) {
+ XtTranslateCoords (wl[i], 0, 0, &x, &y);
+ XtVaGetValues (wl[i],
+ XtNwidth, &width,
+ XtNheight, &height,
+ NULL);
+
+ if (ev->x_root >= x && ev->x_root < x + (Position)width &&
+ ev->y_root >= y && ev->y_root < y + (Position)height) {
+ in_window++;
+ break;
+ }
+ }
+
+ /* If it is not in either window then go ahead and popdown the
+ * child menu, otherwise ignore the request. Erroneous requests
+ * can occur when the pointer is in crossing from one window
+ * to the other.
+ */
+ if (!in_window) {
+ /*
+ * This appears to bring out a bug in the Xaw3d SmeBSB.
+ XtVaSetValues (w,
+ XtNrightBitmap, menu_pullrightBitmap (obm, 0),
+ NULL);
+ */
+
+ XtPopdown (mw->menu);
+ }
+ }
+}
+
+
+/* findMenu -- Return the menu descriptor of a menu given its name.
+ */
+static MenuPtr
+findMenu (obm, name)
+register ObmContext obm;
+char *name;
+{
+ register ObjList lp;
+
+ for (lp = obm->menu_list; lp; lp = lp->next)
+ if (strcmp (lp->name, name) == 0)
+ return ((MenuPtr) lp->ptr);
+
+ return (NULL);
+}
diff --git a/vendor/x11iraf/obm/widget.c b/vendor/x11iraf/obm/widget.c
new file mode 100644
index 00000000..e33723ff
--- /dev/null
+++ b/vendor/x11iraf/obm/widget.c
@@ -0,0 +1,5017 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <ObmP.h>
+#include "widget.h"
+
+/*
+ * WIDGET class.
+ * --------------------------
+ * The Widget class is the generic or base class for the window system
+ * toolkit widgets supported by the object manager. The Widget class
+ * supports a number of different Xt widget classes using a table driven
+ * approach to describe each widget. Any widget may be created, destroyed,
+ * and manipulated in various ways using only the generic Widget class
+ * procedures and Widget-specific resources. The Widget class may be
+ * subclassed to support complex Widgets that require custom class-specific
+ * commands for use by the GUI code.
+ *
+ * Generic Widget-class commands:
+ *
+ * set resource-name value
+ * get resource-name
+ *
+ * addCallback procedure-name [callback-name]
+ * deleteCallback procedure-name
+ * setSensitive sensitive
+ * isSensitive
+ *
+ * realize
+ * unrealize
+ * isRealized
+ * map
+ * unmap
+ * manage child [child ...]
+ * unmanage child [child ...]
+ * popup [grab-kind]
+ * popdown
+ * popupSpringLoaded
+ *
+ * move x y
+ * resize width height border-width
+ * configure x y width height border-width
+ * parseGeometry user_geom def_geom x y width height
+ * geom = getGeometry x y width height [nogravity]
+ *
+ * setTTName name # for call($name...)
+ * name = getTTName
+ *
+ * The most important Widget commands are set/get resource, and the
+ * callbacks. The widget sensitivity can be set and queried using set/get
+ * resource, but special procedures are provided to make this common operation
+ * more convenient.
+ *
+ * Class specific functions:
+ *
+ * append text # text widget
+ * value = getValue # dialog widget
+ *
+ * setList list [resize] # list widget
+ * value = getItem itemno
+ * highlight itemno
+ * unhighlight [itemno]
+ *
+ * getThumb x [y [width height]] # sliders
+ * moveThumb x [y]
+ * resizeThumb width [height]
+ *
+ * setScrollbar position size # scrollbars
+ *
+ * setLocation x y # viewport
+ * setCoordinates x y
+ *
+ * setTop widget # tabs
+ *
+ * setListTree list # list tree
+ * listTreeSelect item [top [child_only] ]
+ * listTreeHighlight item [top [child_only] ]
+ * listTreeDelete item [top]
+ *
+ * setTable nrows ncols data # table
+ * attr = getCellAttr row col attr
+ * setCellAttr row col attr value
+ * attr = getColAttr col attr
+ * setColAttr col attr value
+ * attr = getRowAttr row attr
+ * setRowAttr row attr value
+ * deleteCol col
+ * deleteRow row
+ * addCol col width [where]
+ * addRow row [where]
+ * setTableSize nrows ncols
+ * getTableSize nrows ncols
+ *
+ *
+ * Ideally the widget class should be subclassed for widgets that require
+ * class-specific functions, but in simple cases involving standard widgets
+ * the support is built into the widget class code as a special case.
+ *
+ * Special actions (used in translations):
+ *
+ * call (proc [,arg, ...])
+ * popup (menu-name [xoffset [yoffset]])
+ * popdown (menu-name)
+ *
+ * The "call" action is a very general mechanism which allows any GUI procedure
+ * to be registered with any translation using the X translation table
+ * mechanism. The popup and popdown actions are used for popup menus. The
+ * menu will be popped up at the event coordinates plus the optional offsets
+ * if given.
+ *
+ * Event handling:
+ *
+ * addEventHandler <procname> <event-mask> [<event-mask>...]
+ *
+ * Event callback:
+ *
+ * userEventHandler widget event-type time wx wy rx ry other
+ *
+ * In most cases translations are preferable to events, but a GUI can capture
+ * raw events if it wishes by adding event handlers. Nearly all of the X
+ * event types are supported. The callback syntax employs a number of
+ * standard arguments, followed by a number of event-specific arguments.
+ */
+
+typedef struct rtype *Rtype;
+#define LEN_RHASH 197
+Rtype rhash[LEN_RHASH];
+
+#define MAX_TREE_LEVELS 10
+
+/* Global widget resources table. */
+struct rtype {
+ char *name; /* resource name */
+ char *type; /* resource type */
+ unsigned long flag1, flag2; /* widgets using resource */
+ struct rtype *next; /* next entry on hash thread */
+} ObmResources[] = {
+#include "obmres.dat"
+};
+
+struct callbackType {
+ int type;
+ char *name;
+};
+
+/* Widget callback types. */
+struct callbackType callbackTypes[] = {
+ { Ctcallback, "callback" },
+ { Ctcharmode, "charmode" },
+ { Ctlinemode, "linemode" },
+ { CtgetValue, "getValue" },
+ { CtjumpProc, "jump" },
+ { CtscrollProc, "scroll" },
+ { CtpopupCallback, "popup" },
+ { CtpopdownCallback, "popdown" },
+ { CtreportCallback, "report" },
+ { CtstartCallback, "start" },
+ { CtstopCallback, "stop" },
+};
+
+
+
+enum scaleType { /* MF016 */
+ atom, pixel_size, point_size, /* /|\ */
+ resolution, resolution_x, resolution_y, average_width, /* / | \ */
+ scaledX, scaledY, unscaled, scaledXoverY, uncomputed, /* | */
+}; /* | */
+ /* | */
+typedef struct _fontProp { /* | */
+ char *name; /* | */
+ Atom atom; /* | */
+ enum scaleType type; /* | */
+ char found; /* | */
+} fontProp; /* | */
+ /* | */
+static fontProp fontNamePropTable[] = { /* | */
+ { "FOUNDRY", 0, atom, 0}, /* | */
+ { "FAMILY_NAME", 0, atom, 0}, /* | */
+ { "WEIGHT_NAME", 0, atom, 0}, /* | */
+ { "SLANT", 0, atom, 0}, /* | */
+ { "SETWIDTH_NAME", 0, atom, 0}, /* | */
+ { "ADD_STYLE_NAME", 0, atom, 0}, /* | */
+ { "PIXEL_SIZE", 0, pixel_size, 0}, /* | */
+ { "POINT_SIZE", 0, point_size, 0}, /* | */
+ { "RESOLUTION_X", 0, resolution_x, 0}, /* | */
+ { "RESOLUTION_Y", 0, resolution_y, 0}, /* | */
+ { "SPACING", 0, atom, 0}, /* | */
+ { "AVERAGE_WIDTH", 0, average_width, 0}, /* | */
+ { "CHARSET_REGISTRY", 0, atom, 0}, /* | */
+ { "CHARSET_ENCODING", 0, atom, 0}, /* | */
+}; /* | */
+ /* | */
+#define NUMITEMS(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) /* \ | / */
+ /* \|/ */
+static char *widgetGetFontName(); /* MF016 */
+
+
+static void do_text();
+static void do_userproc();
+static void do_popup();
+static void do_popdown();
+static XtActionsRec widget_actions[] = {
+ {"call", do_userproc},
+ {"do_text", do_text},
+ {"popup", do_popup},
+ {"popdown", do_popdown},
+};
+
+static void call_callbacks();
+static void widgetEvent(), widgetSetDestroy(), widgetDestroy();
+static void widgetCallback(), widgetSCCallback(), widgetJPCallback();
+static void widgetSPCallback(), widgetPUCallback(), widgetPDCallback();
+static void widgetSBCallback(), widgetSECallback(), widgetRPCallback();
+static void widgetRGCallback(), widgetLTHCallback(), widgetLTACallback();
+static void widgetTCCCallback();
+static int widgetSet(), widgetGet(), widgetMap(), widgetUnmap();
+static int widgetRealize(), widgetUnrealize(), widgetIsRealized();
+static int widgetPopup(), widgetPopupSpringLoaded(), widgetPopdown();
+static int widgetAddCallback(), widgetDeleteCallback();
+static int widgetMove(), widgetResize(), widgetConfigure();
+static int widgetParseGeometry(), widgetGetGeometry();
+static int widgetSetSensitive(), widgetIsSensitive();
+static int widgetManage(), widgetUnmanage(), widgetAppend();
+static int widgetAddEventHandler(), widgetRemoveEventHandler();
+static int widgetHighlight(), widgetUnhighlight(), widgetSetTop();
+static int widgetSetList(), widgetGetItem(), widgetGetValue();
+static int widgetGetThumb(), widgetMoveThumb(), widgetResizeThumb();
+static int widgetSetScrollbar(), widgetSetTTName(), widgetGetTTName();
+static int widgetSetListTree(), widgetListTreeSelect();
+static int widgetListTreeHighlight(), widgetListTreeDelete();
+static int widgetSetLocation(), widgetSetCoordinates();
+static int widgetSetTable(), widgetSetCellAttr(), widgetGetCellAttr();
+static int widgetGetColAttr(), widgetSetColAttr(), widgetSetRowAttr();
+static int widgetDeleteRow(), widgetAddRow(), widgetGetTableSize();
+static int widgetDeleteCol(), widgetAddCol(), widgetSetTableSize();
+static int get_itemno(), buildTreeList(), widgetGetRowAttr();
+
+
+/* WidgetClassInit -- Initialize the class record for the widget class.
+ */
+void
+WidgetClassInit (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register int hashval, n;
+ register char *ip;
+ ObjClassRec widgetclass;
+ static int hashed = 0;
+ Tcl_Interp *tcl;
+ MsgContext msg;
+ Rtype rp, hp;
+ int i;
+
+ /* The base class for all Widget classes is "Widget". */
+ widgetclass = obmGetClassrec ("Widget");
+
+ /* Install the class methods. */
+ classrec->ClassDestroy = WidgetClassDestroy;
+ classrec->Create = (ObmFunc) WidgetCreate;
+ classrec->Destroy = WidgetDestroy;
+ classrec->Evaluate = WidgetEvaluate;
+
+ /* Since there can be many instances of the widget object and they
+ * all respond to the same class messages, a single interpreter is
+ * used for all widget instances. By default all Widget subclasses
+ * use the interperter for the base Widget class.
+ */
+ if (!widgetclass->class_data) {
+ msg = (MsgContext) XtMalloc (sizeof (struct msgContext));
+ msg->tcl = tcl = Tcl_CreateInterp();
+ widgetclass->class_data = (XtPointer) msg;
+ msg->level = 0;
+
+ /* Register widget-object actions. */
+ Tcl_CreateCommand (tcl,
+ "addCallback", widgetAddCallback, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteCallback", widgetDeleteCallback, (ClientData)msg,
+ NULL);
+ Tcl_CreateCommand (tcl,
+ "addEventHandler", widgetAddEventHandler, (ClientData)msg,
+ NULL);
+ Tcl_CreateCommand (tcl,
+ "removeEventHandler", widgetRemoveEventHandler,
+ (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "set", widgetSet, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "get", widgetGet, (ClientData)msg, NULL);
+
+ /* Text Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "append", widgetAppend, (ClientData)msg, NULL);
+
+ /* List Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setList", widgetSetList, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getItem", widgetGetItem, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "highlight", widgetHighlight, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "unhighlight", widgetUnhighlight, (ClientData)msg, NULL);
+
+ /* Dialog Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "getValue", widgetGetValue, (ClientData)msg, NULL);
+
+ /* Slider Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "getThumb", widgetGetThumb, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "moveThumb", widgetMoveThumb, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "resizeThumb", widgetResizeThumb, (ClientData)msg, NULL);
+
+ /* Scrollbar Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setScrollbar", widgetSetScrollbar, (ClientData)msg, NULL);
+
+ /* Viewport Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setLocation", widgetSetLocation, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setCoordinates", widgetSetCoordinates, (ClientData)msg, NULL);
+
+ /* Tabs Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setTop", widgetSetTop, (ClientData)msg, NULL);
+
+ /* Tree Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setListTree", widgetSetListTree, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "listTreeSelect", widgetListTreeSelect, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "listTreeDelete", widgetListTreeDelete, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "listTreeHighlight", widgetListTreeHighlight,
+ (ClientData)msg, NULL);
+
+ /* Table Widget Callbacks */
+ Tcl_CreateCommand (tcl,
+ "setTable", widgetSetTable, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getCellAttr", widgetGetCellAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setCellAttr", widgetSetCellAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setColAttr", widgetSetColAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getColAttr", widgetGetColAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setRowAttr", widgetSetRowAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getRowAttr", widgetGetRowAttr, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteCol", widgetDeleteCol, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "deleteRow", widgetDeleteRow, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "addCol", widgetAddCol, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "addRow", widgetAddRow, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setTableSize", widgetSetTableSize, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getTableSize", widgetGetTableSize, (ClientData)msg, NULL);
+
+ Tcl_CreateCommand (tcl,
+ "realize", widgetRealize, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "unrealize", widgetUnrealize, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "isRealized", widgetIsRealized, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "map", widgetMap, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "unmap", widgetUnmap, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "manage", widgetManage, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "unmanage", widgetUnmanage, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "popup", widgetPopup, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "popupSpringLoaded", widgetPopupSpringLoaded,
+ (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "popdown", widgetPopdown, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setSensitive", widgetSetSensitive, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "isSensitive", widgetIsSensitive, (ClientData)msg, NULL);
+
+ Tcl_CreateCommand (tcl,
+ "move", widgetMove, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "resize", widgetResize, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "configure", widgetConfigure, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "parseGeometry", widgetParseGeometry, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getGeometry", widgetGetGeometry, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "setTTName", widgetSetTTName, (ClientData)msg, NULL);
+ Tcl_CreateCommand (tcl,
+ "getTTName", widgetGetTTName, (ClientData)msg, NULL);
+
+ /* Register any actions. */
+ XtAppAddActions (obm->app_context, widget_actions,
+ XtNumber(widget_actions));
+ XtRegisterGrabAction (do_popup, True,
+ (unsigned)(ButtonPressMask | ButtonReleaseMask),
+ GrabModeAsync, GrabModeAsync);
+ }
+
+ /* Build a hash index for the global widget resources table. */
+ if (!hashed) {
+ for (i=0; i < XtNumber(ObmResources); i++) {
+ rp = &ObmResources[i];
+ n = MAX_HASHCHARS;
+ for (hashval=0, ip=rp->name; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+ if (hp = rhash[hashval%LEN_RHASH]) {
+ for ( ; hp->next; hp = hp->next)
+ ;
+ hp->next = rp;
+ } else
+ rhash[hashval%LEN_RHASH] = rp;
+ }
+ hashed++;
+ }
+}
+
+
+/* WidgetClassDestroy -- Custom destroy procedure for the widget class.
+ */
+void
+WidgetClassDestroy (obm, classrec)
+ObmContext obm;
+register ObjClassRec classrec;
+{
+ register MsgContext msg = (MsgContext) classrec->class_data;
+
+ if (msg) {
+ if (msg->tcl)
+ Tcl_DeleteInterp (msg->tcl);
+ XtFree ((char *)msg);
+ classrec->class_data = NULL;
+ }
+}
+
+
+/* WidgetCreate -- Create an instance of a widget object.
+ */
+ObmObject
+WidgetCreate (obm, name, classrec, parent, args, nargs)
+ObmContext obm;
+char *name;
+ObjClassRec classrec;
+char *parent;
+ArgList args;
+int nargs;
+{
+ register WidgetObject obj, pobj;
+ Widget w, pw;
+
+ /* Create the widget object descriptor. */
+ obj = (WidgetObject) XtCalloc (1, sizeof (struct widgetObject));
+ obj->widget.obm = obm;
+
+ /* The widget "toplevel" is a special case. This is the toplevel
+ * widget of the entire application and it is created separately
+ * when the application starts up. When we are called to "create"
+ * this widget all we do is create a descriptor for it, so that it
+ * will appear in the object list like any other widget.
+ */
+ if (strcmp (name, "toplevel") == 0) {
+ w = obm->toplevel;
+ pw = NULL;
+ } else {
+ /* Convert parent name to Widget. */
+ if ((pobj = (WidgetObject) obmFindObject (obm, parent)) == NULL)
+ return (NULL);
+ pw = pobj->widget.w;
+
+ /* Create the widget. */
+ if (classrec->object_type == OtShell) {
+ w = XtCreatePopupShell (name,
+ *classrec->widget_class, pw, args, nargs);
+ } else if (obmClass (classrec, WtObject)) {
+ w = XtCreateWidget (name,
+ *classrec->widget_class, pw, args, nargs);
+ } else {
+ w = XtCreateManagedWidget (name,
+ *classrec->widget_class, pw, args, nargs);
+ }
+ }
+
+ /* Set the pointer to the superclass if subclass of Widget. */
+ if (strcmp (classrec->name, "Widget") != 0)
+ obj->core.superclass = obmGetClassrec ("Widget");
+
+ /* Register any class callback procedures. */
+ if (obmClass (classrec, WtGrip) ||
+ obmClass (classrec, WtList) ||
+ obmClass (classrec, WtMultiList) ||
+ obmClass (classrec, WtSmeBSB) ||
+ obmClass (classrec, WtCommand) ||
+ obmClass (classrec, WtMenuButton) ||
+ obmClass (classrec, WtTabs) ||
+ obmClass (classrec, WtToggle) ||
+ obmClass (classrec, WtArrow)) {
+
+ XtAddCallback (w, XtNcallback, widgetCallback, obj);
+
+ } else if (obmClass (classrec, WtListTree)) {
+ XtAddCallback (w, XtNhighlightCallback, widgetLTHCallback, obj);
+ XtAddCallback (w, XtNactivateCallback, widgetLTACallback, obj);
+
+ } else if (obmClass (classrec, WtRepeater)) {
+ XtAddCallback (w, XtNcallback, widgetCallback, obj);
+ XtAddCallback (w, XtNstartCallback, widgetSBCallback, obj);
+ XtAddCallback (w, XtNstopCallback, widgetSECallback, obj);
+
+ } else if (obmClass (classrec, WtStripChart)) {
+ XtAddCallback (w, XtNgetValue, widgetSCCallback, obj);
+
+ } else if (obmClass (classrec, WtScrollbar)) {
+ XtAddCallback (w, XtNjumpProc, widgetJPCallback, obj);
+ XtAddCallback (w, XtNscrollProc, widgetSPCallback, obj);
+
+ } else if (obmClass (classrec, WtShell) ||
+ obmClass (classrec, WtSimpleMenu)) {
+
+ XtAddCallback (w, XtNpopupCallback, widgetPUCallback, obj);
+ XtAddCallback (w, XtNpopdownCallback, widgetPDCallback, obj);
+
+ } else if (obmClass (classrec, WtPanner) ||
+ obmClass (classrec, WtPorthole) ||
+ obmClass (classrec, WtViewport)) {
+
+ XtAddCallback (w, XtNreportCallback, widgetRPCallback, obj);
+
+ } else if (obmClass (classrec, WtTextButton) ||
+ obmClass (classrec, WtIcon)) {
+ XtAddCallback (w, XtNactivate, widgetCallback, obj);
+
+ } else if (obmClass (classrec, WtGroup) ||
+ obmClass (classrec, WtRadioGroup)) {
+ XtAddCallback (w, XtNactivate, widgetRGCallback, obj);
+
+ } else if (obmClass (classrec, WtTextToggle)) {
+ XtAddCallback (w, XtNonCallback, widgetCallback, obj);
+ XtAddCallback (w, XtNoffCallback, widgetCallback, obj);
+
+ } else if (obmClass (classrec, WtSlider2d) ||
+ obmClass (classrec, WtScrollbar2)) {
+
+ XtVaGetValues (w, "scrollResponse", &obj->widget.response_cb, NULL);
+ XtAddCallback (w, XtNscrollCallback, widgetJPCallback, obj);
+ XtAddCallback (w, XtNscrollCallback, widgetSPCallback, obj);
+ }
+
+ obj->widget.w = w;
+ strcpy (obj->widget.translation_table_name, name);
+ return ((ObmObject) obj);
+}
+
+
+/* WidgetDestroy -- Destroy an instance of a widget object.
+ */
+void
+WidgetDestroy (object)
+ObmObject object;
+{
+ register WidgetObject obj = (WidgetObject) object;
+ register WidgetPrivate wp = &obj->widget;
+ register ObmCallback cb, next;
+
+ /* Ignore the second call to Destroy. */
+ if (obj->core.being_destroyed++)
+ return;
+
+ /* Free any callback descriptors. */
+ for (cb = wp->callback; cb; cb = next) {
+ next = cb->next;
+ XtFree ((char *)cb);
+ }
+
+ /* Free any event handler descriptors. */
+ for (cb = wp->event_handler; cb; cb = next) {
+ next = cb->next;
+ XtFree ((char *)cb);
+ }
+
+ /* Free any object data. Note that free is used, not XtFree, i.e.
+ * we can't assume that Xt allocated the buffer.
+ */
+ if (wp->data)
+ free (wp->data);
+
+ /* Mark any widget children as being destroyed so that we don't try
+ * to destroy them twice.
+ */
+ if (!wp->widget_destroyed) {
+ widgetSetDestroy (object);
+ widgetDestroy (obj);
+ }
+}
+
+
+/* widgetSetDestroy -- Set the being_destroyed flag on all the children of a
+ * widget object to indicate that the widget itself has already been destroyed.
+ * This happens when a widget tree is destroyed in one toolkit call by
+ * destroying the top level widget, leaving the object descriptors intact
+ * while the widgets have already been destroyed.
+ */
+static void
+widgetSetDestroy (obj)
+register ObmObject obj;
+{
+ register int i;
+ ObmObject child;
+ int object_type;
+
+ for (i=0; i < obj->core.nchildren; i++) {
+ child = obj->core.children[i];
+ object_type = child->core.classrec->object_type;
+ if (object_type == OtShell || object_type == OtNonShell)
+ widgetSetDestroy (child);
+ }
+
+ ((WidgetObject)obj)->widget.widget_destroyed = True;
+}
+
+
+/* widgetDestroy -- Destroy a widget and all of its descendents. We can't
+ * just call XtDestroyWidget to do this because while this will destroy all
+ * the normal and popup children of a widget, it won't destroy any top level
+ * shells and their children.
+ */
+static void
+widgetDestroy (obj)
+register ObmObject obj;
+{
+ register int i;
+ WidgetObject wobj = (WidgetObject) obj;
+ WidgetClass *widget_class;
+ ObmObject child;
+ int object_type;
+
+ for (i=0; i < obj->core.nchildren; i++) {
+ child = obj->core.children[i];
+ widget_class = child->core.classrec->widget_class;
+ if (widget_class == &topLevelShellWidgetClass)
+ widgetDestroy (child);
+ }
+
+ XtUnrealizeWidget (wobj->widget.w);
+ XtDestroyWidget (wobj->widget.w);
+}
+
+
+/* WidgetEvaluate -- Evaluate a widget command or message.
+ */
+WidgetEvaluate (object, command)
+ObmObject object;
+char *command;
+{
+ register WidgetObject obj = (WidgetObject) object;
+ register Tcl_Interp *tcl, *server = obj->widget.obm->tcl;
+ MsgContext omsg = (MsgContext) obj->core.classrec->class_data;
+ MsgContext pmsg = (MsgContext) obj->core.superclass->class_data;
+
+ /* Since the class wide interpreter is used to evaluate the message
+ * we can't pass the object descriptor directly to the class procedure
+ * referenced in the message. Instead we pass the object reference
+ * in the message descriptor.
+ */
+ Tcl_SetResult (server, "", TCL_STATIC);
+
+ /* First try to get the widget subclass to accept the message. */
+ if (omsg && (tcl = omsg->tcl) && obmClientCommand(tcl,command)) {
+ omsg->object[++omsg->level] = object;
+ if (Tcl_Eval (tcl, command) == TCL_OK) {
+ if (*tcl->result)
+ Tcl_SetResult (server, tcl->result, TCL_VOLATILE);
+ omsg->level--;
+ return (TCL_OK);
+
+ } else {
+ static char invalid[] = "invalid command name";
+ omsg->level--;
+
+ /* Exit with an error return if the class code recognized
+ * the command but failed to execute it.
+ */
+ if (strncmp (tcl->result, invalid, strlen(invalid)) != 0)
+ goto error;
+ }
+ }
+
+ /* If the subclass code did not recognize the command pass the
+ * message on to the base Widget class.
+ */
+ if (pmsg && pmsg != omsg && (tcl = pmsg->tcl) &&
+ obmClientCommand(tcl,command)) {
+ pmsg->object[++pmsg->level] = object;
+ if (Tcl_Eval (tcl, command) == TCL_OK) {
+ if (*tcl->result)
+ Tcl_SetResult (server, tcl->result, TCL_VOLATILE);
+ pmsg->level--;
+ return (TCL_OK);
+ } else
+ pmsg->level--;
+ }
+
+error:
+ if (*tcl->result)
+ Tcl_SetResult (server, tcl->result, TCL_VOLATILE);
+ else {
+ /* Supply a default error message if none was returned. */
+ Tcl_SetResult (server, obmClientCommand (tcl, command) ?
+ "evaluation error" : "invalid command", TCL_VOLATILE);
+ }
+ server->errorLine = tcl->errorLine;
+ return (TCL_ERROR);
+}
+
+
+/* widgetGetPointer -- Return the widget descriptor for an object of class
+ * widget. Used by non-widget Obm code to get the widget handle from an
+ * object descriptor.
+ */
+Widget
+widgetGetPointer (object)
+ObmObject object;
+{
+ register WidgetObject obj = (WidgetObject) object;
+ return (obj->widget.w);
+}
+
+
+/* widgetToObject -- Convert a widget pointer to an OBM object name.
+ */
+WidgetObject
+widgetToObject (obm, w)
+ObmContext obm;
+Widget w;
+{
+ register int i;
+ register WidgetPrivate wp;
+ ObmObject objs[256];
+ int nobjs;
+
+ obm_nameToObjectList (obm, XtName(w), NULL, &nobjs, objs);
+ for (i=0; i < nobjs; i++)
+ wp = &((WidgetObject)objs[i])->widget;
+ if (wp->w == w)
+ return ((WidgetObject)objs[i]);
+
+ return (NULL);
+}
+
+
+/* widgetAddCallback -- Add a callback procedure to the callback list for
+ * a widget. If no callback name is given, "callback" is assumed.
+ *
+ * Usage: addCallback <procedure-name> [<callback-name>]
+ *
+ * Specific widgets only support certain types of callbacks. There is no
+ * checking that the callback type specified is supported by a widget; the
+ * wrong type of callback can be registered, but it will never be called.
+ */
+static int
+widgetAddCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmCallback cb, new_cb;
+ char *s_proc, *s_type;
+ int callback_type, i;
+
+ s_proc = argv[1];
+ s_type = (argc > 2) ? argv[2] : NULL;
+
+ /* Determine callback type. */
+ if (s_type) {
+ callback_type = Ctcallback;
+ for (i=0; i < XtNumber(callbackTypes); i++)
+ if (strcmp (s_type, callbackTypes[i].name) == 0) {
+ callback_type = callbackTypes[i].type;
+ break;
+ }
+ } else if (obmClass (obj->core.classrec, WtAsciiText)) {
+ callback_type = Ctlinemode;
+ } else if (obmClass (obj->core.classrec, WtPanner) ||
+ obmClass (obj->core.classrec, WtPorthole) ||
+ obmClass (obj->core.classrec, WtViewport)) {
+ callback_type = CtreportCallback;
+ } else if (obmClass (obj->core.classrec, WtSlider2d) ||
+ obmClass (obj->core.classrec, WtScrollbar2) ||
+ obmClass (obj->core.classrec, WtScrollbar)) {
+ callback_type = CtjumpProc;
+ } else
+ callback_type = Ctcallback;
+
+ /* Special handling for asciiText callbacks. */
+ if (obmClass (obj->core.classrec, WtAsciiText))
+ if (callback_type == Ctlinemode) {
+ char text_translations[SZ_LINE];
+ XtTranslations translations;
+ sprintf (text_translations, "<Key>Return: do_text(0x%lx, %s) ",
+ wp->obm, XtName(wp->w));
+ translations = XtParseTranslationTable (text_translations);
+ XtOverrideTranslations (wp->w, translations);
+ } else {
+ XtAddCallback (XawTextGetSource(wp->w), XtNcallback,
+ widgetCallback, obj);
+ }
+
+ /* Create callback record. */
+ new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ new_cb->callback_type = callback_type;
+ strncpy (new_cb->name, s_proc, SZ_NAME);
+
+ /* Add callback to tail of callback list. */
+ if (wp->callback) {
+ for (cb = wp->callback; cb->next; cb = cb->next)
+ ;
+ cb->next = new_cb;
+ } else
+ wp->callback = new_cb;
+
+ return (TCL_OK);
+}
+
+
+/* widgetDeleteCallback -- Delete a callback procedure previously registered
+ * for a widget.
+ *
+ * Usage: deleteCallback <procedure-name>
+ */
+static int
+widgetDeleteCallback (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ ObmCallback cb, prev;
+
+ /* Locate and delete procedure entry in callback list. */
+ for (prev=NULL, cb=wp->callback; cb; prev=cb, cb=cb->next)
+ if (strcmp (cb->name, argv[1]) == 0) {
+ if (prev)
+ prev->next = cb->next;
+ else
+ wp->callback = cb->next;
+ XtFree ((char *)cb);
+ break;
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetCallback -- Generic callback procedure, used for most widgets.
+ * The callback procedure is called with the widget name as the first
+ * argument, followed by zero or more additional arguments which depend upon
+ * the callback type.
+ */
+static void
+widgetCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ register ObjClassRec classrec = obj->core.classrec;
+ char buffer[SZ_COMMAND];
+ char *message = buffer;
+ int callback_type, i;
+
+ /* Default callback type. */
+ callback_type = Ctcallback;
+
+ if (obmClass (classrec, WtAsciiSrc) ||
+ obmClass (classrec, WtAsciiText)) {
+
+ char *string;
+ Arg args[1];
+
+ XtSetArg (args[0], "string", &string);
+ XtGetValues (wp->w, args, 1);
+ sprintf (message, "{%s}", string);
+ callback_type = Ctcharmode;
+
+ } else if (obmClass (classrec, WtGrip)) {
+ GripCallDataRec *grip = (GripCallDataRec *) call_data;
+
+ /* The message, if any, is given in the grip translation table
+ * as the arguments to the GripAction routine. These differ
+ * depending upon the event; we just pass on the arguments and
+ * ignore the event attributes.
+ */
+ message[0] = '\0';
+ for (i=0; i < grip->num_params; i++) {
+ strcat (message, " ");
+ strcat (message, grip->params[i]);
+ }
+
+ } else if (obmClass (classrec, WtList)) {
+ XawListReturnStruct *list = (XawListReturnStruct *) call_data;
+
+ /* The message is the string value of the list element
+ * selected, followed by its index.
+ */
+ sprintf (message, "{%s} %d", list->string, list->list_index);
+
+ } else if (obmClass (classrec, WtMultiList)) {
+ XfwfMultiListReturnStruct *list =
+ (XfwfMultiListReturnStruct *) call_data;
+ Boolean state, sensitive;
+ register char *ip, *op;
+ int buflen, need, i;
+ char *string;
+
+ /* The message consists of an array of string values of the
+ * currently selected list elements in the form { {s} {s} ...},
+ * followed by a array of the indices { n n ...}.
+ */
+ buflen = SZ_COMMAND;
+ if (!(message = XtMalloc (buflen)))
+ return;
+
+ /* Generate list of item strings. */
+ op = message;
+ *op++ = '{';
+ for (i=0; i < list->num_selected; i++) {
+ XfwfMultiListGetItemInfo ((XfwfMultiListWidget)wp->w,
+ list->selected_items[i], &string, &state, &sensitive);
+ need = strlen(string)+3 + list->num_selected * 6;
+ if (buflen < (op-message)+need) {
+ buflen += max (need, SZ_COMMAND);
+ if (!(message = XtRealloc (buffer, buflen)))
+ return;
+ }
+ *op++ = ' ';
+ *op++ = '{';
+ for (ip=string; *op = *ip++; op++)
+ ;
+ *op++ = '}';
+ }
+ *op++ = ' ';
+ *op++ = '}';
+
+ /* Append list of indices. We allocated space for these above. */
+ *op++ = ' ';
+ *op++ = '{';
+ for (i=0; i < list->num_selected; i++) {
+ sprintf (op, " %d", list->selected_items[i]);
+ while (*op)
+ op++;
+ }
+ *op++ = ' ';
+ *op++ = '}';
+ *op++ = '\0';
+
+ } else if (obmClass (classrec, WtToggle)) {
+ Arg args[1];
+ Boolean state;
+
+ /* The callback for a toggle does not pass any call data,
+ * but we return the value of the "state" resource anyway
+ * to indicate the state of the toggle.
+ */
+ XtSetArg (args[0], XtNstate, &state);
+ XtGetValues (wp->w, args, 1);
+ sprintf (message, "%s", state ? TRUESTR : FALSESTR);
+
+ } else if (obmClass (classrec, WtTextToggle)) {
+ Arg args[1];
+ Boolean state;
+
+ /* For this widget the value of the "on" resource indicates
+ * the state of the toggle.
+ */
+ XtSetArg (args[0], XtNon, &state);
+ XtGetValues (wp->w, args, 1);
+ sprintf (message, "%s", state ? TRUESTR : FALSESTR);
+
+ } else {
+ /* The default case, which works for most simple callbacks.
+ * Only the widget name is returned.
+ */
+ message = NULL;
+ }
+
+ call_callbacks (obj, callback_type, message);
+
+ if (message && message != buffer)
+ XtFree (message);
+}
+
+
+/* widgetRGCallback -- Radiogroup or Group callback. The argument list for
+ * the callback is one of the following:
+ *
+ * selectionStyle = multiple: widget-name { label label ... }
+ * selectionStyle = one,single: widget-name [label | "none"]
+ *
+ * Here label refers to the label of the selected TextToggle widget or widgets.
+ * In the case of selectionStyle=multiple, the list will be empty if no widgets
+ * are currently selected.
+ */
+static void
+widgetRGCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ long selection = (long) call_data;
+ register char *op;
+ register int i;
+
+ char message[SZ_COMMAND];
+ SelectionType selectionType;
+ WidgetList children;
+ Cardinal nchildren;
+ Arg args[10];
+ char *label;
+
+ /* Get list of child widgets in the group. */
+ XtSetArg (args[0], XtNselectionStyle, &selectionType);
+ XtSetArg (args[1], XtNnumChildren, &nchildren);
+ XtSetArg (args[2], XtNchildren, &children);
+ XtGetValues (wp->w, args, 3);
+
+ op = message;
+ if (selectionType == XfwfMultipleSelection) {
+ *op++ = '{';
+ for (i=0; selection > 0 && i < min(32,nchildren); i++)
+ if (selection & (1 << i)) {
+ XtSetArg (args[0], XtNlabel, &label);
+ XtGetValues (children[i], args, 1);
+ *op++ = ' ';
+ sprintf (op, "\"%s\"", label);
+ while (*op)
+ op++;
+ }
+ *op++ = '}';
+
+ } else {
+ if (selection < 0 || selection >= nchildren)
+ label = "none";
+ else {
+ XtSetArg (args[0], XtNlabel, &label);
+ XtGetValues (children[selection], args, 1);
+ }
+ sprintf (op, "\"%s\"", label);
+ while (*op)
+ op++;
+ }
+ *op++ = '\0';
+
+ call_callbacks (obj, Ctcallback, message);
+}
+
+
+/* widgetLTHCallback -- ListTree highlight callback.
+ */
+static void
+widgetLTHCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ ListTreeMultiReturnStruct *list;
+ ListTreeItem *item;
+ char message[SZ_COMMAND], buf[SZ_LINE];
+ register int i;
+
+ list = (ListTreeMultiReturnStruct *) call_data;
+ if (!list->items)
+ return;
+
+
+ /* The message is the string value of the list element selected
+ * and a bottom-up path to the root.
+ */
+ sprintf (message, "{%s %d} ",
+ list->items[0]->text, list->items[0]->open);
+
+ strncat (message, "{ ", 2);
+ for (i=0; i < list->count; i++) {
+ item = list->items[i];
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ while (item->parent) {
+ item = item->parent;
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ }
+ }
+ strncat (message, "}", 1);
+
+ call_callbacks (obj, Ctcallback, message);
+}
+
+
+/* widgetLTACallback -- ListTree activate callback.
+ */
+static void
+widgetLTACallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ ListTreeActivateStruct *ret;
+ ListTreeMultiReturnStruct ret2;
+ ListTreeItem *item;
+ char message[SZ_COMMAND], buf[SZ_LINE];
+ int i, count;
+
+ ret = (ListTreeActivateStruct *) call_data;
+
+ /* The message is the string value of the list element selected,
+ * and a bottom-up path to the root.
+ */
+ sprintf (message, "{%s %d} ", ret->item->text, ret->item->open);
+
+ strncat (message, "{ ", 2);
+ item = ret->item;
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ while (item->parent) {
+ item = item->parent;
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ }
+ strncat (message, "}", 1);
+
+ call_callbacks (obj, Ctcallback, message);
+}
+
+
+/* widgetSBCallback -- Repeater start callback.
+ */
+static void
+widgetSBCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ call_callbacks (obj, CtstartCallback, NULL);
+}
+
+
+/* widgetSECallback -- Repeater stop callback.
+ */
+static void
+widgetSECallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ call_callbacks (obj, CtstopCallback, NULL);
+}
+
+
+/* widgetRPCallback -- Report callback used by the panner, porthole, and
+ * viewport widgets to report any changes in the position or size of the
+ * thumb (panner) or child widget (porthole, viewport).
+ */
+static void
+widgetRPCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ register XawPannerReport *rp = (XawPannerReport *) call_data;
+ char message[100];
+
+ /* Return args: changed x y w h cw ch */
+ sprintf (message, "0%o %d %d %d %d %d %d", rp->changed,
+ rp->slider_x, rp->slider_y, rp->slider_width, rp->slider_height,
+ rp->canvas_width, rp->canvas_height);
+
+ call_callbacks (obj, CtreportCallback, message);
+}
+
+
+/* widgetJPCallback -- Jump callback for the scroll bar widget. This is
+ * called when the thumb port of the scroll bar is dragged or moved (button 2).
+ */
+static void
+widgetJPCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ XfwfScrollInfo *info = (XfwfScrollInfo *) call_data;
+ XfwfScrollInfo update_info;
+ register int flags = info->flags;
+ char message[100];
+
+ if (obmClass (obj->core.classrec, WtScrollbar)) {
+ /* Athena scrollbar. The call_data gives the position of the
+ * thumb in percent.
+ */
+ sprintf (message, "%0.6f", *((float *)call_data));
+ call_callbacks (obj, CtjumpProc, message);
+
+ } else if (info->reason != XfwfSDrag) {
+ /* Slider2d callback: widget-name x y
+ * Scrollbar2 callback: widget-name fraction
+ *
+ * Scrollbars return the same fraction value regardless of
+ * whether the scrollbar is vertical or horizontal.
+ * widgetSPCallback below is always called when the slider moves,
+ * so we don't need to call response_cb here.
+ */
+ if (obmClass (obj->core.classrec, WtSlider2d)) {
+ XfwfGetThumb (wp->w, &update_info);
+ sprintf (message, "%0.5f %0.5f",
+ (flags & XFWF_HPOS) ? info->hpos : update_info.hpos,
+ (flags & XFWF_VPOS) ? info->vpos : update_info.vpos);
+ } else {
+ if (info->flags & XFWF_HPOS)
+ sprintf (message, "%0.5f", info->hpos);
+ else if (info->flags & XFWF_VPOS)
+ sprintf (message, "%0.5f", info->vpos);
+ }
+
+ /* Call the callbacks. */
+ call_callbacks (obj, CtjumpProc, message);
+ }
+}
+
+
+/* widgetSPCallback -- Scroll callback for the scroll bar widget. This is
+ * used for incremental scrolling (button 1 or 3).
+ */
+static void
+widgetSPCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ char message[100];
+
+ if (obmClass (obj->core.classrec, WtScrollbar)) {
+ /* Athena scrollbar. The call_data gives the distance in pixels
+ * of the pointer from the top of the scrollbar, and is positive
+ * for button 1 and negative for button 3.
+ */
+ sprintf (message, "%d", (int)call_data);
+ call_callbacks (obj, CtscrollProc, message);
+
+ } else {
+ /* FWF scrollbar2 or slider2d.
+ */
+ XfwfScrollInfo *info = (XfwfScrollInfo *) call_data;
+ XfwfScrollInfo update_info;
+ register int flags = info->flags;
+
+ /* Slider2d callback: widget-name x y
+ * Scrollbar2 callback: widget-name fraction
+ *
+ * Scrollbars return the same fraction value regardless of
+ * whether the scrollbar is vertical or horizontal.
+ */
+ if (obmClass (obj->core.classrec, WtSlider2d)) {
+ XfwfGetThumb (wp->w, &update_info);
+ sprintf (message, "%0.5f %0.5f",
+ (flags & XFWF_HPOS) ? info->hpos : update_info.hpos,
+ (flags & XFWF_VPOS) ? info->vpos : update_info.vpos);
+ } else {
+ if (flags & XFWF_HPOS)
+ sprintf (message, "%0.5f", info->hpos);
+ else if (flags & XFWF_VPOS)
+ sprintf (message, "%0.5f", info->vpos);
+ }
+
+ /* Call the callbacks. */
+ call_callbacks (obj, CtscrollProc, message);
+
+ /* Update the slider. */
+ update_info = *info;
+ update_info.reason = XfwfSNotify;
+ wp->response_cb (NULL, w, (caddr_t) &update_info);
+ }
+}
+
+
+/* widgetSCCallback -- Strip chart callback procedure. This is called by the
+ * strip chart widget every "update" seconds to get the next value to be
+ * plotted.
+ */
+static void
+widgetSCCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ char *callback_name;
+ ObmCallback cb;
+ double atof();
+ int status, i;
+
+ callback_name = "getValue";
+ for (i=0; i < XtNumber(callbackTypes); i++)
+ if (callbackTypes[i].type == CtgetValue) {
+ callback_name = callbackTypes[i].name;
+ break;
+ }
+
+ /* Call the callback procedure to get the next value to be plotted
+ * in the strip chart. This is a numeric (e.g. floating point) value
+ * returned as the function value of the callback procedure. Multiple
+ * callbacks can be registered, but only the first such procedure
+ * will be called.
+ */
+ for (cb = wp->callback; cb; cb = cb->next) {
+ if (cb->callback_type != CtgetValue)
+ continue;
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ callback_name, " ",
+ NULL);
+ if (status == TCL_OK)
+ *((double *)call_data) = atof (obm->tcl->result);
+ else {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+ break;
+ }
+}
+
+
+/* widgetPUCallback -- Popup callback, used by the shell and simpleMenu
+ * widgets. Called when the window pops up.
+ */
+static void
+widgetPUCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ call_callbacks (obj, CtpopupCallback, NULL);
+}
+
+
+/* widgetPDCallback -- Popdown callback, used by the shell and simpleMenu
+ * widgets. Called when the window pops down.
+ */
+static void
+widgetPDCallback (w, obj, call_data)
+Widget w;
+WidgetObject obj;
+caddr_t call_data;
+{
+ register WidgetPrivate wp = &obj->widget;
+ call_callbacks (obj, CtpopdownCallback, NULL);
+}
+
+
+/* call_callbacks -- Call all the callbacks of the given type for the given
+ * widget object, passing the given message on the argument list.
+ */
+static void
+call_callbacks (obj, callback_type, message)
+WidgetObject obj;
+int callback_type;
+char *message;
+{
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register ObmCallback cb;
+ char *callback_name;
+ int status, i;
+
+ callback_name = callbackTypes[0].name;
+ for (i=0; i < XtNumber(callbackTypes); i++)
+ if (callback_type == callbackTypes[i].type) {
+ callback_name = callbackTypes[i].name;
+ break;
+ }
+
+ /* Deliver the message to all the callback procedures registered for
+ * this widget for which the callback type matches. The callback
+ * arguments are:
+ *
+ * widget-name callback-name callback-args
+ *
+ * where the callback-args depend on the callback.
+ */
+ for (cb = wp->callback; cb; cb = cb->next) {
+ if (cb->callback_type != callback_type)
+ continue;
+
+ if (message) {
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ callback_name, " ",
+ message, " ",
+ NULL);
+ } else {
+ status = Tcl_VarEval (obm->tcl,
+ cb->name, " ",
+ obj->core.name, " ",
+ callback_name, " ",
+ NULL);
+ }
+
+ if (status != TCL_OK) {
+ char *errstr = Tcl_GetVar (obm->tcl, "errorInfo", 0);
+ fprintf (stderr, "Error on line %d in %s: %s\n",
+ obm->tcl->errorLine, cb->name,
+ errstr ? errstr : obm->tcl->result);
+ }
+ }
+}
+
+
+/* do_text -- Translation action procedure for the text widget, called when
+ * return is typed to process an input string ("linemode" callback type).
+ */
+static void
+do_text (w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ char *message, *s;
+ WidgetObject obj;
+ ObmCallback cb;
+ Arg args[1];
+
+ /* do_text (0xXXXX, object-name) */
+ if (*num_params >= 2) {
+ ObmContext obm = (ObmContext) strtol (params[0], NULL, 0);
+ char *object = params[1];
+
+ if (obm && (obj = (WidgetObject) obmFindObject (obm, object))) {
+ XtSetArg (args[0], XtNstring, &s);
+ XtGetValues (obj->widget.w, args, 1);
+
+ if (!(message = XtMalloc (strlen(s) + 10)))
+ return;
+ sprintf (message, "{%s}", s);
+
+ call_callbacks (obj, Ctlinemode, message);
+ XtFree (message);
+ }
+ }
+}
+
+
+/* do_userproc -- Translation action procedure used to call general user
+ * action procedures in the interpreter. The name of the user procedure to
+ * be called is given as the first argument in the translation. For example,
+ * the translation "call(foo,a,b,c)" would cause procedure foo to be called
+ * with the arguments (a,b,c). The following arguments are special:
+ *
+ * Argument Replaced by
+ *
+ * $name translation table name (defaults to widget name)
+ * $time event->time
+ * $x event->x
+ * $y event->y
+ * $x_root event->x_root
+ * $y_root event->y_root
+ *
+ * The "user procedure" can be any server procedure.
+ */
+static void
+do_userproc (w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ register char *ip, *op;
+ ObmContext obm = global_obm_handle;
+ char cmd[SZ_COMMAND], *param;
+ int x, y, x_root, y_root;
+ int status, arg;
+ Time time;
+
+ if (*num_params < 1)
+ return;
+
+ time = 0;
+ x = y = 0;
+ x_root = y_root = 0;
+
+ /* Get common event parameters. */
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyEvent *ev = (XKeyEvent *) event;
+ time = ev->time;
+ x = ev->x; y = ev->y;
+ x_root = ev->x_root; y_root = ev->y_root;
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonEvent *ev = (XButtonEvent *) event;
+ time = ev->time;
+ x = ev->x; y = ev->y;
+ x_root = ev->x_root; y_root = ev->y_root;
+ }
+ break;
+ case MotionNotify:
+ { XMotionEvent *ev = (XMotionEvent *) event;
+ time = ev->time;
+ x = ev->x; y = ev->y;
+ x_root = ev->x_root; y_root = ev->y_root;
+ }
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ { XCrossingEvent *ev = (XCrossingEvent *) event;
+ time = ev->time;
+ x = ev->x; y = ev->y;
+ x_root = ev->x_root; y_root = ev->y_root;
+ }
+ break;
+ }
+
+ /* Copy name of server procedure to be called. */
+ for (ip=params[0], op=cmd; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+
+ /* Copy the remaining arguments. */
+ for (arg=1; arg < *num_params; arg++) {
+ param = params[arg];
+ if (*param == '$') {
+ if (strcmp (param, "$name") == 0) {
+ /* Return the current translation table name for the
+ * widget (defaults to the widget name).
+ */
+ WidgetObject obj;
+ char *name;
+
+ if (obj = widgetToObject (obm, w))
+ name = obj->widget.translation_table_name;
+ else
+ name = XtName (w);
+
+ for (ip = name; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+
+ } else if (strcmp (param, "$time") == 0) {
+ sprintf (op, "%u ", time);
+ while (*op)
+ op++;
+ } else if (strcmp (param, "$x") == 0) {
+ sprintf (op, "%d ", x);
+ while (*op)
+ op++;
+ } else if (strcmp (param, "$y") == 0) {
+ sprintf (op, "%d ", y);
+ while (*op)
+ op++;
+ } else if (strcmp (param, "$x_root") == 0) {
+ sprintf (op, "%d ", x_root);
+ while (*op)
+ op++;
+ } else if (strcmp (param, "$y_root") == 0) {
+ sprintf (op, "%d ", y_root);
+ while (*op)
+ op++;
+ } else {
+ for (ip=param; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+ }
+ } else {
+ for (ip=param; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+ }
+ }
+
+ *op = '\0';
+ status = Tcl_Eval (obm->tcl, cmd);
+ if (status != TCL_OK) {
+ fprintf (stderr, "Error on line %d of %s: %s\n",
+ obm->tcl->errorLine, params[0], obm->tcl->result);
+ }
+}
+
+
+/* widgetSetTTName -- Set the translation table name for a widget. This
+ * is the name passed in the $name field of a translation table action
+ * procedure called with the "call" action from a translation table.
+ *
+ * Usage: setTTName name
+ *
+ * The default translation table name is the name of the widget. Note that
+ * some widget subclasses (e.g. marker) may set the translation table name
+ * automatically when the widget changes the translation table.
+ */
+static int
+widgetSetTTName (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ widget_setTTName (obj, argv[1]);
+ return (TCL_OK);
+}
+
+void
+widget_setTTName (obj, name)
+WidgetObject obj;
+char *name;
+{
+ register WidgetPrivate wp = &obj->widget;
+ strncpy (wp->translation_table_name, name, SZ_NAME);
+ wp->translation_table_name[SZ_NAME-1] = '\0';
+}
+
+
+/* widgetGetTTName -- Get the translation table name for a widget.
+ *
+ * Usage: name = getTTName
+ */
+static int
+widgetGetTTName (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ register WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+
+ Tcl_SetResult (wp->obm->tcl, widget_getTTName(obj), TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+char *
+widget_getTTName (obj)
+WidgetObject obj;
+{
+ register WidgetPrivate wp = &obj->widget;
+ return (wp->translation_table_name);
+}
+
+
+/* do_popup -- Popup a menu (or other spring loaded popup) at the location
+ * of the event which triggered this action.
+ *
+ * Usage: popup(menu-name [xoffset [yoffset]])
+ */
+static void
+do_popup (w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ register char *ip, *op;
+ ObmContext obm = global_obm_handle;
+ XKeyEvent *ev = (XKeyEvent *) event;
+ Boolean spring_loaded;
+ Dimension menu_width, menu_height, menu_borderWidth;
+ Position menu_x, menu_y;
+ int xoffset, yoffset;
+ char *menu_name;
+ WidgetObject obj;
+ Widget menu;
+
+ if (*num_params < 1)
+ return;
+
+ menu_name = params[0];
+ xoffset = (*num_params >= 2) ? atoi(params[1]) : -10;
+ yoffset = (*num_params >= 3) ? atoi(params[2]) : -10;
+
+ if (!(obj = (WidgetObject) obmFindObject (obm, menu_name)))
+ return;
+ else
+ menu = obj->widget.w;
+
+ /* Evidently SimpleMenu requires that the following be called to
+ * properly initialize things.
+ */
+ if (obmClass (obj->core.classrec, WtSimpleMenu))
+ XtCallActionProc (XtParent(menu), "XawPositionSimpleMenu",
+ event, params, *num_params);
+
+ XtVaGetValues (menu,
+ XtNwidth, &menu_width,
+ XtNheight, &menu_height,
+ XtNborderWidth, &menu_borderWidth,
+ NULL);
+
+ menu_width = menu_width + 2 * menu_borderWidth;
+ menu_height = menu_height + 2 * menu_borderWidth;
+ menu_x = ev->x_root + xoffset;
+ menu_y = ev->y_root + yoffset;
+
+ if (menu_x >= 0) {
+ int scr_width = WidthOfScreen(XtScreen(menu));
+ if ((int)(menu_x + menu_width) > scr_width)
+ menu_x = scr_width - menu_width;
+ }
+ if (menu_x < 0)
+ menu_x = 0;
+
+ if (menu_y >= 0) {
+ int scr_height = HeightOfScreen(XtScreen(menu));
+ if ((int)(menu_y + menu_height) > scr_height)
+ menu_y = scr_height - menu_height;
+ }
+ if (menu_y < 0)
+ menu_y = 0;
+
+ XtVaSetValues (menu,
+ XtNx, menu_x,
+ XtNy, menu_y,
+ NULL);
+
+ if (event->type == ButtonPress)
+ spring_loaded = True;
+ else if (event->type == KeyPress || event->type == EnterNotify)
+ spring_loaded = False;
+ else {
+ /* should not happen. */
+ spring_loaded = False;
+ }
+
+ if (spring_loaded)
+ XtPopupSpringLoaded (menu);
+ else
+ XtPopup (menu, XtGrabNonexclusive);
+}
+
+
+/* do_popdown -- Pop down a menu.
+ *
+ * Usage: popdown(menu-name)
+ */
+static void
+do_popdown (w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ register char *ip, *op;
+ ObmContext obm = global_obm_handle;
+ XKeyEvent *ev = (XKeyEvent *) event;
+ char *menu_name;
+ WidgetObject obj;
+ Widget menu;
+
+ if (*num_params < 1)
+ return;
+
+ menu_name = params[0];
+ if (obj = (WidgetObject) obmFindObject (obm, menu_name)) {
+ menu = obj->widget.w;
+ XtPopdown (menu);
+ }
+}
+
+
+/* widgetSet -- Set a widget resource.
+ *
+ * Usage: set <resource-name> <value>
+ */
+static int
+widgetSet (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ register char *ip;
+ register int hashval, n;
+ register Rtype rp;
+ XrmValue from, to;
+ Arg args[1];
+
+ /* Lookup resource. There can be multiple entries for a given resource
+ * if the resource has a different type in different widgets. A
+ * resource entry can be used only if both the name matches and the
+ * bitflags indicate that the target widget uses the resource.
+ */
+ for (hashval=0, ip=argv[1], n=MAX_HASHCHARS; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+
+ if (rp = rhash[hashval%LEN_RHASH]) {
+ for ( ; rp; rp = rp->next)
+ if (!strcmp(rp->name,argv[1]) &&
+ obmClass (obj->core.classrec, rp->flag1, rp->flag2))
+ break;
+ }
+
+ /* For a string type resource, no value string arg indicates the
+ * null string.
+ */
+ if (!rp || argc < 3 && strcmp (rp->type, XtRString))
+ return (TCL_ERROR);
+
+ /* If the resource entry was found, convert the resource value
+ * from a string to whatever the resource type is, and set the
+ * resource value.
+ */
+ from.size = strlen (argv[2]) + 1;
+ from.addr = argv[2];
+
+ if (strcmp (rp->type, XtRString) == 0) {
+ XtSetArg (args[0], rp->name, argc < 3 ? "" : argv[2]);
+ XtSetValues (wp->w, args, 1);
+
+ /* The following is for text widgets. */
+ if (obmClass (obj->core.classrec, WtAsciiText)) {
+ register ObmCallback cb;
+
+ wp->text_newline = 0;
+ wp->text_pos = strlen (argv[2]);
+
+ /* If linemode is in effect set insertion point to EOL. */
+ for (cb = wp->callback; cb; cb = cb->next)
+ if (cb->callback_type == Ctlinemode) {
+ XawTextSetInsertionPoint (wp->w, wp->text_pos);
+ break;
+ }
+ }
+
+ } else if (strcmp (rp->type, XtRDimension) == 0 ||
+ strcmp (rp->type, XtRPosition) == 0) {
+
+ Dimension value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRBool) == 0 ||
+ strcmp (rp->type, XtRBoolean) == 0) {
+
+ Boolean value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. The numeric values "0" and "1" are
+ * permitted as well as the resource values "true" and "false".
+ */
+ if (strcmp (from.addr, "0") == 0) {
+ value = False;
+ goto set_bval;
+ } else if (strcmp (from.addr, "1") == 0) {
+ value = True;
+ goto set_bval;
+ } else if (XtConvertAndStore (wp->w,XtRString,&from,rp->type,&to)) {
+set_bval: XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRAtom) == 0 ||
+ strcmp (rp->type, XtRCardinal) == 0 ||
+ strcmp (rp->type, XtRInt) == 0) {
+
+ int value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRFloat) == 0) {
+ union {
+ int int_value;
+ float float_value;
+ } value;
+
+ to.addr = (caddr_t) &value.float_value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value.int_value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRPixel) == 0) {
+ Pixel value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRPixmap) == 0 ||
+ strcmp (rp->type, XtRBitmap) == 0) {
+
+ Pixmap value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if ((value = findPixmap (obm, (char *)from.addr)) ||
+ XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRIcon) == 0) {
+ Icon *value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if ((value = findIcon (obm, (char *)from.addr)) ||
+ XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRCursor) == 0) {
+ Cursor value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if ((value = findCursor (obm, (char *)from.addr)) ||
+ XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRFontStruct) == 0) {
+ XFontStruct *value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRVisual) == 0) {
+ Visual *value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRWidget) == 0) {
+ Widget value;
+
+ /* Convert resource value. */
+ if (value = XtNameToWidget (obm->toplevel, argv[2])) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+
+ } else if (strcmp (rp->type, XtRTranslationTable) == 0) {
+ XtTranslations value;
+
+ /* Convert resource value. */
+ value = XtParseTranslationTable (argv[2]);
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+
+ } else {
+ caddr_t value;
+ to.addr = (caddr_t) &value;
+ to.size = sizeof(value);
+
+ /* Convert resource value. */
+ if (XtConvertAndStore (wp->w, XtRString,&from, rp->type,&to)) {
+ XtSetArg (args[0], rp->name, value);
+ XtSetValues (wp->w, args, 1);
+ }
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetGet -- Get a widget resource value as a string.
+ *
+ * Usage: get <resource-name>
+ */
+static int
+widgetGet (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ char rbuf[SZ_MESSAGE];
+ char *result = rbuf;
+ register char *ip;
+ register int hashval, n;
+ register Rtype rp;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ /* Lookup widget. There can be multiple entries for a given resource
+ * if the resource has a different type in different widgets. A
+ * resource entry can be used only if both the name matches and the
+ * bitflags indicate that the target widget uses the resource.
+ */
+ for (hashval=0, ip=argv[1], n=MAX_HASHCHARS; --n >= 0 && *ip; ip++)
+ hashval += (hashval + *ip);
+
+ if (rp = rhash[hashval%LEN_RHASH]) {
+ for ( ; rp; rp = rp->next)
+ if (!strcmp(rp->name,argv[1]) &&
+ obmClass (obj->core.classrec, rp->flag1, rp->flag2))
+ break;
+ }
+ if (!rp)
+ return (TCL_ERROR);
+
+ /* Return the resource value as a string. In general type converters
+ * are only registered for string-to-whatever conversions, so we
+ * cannot reproduce the original string value for all resource types.
+ * We can return a valid string value for the simple types (boolean,
+ * integer, floating, string). An attempt is made to convert widget
+ * pointers to widget names. For everything else, we just return
+ * the hex representation of the resource value.
+ */
+ if (strcmp (rp->type, XtRBool) == 0 ||
+ strcmp (rp->type, XtRBoolean) == 0) {
+
+ Boolean value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ strcpy (result, value ? TRUESTR : FALSESTR);
+
+ } else if (
+ strcmp (rp->type, XtRDimension) == 0 ||
+ strcmp (rp->type, XtRPosition) == 0) {
+
+ short value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ sprintf (result, "%d", value);
+
+ } else if (
+ strcmp (rp->type, XtRAtom) == 0 ||
+ strcmp (rp->type, XtRCardinal) == 0 ||
+ strcmp (rp->type, XtRInt) == 0) {
+
+ int value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ sprintf (result, "%d", value);
+
+ } else if (strcmp (rp->type, XtRFloat) == 0) {
+ float value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ sprintf (result, "%g", value);
+
+ } else if (strcmp (rp->type, XtRString) == 0) {
+ char *value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ result = (char *)value;
+
+ } else if (strcmp (rp->type, XtRWidget) == 0) {
+ Widget value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ result = XtName (value);
+
+ } else if (strcmp (rp->type, XtRFontStruct) == 0) { /* MF016 */
+ caddr_t value; Arg args[1];
+ XFontStruct *font_struct;
+ ObmContext obm = wp->obm;
+ char *name = NULL;
+
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ sprintf (result, "0x%x", value);
+
+ font_struct = (XFontStruct *) value;
+ name = widgetGetFontName (obm->display, font_struct);
+
+ if (font_struct == NULL || name == NULL)
+ name = XtNewString("-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1");
+ strcpy (result, name);
+ free ((char *)name);
+
+ } else {
+ caddr_t value; Arg args[1];
+ XtSetArg (args[0], rp->name, &value);
+ XtGetValues (wp->w, args, 1);
+ sprintf (result, "0x%x", value);
+ }
+
+ Tcl_SetResult (wp->obm->tcl, result, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* widgetAppend -- Append data to a text widget.
+ *
+ * Usage: append <text>
+ */
+static int
+widgetAppend (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+
+ register char *ip, *op;
+ char buf[SZ_COMMAND];
+ XawTextBlock tx;
+ char *text;
+
+ if (!(obmClass (obj->core.classrec, WtAsciiText))) {
+ obm->tcl->result = "not a text widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else
+ text = argv[1];
+
+ if (wp->text_pos == 0) {
+ Arg args[1];
+ XtSetArg (args[0], XtNstring, "");
+ XtSetValues (wp->w, args, 1);
+ }
+
+ op = buf;
+ if (wp->text_newline)
+ *op++ = '\n';
+
+ for (ip=text; *ip; )
+ *op++ = *ip++;
+
+ if (wp->text_newline = (*(ip-1) == '\n'))
+ op--;
+
+ *op = '\0';
+
+ tx.ptr = buf;
+ tx.length = op - buf;
+ tx.format = FMT8BIT;
+ tx.firstPos = 0;
+
+ XawTextReplace (wp->w, wp->text_pos, wp->text_pos, &tx);
+ XawTextSetInsertionPoint (wp->w, (wp->text_pos += (op - buf)));
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetList -- Set the item list of a list widget.
+ *
+ * Usage: setList list [resize]
+ *
+ * The list is a simple list of strings, passed as a single string argument to
+ * setList (quotes, braces, etc. may be used to quote strings containing
+ * special characters).
+ */
+static int
+widgetSetList (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Boolean resize;
+ String *items;
+ int nitems;
+ char *list;
+
+ if (!(obmClass (obj->core.classrec, WtList) ||
+ obmClass (obj->core.classrec, WtMultiList))) {
+ obm->tcl->result = "not a list widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else
+ list = argv[1];
+
+ resize = (argc > 2) ? (strcmp (argv[2], "resize") == 0) : False;
+
+ if (Tcl_SplitList (obm->tcl, list, &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+
+ if ((obmClass (obj->core.classrec, WtList)))
+ XawListChange (wp->w, items, nitems, 0, resize);
+ else if ((obmClass (obj->core.classrec, WtMultiList)))
+ XfwfMultiListSetNewData ((XfwfMultiListWidget)wp->w,
+ items, nitems, 0, resize, NULL);
+
+ if (wp->data)
+ free (wp->data);
+
+ wp->data = (char *) items;
+ wp->datalen = nitems;
+
+ return (TCL_OK);
+}
+
+
+/* widgetGetItem -- Get an item in a list widget.
+ *
+ * Usage: value = getItem itemno
+ *
+ * If ITEMNO is a number the indicated list item is returned, or the string
+ * "EOF" if the requested item is beyond the end of the list. Otherwise the
+ * currently selected item (or list of items in the case of a MultiList
+ * widget) is returned, and the index (list of indices) of the item is
+ * returned in the output variable ITEMNO. If no item is currently selected
+ * ITEMNO will be set to "none" ({}) on output.
+ */
+static int
+widgetGetItem (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+
+ register nelem;
+ register String *list;
+ register char *ip, *op;
+ XawListReturnStruct *itemp;
+ char *s_itemno, *s_item;
+ char buf[SZ_NUMBER];
+ int requested;
+ char *itemno;
+
+ if (!(obmClass (obj->core.classrec, WtList) ||
+ obmClass (obj->core.classrec, WtMultiList))) {
+ obm->tcl->result = "not a list widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else
+ itemno = argv[1];
+
+ if (isdigit (itemno[0])) {
+ /* Get indexed item. */
+ requested = atoi (itemno);
+ list = (String *) wp->data;
+ nelem = wp->datalen;
+ if (requested < nelem)
+ s_item = list[requested];
+ else
+ s_item = "EOF";
+
+ } else if (obmClass (obj->core.classrec, WtList)) {
+ /* Athena list: get the currently selected list item.
+ */
+ itemp = XawListShowCurrent (wp->w);
+ if (!itemp || itemp->list_index == XAW_LIST_NONE) {
+ s_itemno = "none";
+ s_item = "";
+ } else {
+ sprintf (buf, "%d", itemp->list_index);
+ s_itemno = buf;
+ s_item = itemp->string;
+ }
+ if ((Tcl_SetVar (obm->tcl, itemno, s_itemno, 0)) == NULL)
+ return (TCL_ERROR);
+
+ Tcl_SetResult (obm->tcl, s_item, TCL_VOLATILE);
+
+ } else {
+ /* MultiList: get currently selected items.
+ */
+ XfwfMultiListReturnStruct *list;
+ char *buffer, *strlist, *indexlist, *string;
+ Boolean state, sensitive;
+ int buflen, need, i;
+
+ list = XfwfMultiListGetHighlighted ((XfwfMultiListWidget)wp->w);
+ buflen = SZ_COMMAND;
+ if (!(buffer = XtMalloc (buflen)))
+ return;
+
+ /* Generate list of item strings. */
+ strlist = op = buffer;
+ *op++ = '{';
+ for (i=0; i < list->num_selected; i++) {
+ XfwfMultiListGetItemInfo ((XfwfMultiListWidget)wp->w,
+ list->selected_items[i], &string, &state, &sensitive);
+ need = strlen(string)+3 + list->num_selected * 6;
+ if (buflen < (op-buffer)+need) {
+ buflen += max (need, SZ_COMMAND);
+ if (!(buffer = XtRealloc (buffer, buflen)))
+ return;
+ }
+ *op++ = ' ';
+ *op++ = '{';
+ for (ip=string; *op = *ip++; op++)
+ ;
+ *op++ = '}';
+ }
+ *op++ = '}';
+ *op++ = '\0';
+
+ /* Append list of indices. We allocated space for these above. */
+ indexlist = op;
+ *op++ = '{';
+ for (i=0; i < list->num_selected; i++) {
+ sprintf (op, " %d", list->selected_items[i]);
+ while (*op)
+ op++;
+ }
+ *op++ = '}';
+ *op++ = '\0';
+
+ if ((Tcl_SetVar (obm->tcl, itemno, indexlist, 0)) == NULL)
+ return (TCL_ERROR);
+
+ Tcl_SetResult (obm->tcl, strlist, TCL_VOLATILE);
+ XtFree (buffer);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetHighlight -- Highlight an item in a list widget.
+ *
+ * Usage: highlight itemno
+ *
+ * The indicated item of the list is highlighted as if the item had been
+ * selected by the user. Any previously highlighted item is unhighlighted.
+ * List items may be specified by either the element number or by name.
+ */
+static int
+widgetHighlight (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ int itemno;
+
+ if (!(obmClass (obj->core.classrec, WtList) ||
+ obmClass (obj->core.classrec, WtMultiList))) {
+ obm->tcl->result = "not a list widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else
+ itemno = get_itemno (obj, argv[1]);
+
+ if (itemno >= 0 && itemno < wp->datalen)
+ if (obmClass (obj->core.classrec, WtList))
+ XawListHighlight (wp->w, itemno);
+ else
+ XfwfMultiListHighlightItem ((XfwfMultiListWidget)wp->w, itemno);
+
+ return (TCL_OK);
+}
+
+
+/* widgetUnhighlight -- Unhighlight the currently highlighted item in a
+ * list widget.
+ *
+ * Usage: unhighlight [itemno]
+ *
+ * If itemno is not given all list elements are unhighlighted, otherwise
+ * the given entry is unhighlighted. The itemno argument may be either
+ * the actual item number, or the name of the list element.
+ */
+static int
+widgetUnhighlight (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ int itemno;
+
+ if (!(obmClass (obj->core.classrec, WtList) ||
+ obmClass (obj->core.classrec, WtMultiList))) {
+ obm->tcl->result = "not a list widget";
+ return (TCL_ERROR);
+ }
+
+ itemno = (argc > 1) ? get_itemno(obj,argv[1]) : -1;
+
+ if (obmClass (obj->core.classrec, WtList)) {
+ if (itemno >= 0) {
+ XawListReturnStruct *itemp = XawListShowCurrent (wp->w);
+ if (itemp && itemp->list_index == itemno)
+ XawListUnhighlight (wp->w);
+ } else
+ XawListUnhighlight (wp->w);
+ } else {
+ if (itemno >= 0) {
+ XfwfMultiListUnhighlightItem ((XfwfMultiListWidget)wp->w,
+ itemno);
+ } else
+ XfwfMultiListUnhighlightAll ((XfwfMultiListWidget)wp->w);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* get_itemno -- Get the item number of an item in a list widget, given
+ * either the ascii representation of the item number, or the item string.
+ */
+static
+get_itemno (obj, itemstr)
+WidgetObject obj;
+char *itemstr;
+{
+ WidgetPrivate wp = &obj->widget;
+ register int i;
+
+ if (isdigit (*itemstr))
+ return (atoi(itemstr));
+ else {
+ /* Check first to see if the named item is the currently
+ * selected, or most recently referenced item.
+ */
+ if (obmClass (obj->core.classrec, WtList)) {
+ XawListReturnStruct *itemp;
+ itemp = XawListShowCurrent (wp->w);
+ if (itemp && strcmp (itemp->string, itemstr) == 0)
+ return (itemp->list_index);
+
+ } else if (obmClass (obj->core.classrec, WtMultiList)) {
+ XfwfMultiListReturnStruct *list;
+ list = XfwfMultiListGetHighlighted ((XfwfMultiListWidget)wp->w);
+ if (list->string && strcmp (list->string, itemstr) == 0)
+ return (list->item);
+ }
+
+ /* Search the full list. */
+ for (i=0; i < wp->datalen; i++)
+ if (strcmp (((String *)wp->data)[i], itemstr) == 0)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* widgetGetValue -- Get the text value of a dialog widget.
+ *
+ * Usage: value = getValue
+ */
+static int
+widgetGetValue (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *value;
+
+ if (!(obmClass (obj->core.classrec, WtDialog))) {
+ obm->tcl->result = "not a dialog widget";
+ return (TCL_ERROR);
+ }
+
+ value = XawDialogGetValueString (wp->w);
+ Tcl_SetResult (obm->tcl, value, TCL_VOLATILE);
+
+ return (TCL_OK);
+}
+
+
+/* widgetGetThumb -- Get the position and size of the thumb of a slider2d
+ * widget.
+ *
+ * Usage: getThumb x [y [width [height]]]
+ */
+static int
+widgetGetThumb (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ XfwfScrollInfo info;
+ char buf[SZ_NUMBER];
+
+ if (!(obmClass (obj->core.classrec, WtSlider2d))) {
+ obm->tcl->result = "not a slider2d widget";
+ return (TCL_ERROR);
+ }
+
+ XfwfGetThumb (wp->w, &info);
+
+ if (argc > 1) {
+ sprintf (buf, "%g", info.hpos);
+ if ((Tcl_SetVar (obm->tcl, argv[1], buf, 0)) == NULL)
+ return (TCL_ERROR);
+ }
+ if (argc > 2) {
+ sprintf (buf, "%g", info.vpos);
+ if ((Tcl_SetVar (obm->tcl, argv[2], buf, 0)) == NULL)
+ return (TCL_ERROR);
+ }
+ if (argc > 3) {
+ sprintf (buf, "%g", info.hsize);
+ if ((Tcl_SetVar (obm->tcl, argv[3], buf, 0)) == NULL)
+ return (TCL_ERROR);
+ }
+ if (argc > 4) {
+ sprintf (buf, "%g", info.vsize);
+ if ((Tcl_SetVar (obm->tcl, argv[4], buf, 0)) == NULL)
+ return (TCL_ERROR);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetMoveThumb -- Move the thumb of a slider2D widget.
+ *
+ * Usage: moveThumb x [y]
+ *
+ * The thumb of a slider2D wiget is set to the given position specified as
+ * a fraction of the widget's width or height. The widget and height
+ * arguments should be floating point values in the range 0.0 to 1.0.
+ */
+static int
+widgetMoveThumb (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ double x, y;
+ double atof();
+
+ if (!(obmClass (obj->core.classrec, WtSlider2d))) {
+ obm->tcl->result = "not a slider2D widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else {
+ x = atof (argv[1]);
+ y = (argc > 2) ? atof(argv[2]) : 0.0;
+ }
+
+ x = max(0, min(1, x));
+ y = max(0, min(1, y));
+
+ XfwfMoveThumb (wp->w, x, y);
+ return (TCL_OK);
+}
+
+
+/* widgetResizeThumb -- Resize the thumb of a slider2D widget.
+ *
+ * Usage: resizeThumb width [height]
+ *
+ * The thumb of a slider2D wiget is set to the given fraction of the widget's
+ * width or height. The widget and height arguments should be floating point
+ * values in the range 0.0 to 1.0.
+ */
+static int
+widgetResizeThumb (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ double width, height;
+ double atof();
+
+ if (!(obmClass (obj->core.classrec, WtSlider2d))) {
+ obm->tcl->result = "not a slider2D widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else {
+ width = atof (argv[1]);
+ height = (argc > 2) ? atof(argv[2]) : 1.0;
+ }
+
+ width = max(0, min(1, width));
+ height = max(0, min(1, height));
+
+ XfwfResizeThumb (wp->w, width, height);
+ return (TCL_OK);
+}
+
+
+/* widgetSetScrollbar -- Set the position and size of a scrollbar.
+ *
+ * Usage: setScrollbar position size
+ *
+ * The thumb of a scrollbar wiget is set to the given position and size
+ * specified as a fraction of the widget's width or height. The position and
+ * height arguments should be floating point values in the range 0.0 to 1.0.
+ */
+static int
+widgetSetScrollbar (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ double position, size;
+ double atof();
+
+ if (!(obmClass (obj->core.classrec, WtScrollbar) ||
+ obmClass (obj->core.classrec, WtScrollbar2))) {
+
+ obm->tcl->result = "not a scrollbar widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 3) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else {
+ position = atof (argv[1]);
+ size = atof (argv[2]);
+ }
+
+ position = max(0, min(1, position));
+ size = max(0, min(1, size));
+
+ if (obmClass (obj->core.classrec, WtScrollbar))
+ XawScrollbarSetThumb (wp->w, position, size);
+ else
+ XfwfSetScrollbar (wp->w, position, size);
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetLocation -- Set the position of a Viewport.
+ *
+ * Usage: setLocation x y
+ *
+ */
+static int
+widgetSetLocation (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ float x, y;
+ double atof();
+
+ if (!(obmClass (obj->core.classrec, WtViewport))) {
+ obm->tcl->result = "not a viewport widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 3) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else {
+ x = atof (argv[1]);
+ y = atof (argv[2]);
+ }
+
+ XawViewportSetLocation (wp->w, x, y);
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetCoordinates -- Set the coordinates of a Viewport.
+ *
+ * Usage: setCoordinates x y
+ *
+ */
+static int
+widgetSetCoordinates (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ int x, y;
+ double atof();
+
+ if (!(obmClass (obj->core.classrec, WtViewport))) {
+ obm->tcl->result = "not a viewport widget";
+ return (TCL_ERROR);
+ }
+
+ if (argc < 3) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ } else {
+ x = atoi (argv[1]);
+ y = atoi (argv[2]);
+ }
+
+ XawViewportSetCoordinates (wp->w, (int)x, (int)y);
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetTop -- Raise the child of a Tabs widget.
+ *
+ * Usage: setTop widget
+ *
+ */
+static int
+widgetSetTop (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ ObmObject child = (ObmObject) NULL;
+
+ if (!(obmClass (obj->core.classrec, WtTabs))) {
+ obm->tcl->result = "not a Tabs widget";
+ return (TCL_ERROR);
+ } else if (argc < 2) {
+ obm->tcl->result = "missing argument";
+ return (TCL_ERROR);
+ }
+
+ /* Get the child object pointer and raise it. */
+ child = obmFindObject (obm, argv[1]);
+ if (child)
+ XawTabsSetTop (widgetGetPointer (child), False);
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetListTree -- Set a ListTree hierarchy.
+ *
+ * Usage: setListTree list [append]
+ *
+ * The list is specified as a hierarchical Tcl list of the form
+ *
+ * {a1 {b1 {a2 {a3 b3}} b2} c1}
+ *
+ * This would produce an indented list something like:
+ *
+ * a1
+ * b1
+ * |- a2
+ * |- a3
+ * |- b3
+ * |- b2
+ * c1
+ *
+ */
+static int
+widgetSetListTree (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Boolean append;
+ char *list, **items, buf[SZ_LINE];
+ int nitems, item;
+ static char **sv_items = NULL;
+ static int sv_nitems;
+ ListTreeItem *val;
+ extern ListTreeItem *ListTreeAdd(), *ListTreeFirstItem();
+
+
+ /* Do some error checking first. */
+ if (!(obmClass (obj->core.classrec, WtListTree))) {
+ obm->tcl->result = "not a ListTree widget";
+ return (TCL_ERROR);
+ } else if (argc < 2) {
+ obm->tcl->result = "missing list argument";
+ return (TCL_ERROR);
+ }
+
+ list = argv[1];
+ append = (argc > 2) ? (strcmp (argv[2], "append") == 0) : False;
+
+ /* Delete the old tree. */
+ if (!append && sv_items) {
+ while ((val = ListTreeFirstItem(wp->w)))
+ ListTreeDelete (wp->w, val);
+ free ((char *) sv_items);
+ sv_items = NULL;
+ }
+
+ /* Split the list so we can parse as needed. */
+ if (Tcl_SplitList (tcl, list, &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+
+ /* Get local copy of argc and argv. */
+ if (!sv_nitems) {
+ sv_items = (char **) XtMalloc (nitems * sizeof(char *));
+ memmove (sv_items, items, nitems * sizeof(char *));
+ }
+
+ if (append && sv_items) {
+ sv_items = (char **) XtRealloc ((char *)sv_items,
+ (sv_nitems + nitems * 1) * sizeof(char *));
+ memmove (sv_items+sv_nitems, items, nitems * sizeof(char *));
+ }
+
+ for (item=0; item < nitems; item++) {
+ /* Build the top-level tree, children are built recursively
+ * in the routine.
+ */
+ if (buildTreeList (wp->w, tcl, NULL, items[item]) != TCL_OK) {
+ free ((char *) items);
+ return (TCL_ERROR);
+ }
+ }
+
+ret: free ((char *) items);
+ return (TCL_OK);
+}
+
+
+/* buildTreeList -- Recursively build a tree from a list of nested Tcl
+ * lists. This is used to fill out the ListTree widget values.
+ */
+static int
+buildTreeList (w, tcl, parent, item)
+Widget w;
+Tcl_Interp *tcl;
+ListTreeItem *parent;
+char *item;
+{
+ char **fields, **entry;
+ int i, nentries, nfields, field;
+ char buf[SZ_LINE];
+ ListTreeItem *level;
+
+ /* Split the list so we can parse as needed. */
+ if (Tcl_SplitList (tcl, item, &nfields, &fields) != TCL_OK) {
+ sprintf (buf, "bad item '%s' in tree list", item);
+ Tcl_AppendResult (tcl, buf, NULL);
+ return (TCL_ERROR);
+ }
+
+ /* First item is always added to the list, it may be either the
+ * parent of another list or a single item.
+ */
+ level = ListTreeAdd (w, parent, fields[0]);
+
+ /* For each of the items, split it and recursively call ourselves
+ * until it gets added as a single item.
+ */
+ for (field=1; field < nfields; field++) {
+ if (Tcl_SplitList (tcl, fields[field], &nentries, &entry) != TCL_OK)
+ return (TCL_ERROR);
+
+ for (i=0; i < nentries; i++)
+ buildTreeList (w, tcl, level, entry[i]);
+ }
+
+ free ((char *) fields);
+/* free ((char *) entry);*/
+ return (TCL_OK);
+}
+
+
+/* widgetListTreeSelect -- Select the specified item from a ListTree.
+ *
+ * Usage: listTreeSelect item [ top [children_only] ]
+ *
+ * The 'item' may be one of:
+ *
+ * all open all children in list
+ * none close all children in list
+ *
+ * If 'toplevel' is specified then 'item' is assumed to be a child of
+ * that node. If 'children_only' is set then only the children of the
+ * specified item will be opened (applies to all/none only). The return
+ * message is a pair of lists of the form
+ *
+ * { value state } { parent1 parent2 ... }
+ *
+ * where the 'value' is the label of the item selected, 'state' is an int
+ * indicating whether the node is open or closed, and 'parentN' is a list
+ * of node names chaining back to the top level of the tree.
+ *
+ */
+static int
+widgetListTreeSelect (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *top, *name;
+ char message[SZ_COMMAND], buf[SZ_LINE];
+ int i, count;
+ ListTreeItem *item, *titem, *first;
+
+ extern ListTreeItem *ListTreeFindSiblingName();
+ extern ListTreeItem *ListTreeFindChildName();
+ extern ListTreeItem *ListTreeFindChildNameInTree();
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ first = ListTreeFirstItem (wp->w);
+
+ if (strcmp(argv[1], "all") == 0) {
+ if (argc == 4) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ item = ListTreeFindChildName (wp->w, titem, name);
+ ListTreeOpenAll (wp->w, (item ? item : titem), 1);
+ ListTreeHighlightItem (wp->w, (item ? item : titem));
+ sprintf (message, "{%s 1} { }",
+ (item ? item->text : titem->text));
+ } else {
+ ListTreeOpenAll (wp->w, (ListTreeItem *)NULL, 0);
+ strcpy (message, "{all 1} { }");
+ }
+
+
+ } else if (strcmp(argv[1], "none") == 0) {
+ if (argc == 4) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ item = ListTreeFindChildName (wp->w, titem, name);
+ ListTreeCloseAll (wp->w, (item ? item : titem), 0);
+ sprintf (message, "{%s 0} { }",
+ (item ? item->text : titem->text));
+ } else {
+ ListTreeCloseAll (wp->w, (ListTreeItem *)NULL, 0);
+ strcpy (message, "{all 0} { }");
+ }
+
+ } else {
+ if (argc == 3) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ if (titem)
+ ListTreeOpenAll (wp->w, titem, 0);
+ item = ListTreeFindChildNameInTree (wp->w, titem, name);
+ item = (item ? item : titem);
+ } else {
+ titem = ListTreeFindSiblingName (wp->w, first, name);
+ if (strcmp (name, titem->text) == 0)
+ item = titem;
+ else
+ item = ListTreeFindChildNameInTree (wp->w, titem, name);
+ }
+ ListTreeHighlightItem (wp->w, item);
+ ListTreeOpenAll (wp->w, item, 0);
+
+ /* The message is the string value of the list element selected,
+ * and a bottom-up path to the root.
+ */
+ sprintf (message, "{%s %d} ", item->text, item->open);
+
+ strncat (message, "{ ", 2);
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ while (item->parent) {
+ item = item->parent;
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ }
+
+ strncat (message, "}", 1);
+
+ }
+
+ /* Call all the callbacks with the message. */
+ call_callbacks (obj, Ctcallback, message);
+
+ return (TCL_OK);
+}
+
+
+/* widgetListTreeHighlight -- Highlight but do not select the specified item
+ * from a ListTree.
+ *
+ * Usage: listTreeHighlight item [ top ]
+ *
+ * The 'item' is given as a node name of the tree. If 'top' is specified
+ * then 'item' is assumed to be a child of that node. If 'children_only' is
+ * set then only the children of the specified item will be opened (applies
+ * to all/none only). The return message is a pair of lists of the form
+ *
+ * { value state } { parent1 parent2 ... }
+ *
+ * where the 'value' is the label of the item selected, 'state' is an int
+ * indicating whether the node is open or closed, and 'parentN' is a list
+ * of node names chaining back to the top level of the tree.
+ *
+ */
+static int
+widgetListTreeHighlight (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *top, *name;
+ char message[SZ_COMMAND], buf[SZ_LINE];
+ int i, count;
+ ListTreeItem *item, *titem, *first, *op;
+
+ extern ListTreeItem *ListTreeFindSiblingName();
+ extern ListTreeItem *ListTreeFindChildName();
+ extern ListTreeItem *ListTreeFindChildNameInTree();
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ first = ListTreeFirstItem (wp->w);
+
+ if (argc == 3) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ item = ListTreeFindChildNameInTree (wp->w, titem, name);
+ item = (item ? item : titem);
+
+ /* Now chain back up thru the parents and open the nodes.
+ */
+ for (op=item ; op->parent && op->parent != first; op = op->parent) {
+ if (op->open == 0)
+ ListTreeOpenAll (wp->w, op, 1);
+ }
+
+ } else {
+ if (first->open == 0)
+ ListTreeOpenAll (wp->w, first, 0);
+ titem = ListTreeFindChildNameInTree (wp->w, first, name);
+ if (titem && strcmp (name, titem->text) == 0)
+ item = titem;
+ else
+ item = ListTreeFindChildNameInTree (wp->w, titem, name);
+ }
+ ListTreeHighlightItem (wp->w, item);
+
+ /* The message is the string value of the list element selected,
+ * and a bottom-up path to the root.
+ */
+ sprintf (message, "{%s %d} ", item->text, item->open);
+
+ strncat (message, "{ ", 2);
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ while (item->parent) {
+ item = item->parent;
+ sprintf (buf, "{ %s } ", item->text);
+ strcat (message, buf);
+ }
+ strncat (message, "}", 1);
+
+ /* Call all the callbacks with the message. */
+ call_callbacks (obj, Ctcallback, message);
+
+ return (TCL_OK);
+}
+
+
+/* widgetListTreeDelete -- Delete the specified item from a ListTree.
+ *
+ * Usage: listTreeDelete item [top]
+ *
+ * The 'item' may 'all' to delete the entire list or a named element.
+ * If 'toplevel' is specified then 'item' is assumed to be a child of
+ * that node. If 'children_only' is set then only the children of the
+ * specified item will be opened (applies to all/none only). The return
+ * message is a pair of lists of the form
+ *
+ * { value state } { parent1 parent2 ... }
+ *
+ * where the 'value' is the label of the item selected, 'state' is an int
+ * indicating whether the node is open or closed, and 'parentN' is a list
+ * of node names chaining back to the top level of the tree.
+ *
+ */
+static int
+widgetListTreeDelete (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *top, *name;
+ ListTreeItem *item, *titem, *first;
+
+ extern ListTreeItem *ListTreeFindSiblingName();
+ extern ListTreeItem *ListTreeFindChildName();
+ extern ListTreeItem *ListTreeFirstItem();
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ name = argv[1];
+ first = ListTreeFirstItem (wp->w);
+
+ if (strcmp(argv[1], "all") == 0) {
+ if (argc == 3) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ if (strcmp (top, titem->text) == 0)
+ item = titem;
+ else
+ item = ListTreeFindChildName (wp->w, titem, name);
+
+ ListTreeDelete(wp->w, item);
+
+ } else {
+ while ((item = ListTreeFirstItem(wp->w)))
+ ListTreeDelete (wp->w, item);
+ }
+
+ } else {
+ if (argc == 3) {
+ top = argv[2];
+ titem = ListTreeFindSiblingName (wp->w, first, top);
+ item = ListTreeFindChildName (wp->w, titem, name);
+ } else {
+ titem = ListTreeFindSiblingName (wp->w, first, name);
+ if (strcmp (name, titem->text) == 0)
+ item = titem;
+ else
+ item = ListTreeFindChildName (wp->w, titem, name);
+ }
+
+ /* Now delete the item from the list. */
+ ListTreeDelete(wp->w, item);
+ }
+
+
+ /* Call all the callbacks with the message.
+ call_callbacks (obj, Ctcallback, message);
+ */
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetTable -- Set the contents of a Table widget.
+ *
+ * Usage: setTable nrows ncols data
+ *
+ * The table data is specified as a Tcl list of the form:
+ *
+ * { {r1c1 r1c2 ... r1cN}
+ * {r2c1 r2c2 ... r2cN}
+ * :
+ * {rNc1 rNc2 ... rNcN} }
+ *
+ * String values must be quoted, rows/cols will be truncated or cleared if
+ * the specified table size does not agree with the size of the data table
+ * being loaded.
+ *
+ */
+static int
+widgetSetTable (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+
+ register int i, j;
+ int nrows, ncols, ndrows=0, ndcols=0, onrows, oncols;
+ char *list = NULL, **rows = NULL, **cols = NULL;
+
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ /* Get the arguments */
+ nrows = atoi(argv[1]);
+ ncols = atoi(argv[2]);
+ list = argv[3];
+
+ /* Resize the table if needed. */
+ XawTableGetSize (wp->w, &onrows, &oncols);
+ if (onrows != nrows || oncols != ncols)
+ XawTableSetNewSize (wp->w, nrows, ncols);
+
+ /* Split the list so we can parse the rows. */
+ if (Tcl_SplitList (tcl, list, &ndrows, &rows) != TCL_OK)
+ return (TCL_ERROR);
+
+ /* Set the labels for the table. Clear any extra row or column
+ * labels in case we didn't get enough data, ignore extra data in
+ * the table if it's more than the size we're trying to create.
+ */
+ for (i=0; i < ndrows; i++) {
+ if (Tcl_SplitList (tcl, rows[i], &ndcols, &cols) != TCL_OK)
+ return (TCL_ERROR);
+
+ for (j=0; j < ndcols; j++)
+ XawTableSetLabel (wp->w, i, j, cols[j]);
+ }
+
+ free ((char *) rows);
+ free ((char *) cols);
+ return (TCL_OK);
+}
+
+
+/* widgetGetCellAttr -- Get the given attribute of a Table cell.
+ *
+ * Usage: setGellAttr row col attribute value
+ *
+ *
+ * The cell position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a cell include:
+ *
+ * label label text (string)
+ * background background color (string)
+ * foreground foreground color (string)
+ *
+ */
+static int
+widgetGetCellAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ XrmValue from, to;
+ unsigned long bg, fg;
+ int row, col;
+ char *attr, *value;
+
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ row = atoi(argv[1]) - 1;
+ col = atoi(argv[2]) - 1;
+ attr = argv[3];
+
+ if (strcmp(attr, "label") == 0)
+ value = XawTableGetLabelByPosition (wp->w, row, col);
+ else
+ return (TCL_ERROR);
+
+ Tcl_SetResult (wp->obm->tcl, value, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* widgetSetCellAttr -- Set the given attribute of a Table cell.
+ *
+ * Usage: setCellAttr row col attribute value
+ *
+ *
+ * The cell position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a cell include:
+ *
+ * label label text (string)
+ * background background color (string)
+ * foreground foreground color (string)
+ *
+ */
+static int
+widgetSetCellAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ XrmValue from, to;
+ unsigned long bg, fg;
+ int row, col;
+ char *attr, *value;
+
+
+ if (argc < 5)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ row = atoi(argv[1]) - 1;
+ col = atoi(argv[2]) - 1;
+ attr = argv[3];
+ value = argv[4];
+
+ if (strcmp(attr, "label") == 0) {
+ XawTableSetLabel (wp->w, row, col, value);
+
+ } else if (strcmp(attr, "background") == 0) {
+ from.size = strlen (value) + 1;
+ from.addr = value;
+ to.addr = (caddr_t) &bg;
+ to.size = sizeof(bg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ bg = BlackPixelOfScreen (obm->screen);
+
+ XawTableSetCellBackground (wp->w, row, col, bg);
+
+ } else if (strcmp(attr, "foreground") == 0) {
+ from.size = strlen (value) + 1;
+ from.addr = value;
+ to.addr = (caddr_t) &fg;
+ to.size = sizeof(fg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ fg = BlackPixelOfScreen (obm->screen);
+
+ XawTableSetCellForeground (wp->w, row, col, fg);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetColAttr -- Set the given attribute of a Table column.
+ *
+ * Usage: setColAttr col attribute value
+ *
+ * The column position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a column include:
+ *
+ * width column width (pixels)
+ * background background color (string)
+ * foreground foreground color (string)
+ * justify text justification (string)
+ *
+ */
+static int
+widgetSetColAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ XrmValue from, to;
+ unsigned long bg, fg;
+ int cols[128], widths[128];
+ int nitems, row, col, nrows, ncols, i;
+ String *items;
+ char *attr;
+
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ /* Get the arguments. NOTE: need to bounds check the length of the
+ * list with the array.
+ */
+ if (Tcl_SplitList (tcl, argv[1], &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+ else {
+ if (nitems == 1)
+ col = atoi(argv[1]) - 1;
+ else {
+ if (nitems > 128)
+ return (TCL_ERROR);
+ for (i=0; i < nitems; i++)
+ cols[i] = atoi(items[i]) - 1;
+ }
+ }
+ attr = argv[2];
+
+ /* Get current table size. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+
+ if (strcmp(attr, "width") == 0) {
+ /* Reset the column width. */
+ if (nitems == 1)
+ XawTableSetColumnWidth (wp->w, col, atoi(argv[3]));
+ else {
+ if (Tcl_SplitList (tcl, argv[3], &nitems, &items) != TCL_OK)
+ return (TCL_ERROR);
+ if (nitems > 128)
+ return (TCL_ERROR);
+ for (i=0; i < nitems; i++)
+ widths[i] = atoi(items[i]) - 1;
+ XawTableSetMultiColumnWidths (wp->w, cols, widths, nitems);
+ }
+
+ } else if (strcmp(attr, "background") == 0) {
+ /* Reset the column background color. */
+ from.size = strlen (argv[3]) + 1;
+ from.addr = argv[3];
+ to.addr = (caddr_t) &bg;
+ to.size = sizeof(bg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ bg = BlackPixelOfScreen (obm->screen);
+
+ for (i=0; i < nrows; i++)
+ XawTableSetCellBackground (wp->w, i, col, bg);
+
+ } else if (strcmp(attr, "foreground") == 0) {
+ /* Reset the column foreground color. */
+ from.size = strlen (argv[3]) + 1;
+ from.addr = argv[3];
+ to.addr = (caddr_t) &fg;
+ to.size = sizeof(fg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ fg = BlackPixelOfScreen (obm->screen);
+
+ for (i=0; i < nrows; i++)
+ XawTableSetCellForeground (wp->w, i, col, fg);
+
+ } else if (strcmp(attr, "justify") == 0) {
+ /* Reset the column text justification. */
+ if (strcmp(argv[3], "left") == 0)
+ XawTableSetColumnJustify (wp->w, col, XtJustifyLeft);
+ else if (strcmp(argv[3], "center") == 0)
+ XawTableSetColumnJustify (wp->w, col, XtJustifyCenter);
+ else if (strcmp(argv[3], "right") == 0)
+ XawTableSetColumnJustify (wp->w, col, XtJustifyRight);
+ else
+ XawTableSetColumnJustify (wp->w, col, XtJustifyLeft);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetGetColAttr -- Get the requested attribute of a Table column.
+ *
+ * Usage: attr = getColAttr col attribute
+ *
+ *
+ * The column position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a column include:
+ *
+ * width column width
+ * pixelWidth foreground color
+ * justify text justification
+ *
+ */
+static int
+widgetGetColAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char rbuf[SZ_MESSAGE];
+ char *result = rbuf, *attr;
+ int col, nrows, ncols, width, pixelWidth;
+ XtJustify justify;
+
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ col = atoi(argv[1]) - 1;
+ attr = argv[2];
+
+ /* Get current table size. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+
+ if (strcmp(attr, "width") == 0) {
+ width = XawTableGetColumnWidth (wp->w, col);
+
+ } else if (strcmp(attr, "pixelWidth") == 0) {
+ pixelWidth = XawTableGetColumnPixelWidth (wp->w, col);
+
+ } else if (strcmp(attr, "justify") == 0) {
+ justify = XawTableGetColumnJustify (wp->w, col);
+
+ /* Reset the column text justification. */
+ if (justify == XtJustifyLeft)
+ strcpy (result, "left");
+ else if (justify == XtJustifyCenter)
+ strcpy (result, "center");
+ else if (justify == XtJustifyRight)
+ strcpy (result, "right");
+ else
+ strcpy (result, "left");
+ }
+
+ Tcl_SetResult (wp->obm->tcl, result, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* widgetSetRowAttr -- Set the given attribute of a Table row.
+ *
+ * Usage: setRowAttr row attribute value
+ *
+ * The row position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a row include:
+ *
+ * background background color
+ * foreground foreground color
+ */
+static int
+widgetSetRowAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ XrmValue from, to;
+ unsigned long bg, fg;
+ int row, col, nrows, ncols, i;
+ char *attr;
+
+
+ if (argc < 4)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ row = atoi(argv[1]) - 1;
+ attr = argv[2];
+
+ /* Get current table size. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+
+ if (strcmp(attr, "background") == 0) {
+ /* Reset the column background color. */
+ from.size = strlen (argv[3]) + 1;
+ from.addr = argv[3];
+ to.addr = (caddr_t) &bg;
+ to.size = sizeof(bg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ bg = BlackPixelOfScreen (obm->screen);
+
+ for (i=0; i < ncols; i++)
+ XawTableSetCellBackground (wp->w, row, i, bg);
+
+ } else if (strcmp(attr, "foreground") == 0) {
+ /* Reset the column foreground color. */
+ from.size = strlen (argv[3]) + 1;
+ from.addr = argv[3];
+ to.addr = (caddr_t) &fg;
+ to.size = sizeof(fg);
+
+ if (!XtConvertAndStore (wp->w, XtRString, &from, XtRPixel, &to))
+ fg = BlackPixelOfScreen (obm->screen);
+
+ for (i=0; i < ncols; i++)
+ XawTableSetCellForeground (wp->w, row, i, fg);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetGetRowAttr -- Get the requested attribute of a Table column.
+ *
+ * Usage: attr = getRowAttr row attribute
+ *
+ *
+ * The column position is given as a 1-indexed array element where the UL
+ * of the table is cell (1,1). Allowed attributes for a column include:
+ *
+ * <none yet>
+ *
+ */
+static int
+widgetGetRowAttr (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char rbuf[SZ_MESSAGE];
+ char *result = rbuf, *attr;
+ int row, nrows, ncols, width, pixelWidth;
+ XtJustify justify;
+
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ row = atoi(argv[1]) - 1;
+ attr = argv[2];
+
+ /* Get current table size. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+
+ return (TCL_OK);
+}
+
+
+/* widgetDeleteCol -- Delete the specified columns from the table.
+ *
+ * Usage: deleteCol column
+ *
+ */
+static int
+widgetDeleteCol (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ int col;
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ col = atoi(argv[1]) - 1;
+
+ /* Delete the specified row. */
+ XawTableDeleteColumn (wp->w, col);
+
+ return (TCL_OK);
+}
+
+
+/* widgetAddCol -- Add a new column to the Table.
+ *
+ * Usage: addCol col width
+ *
+ * The column may be specified in one of the following ways:
+ *
+ * first make column the first column in the table
+ * last make column the last column in the table
+ * <num> make column the N-th column in the table
+ *
+ * The column width is specified as a character width. Data for the
+ * column must be added separately using the setColAttr function to
+ * set individual labels.
+ *
+ */
+static int
+widgetAddCol (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *col = NULL;
+ int nrows, ncols, width, colnum = 0;
+
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ col = argv[1];
+ width = atoi(argv[2]);
+
+ /* Add the specified column. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+ colnum = max (0, min (ncols, atoi (col) - 1));
+
+ if (colnum == 0 || streq(col, "first"))
+ XawTablePrependColumn (wp->w, width);
+ else if (colnum == ncols || streq (col, "last"))
+ XawTableAppendColumn (wp->w, width);
+ else
+ XawTableInsertColumn (wp->w, colnum, width);
+
+ return (TCL_OK);
+}
+
+
+/* widgetDeleteRow -- Delete the specified rows from the table.
+ *
+ * Usage: deleteRow row
+ *
+ */
+static int
+widgetDeleteRow (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ int row;
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ row = atoi(argv[1]) - 1;
+
+ /* Delete the specified row. */
+ XawTableDeleteRow (wp->w, row);
+
+ return (TCL_OK);
+}
+
+
+/* widgetAddRow -- Add a new row to the Table.
+ *
+ * Usage: addRow row
+ *
+ * The row may be specified in one of the following ways:
+ *
+ * first make row the first row in the table
+ * last make row the last row in the table
+ * <num> make row the N-th row in the table
+ *
+ * Data for the column must be added separately using the setColAttr
+ * function to set individual labels.
+ *
+ */
+static int
+widgetAddRow (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char *row = NULL;
+ int nrows, ncols, rownum = 0;
+
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ /* Get the arguments. */
+ row = argv[1];
+
+ /* Add the specified column. */
+ XawTableGetSize (wp->w, &nrows, &ncols);
+ rownum = max (0, min (nrows, atoi (row) - 1));
+
+ if (rownum == 0 || streq(row, "first"))
+ XawTablePrependRow (wp->w);
+ else if (rownum == nrows || streq (row, "last"))
+ XawTableAppendRow (wp->w);
+ else
+ XawTableInsertRow (wp->w, rownum);
+
+ return (TCL_OK);
+}
+
+
+/* widgetSetTableSize -- Set the size of the specified table.
+ *
+ * Usage: setTableSize nrows ncols
+ *
+ */
+static int
+widgetSetTableSize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ int nrows, ncols;
+
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ nrows = atoi (argv[1]);
+ ncols = atoi (argv[2]);
+ if (XawTableSetNewSize (wp->w, nrows, ncols) >= 0)
+ return (TCL_OK);
+ else
+ return (TCL_ERROR);
+}
+
+
+
+/* widgetGetTableSize -- Get the size of the specified table.
+ *
+ * Usage: getTableSize nrows ncols
+ *
+ */
+static int
+widgetGetTableSize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char buf[16], *nrows, *ncols;
+ int nr, nc;
+
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ nrows = argv[1];
+ ncols = argv[2];
+
+ XawTableGetSize (wp->w, &nr, &nc);
+
+ sprintf (buf, "%d", nr);
+ Tcl_SetVar (wp->obm->tcl, nrows, buf, 0);
+ sprintf (buf, "%d", nc);
+ Tcl_SetVar (wp->obm->tcl, ncols, buf, 0);
+
+ return (TCL_OK);
+}
+
+
+
+/* widgetRealize -- Realize a widget. This activates and assigns windows for
+ * a widget and all of its descendants. Realizing a widget does not in itself
+ * cause it to appear on the screen.
+ *
+ * Usage: realize
+ */
+static int
+widgetRealize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+
+ XtRealizeWidget (wp->w);
+ return (TCL_OK);
+}
+
+
+/* widgetUnrealize -- Unrealize a widget. This destroys the windows assigned
+ * to a widget and all of its descendants.
+ *
+ * Usage: unrealize
+ */
+static int
+widgetUnrealize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+
+ XtUnrealizeWidget (wp->w);
+ return (TCL_OK);
+}
+
+
+/* widgetIsRealized -- Test whether a widget is realized.
+ *
+ * Usage: isRealized
+ */
+static int
+widgetIsRealized (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Boolean sensitive;
+
+ if (XtIsRealized (wp->w))
+ Tcl_SetResult (wp->obm->tcl, TRUESTR, TCL_STATIC);
+ else
+ Tcl_SetResult (wp->obm->tcl, FALSESTR, TCL_STATIC);
+ return (TCL_OK);
+}
+
+
+/* widgetMap -- Map a widget.
+ *
+ * Usage: map
+ */
+static int
+widgetMap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+
+ XtRealizeWidget (wp->w);
+ XtMapWidget (wp->w);
+ return (TCL_OK);
+}
+
+
+/* widgetUnmap -- Unmap a widget.
+ *
+ * Usage: unmap
+ */
+static int
+widgetUnmap (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ Widget w = wp->w;
+
+ if (!XtIsRealized(w) || !XtWindow(w))
+ return (TCL_ERROR);
+
+ XmuUpdateMapHints (obm->display, XtWindow(w), NULL);
+ XWithdrawWindow (obm->display, XtWindow(w),
+ XScreenNumberOfScreen(obm->screen));
+
+ return (TCL_OK);
+}
+
+
+/* widgetManage -- Manage a list of child widgets. These should share the
+ * same common parent, a geometry widget of some sort. Managing the
+ * children makes them appear in the window, possibly causing the other
+ * children to be rearranged in the window.
+ *
+ * Usage: manage child [child ...]
+ *
+ * This message should be sent to the geometry widget which is the parent
+ * of the children.
+ */
+static int
+widgetManage (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Widget w, children[512];
+ int nchildren, i;
+
+ for (i=1, nchildren=0; i < argc; i++)
+ if (w = XtNameToWidget (wp->w, argv[i]))
+ children[nchildren++] = w;
+
+ XtManageChildren (children, nchildren);
+ return (TCL_OK);
+}
+
+
+/* widgetUnmanage -- Unmanage a list of child widgets. These should share the
+ * same common parent, a geometry widget of some sort. Unmanaging the
+ * children makes them disappear from the window and be removed from geometry
+ * management, possibly causing the other children to be rearranged in the
+ * window.
+ *
+ * Usage: unmanage child [child ...]
+ *
+ * This message should be sent to the geometry widget which is the parent
+ * of the children.
+ */
+static int
+widgetUnmanage (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Widget w, children[512];
+ int nchildren, i;
+
+ for (i=1, nchildren=0; i < argc; i++)
+ if (w = XtNameToWidget (wp->w, argv[i]))
+ children[nchildren++] = w;
+
+ XtUnmanageChildren (children, nchildren);
+ return (TCL_OK);
+}
+
+
+/* widgetPopup -- Popup a shell widget. If no grab is indicated the popup
+ * can remain up while other windows accept input.
+ *
+ * Usage: popup [grab-kind]
+ */
+static int
+widgetPopup (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ XtGrabKind grab;
+
+ grab = XtGrabNone;
+ if (argc >= 2) {
+ if (strcmp (argv[1], "GrabNone") == 0)
+ grab = XtGrabNone;
+ else if (strcmp (argv[1], "GrabNonexclusive") == 0)
+ grab = XtGrabNonexclusive;
+ else if (strcmp (argv[1], "GrabExclusive") == 0)
+ grab = XtGrabExclusive;
+ }
+
+ XtPopup (wp->w, grab);
+ return (TCL_OK);
+}
+
+
+/* widgetPopdown -- Popdown a shell widget.
+ *
+ * Usage: popdown
+ */
+static int
+widgetPopdown (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+
+ XtPopdown (wp->w);
+ return (TCL_OK);
+}
+
+
+/* widgetPopupSpringLoaded -- Popup a shell widget, e.g., a popup menu.
+ * This implies an exclusive grab.
+ *
+ * Usage: popupSpringLoaded
+ */
+static int
+widgetPopupSpringLoaded (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+
+ XtPopupSpringLoaded (wp->w);
+ return (TCL_OK);
+}
+
+
+/* widgetMove -- Move a widget to the given window relative coordinates.
+ *
+ * Usage: move x y
+ */
+static int
+widgetMove (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Arg args[10]; int nargs=0;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[nargs], XtNx, atoi(argv[1])); nargs++;
+ XtSetArg (args[nargs], XtNy, atoi(argv[2])); nargs++;
+
+ XtSetValues (wp->w, args, nargs);
+
+ return (TCL_OK);
+}
+
+
+/* widgetResize -- Resize a widget.
+ *
+ * Usage: resize width height [border-width]
+ */
+static int
+widgetResize (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Arg args[10]; int nargs=0;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[nargs], XtNwidth, atoi(argv[1])); nargs++;
+ XtSetArg (args[nargs], XtNheight, atoi(argv[2])); nargs++;
+ if (argc > 3) {
+ XtSetArg (args[nargs], XtNborderWidth, atoi(argv[3]));
+ nargs++;
+ }
+
+ XtSetValues (wp->w, args, nargs);
+
+ return (TCL_OK);
+}
+
+
+/* widgetConfigure -- Configure a widget, i.e., execute a simultaneous
+ * move and resize.
+ *
+ * Usage: configure x y width height [border-width]
+ */
+static int
+widgetConfigure (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Arg args[10]; int nargs=0;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ XtSetArg (args[nargs], XtNx, atoi(argv[1])); nargs++;
+ XtSetArg (args[nargs], XtNy, atoi(argv[2])); nargs++;
+ XtSetArg (args[nargs], XtNwidth, atoi(argv[3])); nargs++;
+ XtSetArg (args[nargs], XtNheight, atoi(argv[4])); nargs++;
+ if (argc > 5) {
+ XtSetArg (args[nargs], XtNborderWidth, atoi(argv[5]));
+ nargs++;
+ }
+
+ XtSetValues (wp->w, args, nargs);
+
+ return (TCL_OK);
+}
+
+
+/* widgetParseGeometry -- Compute the position and size of a region within
+ * a window , given a user defined geometry and a default geometry.
+ *
+ * Usage: parseGeometry user_geom def_geom x y width height
+ *
+ * Geometries are specified as in X, e.g. 123x456+5-5. The default geometry
+ * must be fully specified.
+ */
+static int
+widgetParseGeometry (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+
+ register int uflags, dflags;
+ Dimension winWidth, winHeight;
+ int need, x, y, width, height;
+ char *user_geom, *def_geom;
+ char *s_x, *s_y, *s_width, *s_height;
+ unsigned int u_width, u_height;
+ unsigned int d_width, d_height;
+ int u_x, u_y, d_x, d_y;
+ char buf[SZ_NUMBER];
+
+ if (argc != 7)
+ return (TCL_ERROR);
+
+ user_geom = argv[1];
+ def_geom = argv[2];
+ s_x = argv[3];
+ s_y = argv[4];
+ s_width = argv[5];
+ s_height = argv[6];
+
+ XtVaGetValues (wp->w,
+ XtNwidth, &winWidth,
+ XtNheight, &winHeight,
+ NULL);
+
+ /* Parse the default geometry. */
+ dflags = XParseGeometry (def_geom, &d_x, &d_y, &d_width, &d_height);
+ need = (XValue | YValue | WidthValue | HeightValue);
+ if ((dflags & need) != need) {
+ Tcl_SetResult (obm->tcl,
+ "default geometry not fully qualified", TCL_VOLATILE);
+ return (TCL_ERROR);
+ }
+
+ /* Parse the user supplied geometry. */
+ uflags = XParseGeometry (user_geom, &u_x, &u_y, &u_width, &u_height);
+
+ /* Compute the final geometry. This is constrained to fit within
+ * the given window.
+ */
+ width = (uflags & WidthValue) ? u_width : d_width;
+ width = max(0, min((int)winWidth, width));
+
+ height = (uflags & HeightValue) ? u_height : d_height;
+ height = max(0, min((int)winHeight, height));
+
+ if (uflags & XValue)
+ x = (uflags & XNegative) ? winWidth + u_x - width : u_x;
+ else
+ x = (dflags & XNegative) ? winWidth + d_x - width : d_x;
+ x = max(0, min((int)winWidth-width, x));
+
+ if (uflags & YValue)
+ y = (uflags & YNegative) ? winHeight + u_y - height : u_y;
+ else
+ y = (dflags & YNegative) ? winHeight + d_y - height : d_y;
+ y = max(0, min((int)winHeight-height, y));
+
+ /* Output the results.
+ */
+ sprintf (buf, "%d", x);
+ if ((Tcl_SetVar (obm->tcl, s_x, buf, 0)) == NULL)
+ return (TCL_ERROR);
+ sprintf (buf, "%d", y);
+ if ((Tcl_SetVar (obm->tcl, s_y, buf, 0)) == NULL)
+ return (TCL_ERROR);
+ sprintf (buf, "%d", width);
+ if ((Tcl_SetVar (obm->tcl, s_width, buf, 0)) == NULL)
+ return (TCL_ERROR);
+ sprintf (buf, "%d", height);
+ if ((Tcl_SetVar (obm->tcl, s_height, buf, 0)) == NULL)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
+
+
+/* widgetGetGeometry -- Given a subregion within a rectangular window compute
+ * the geometry specification which best describes the region.
+ *
+ * Usage: geom = getGeometry x y width height [nogravity]
+ *
+ * If gravity is enabled (the default) and the rect is near an edge or corner
+ * the specified geometry will be in the form -X-Y to cause the region to
+ * track the edge or corner of the window. Otherwise the absolute coordinates
+ * of the region are returned.
+ */
+static int
+widgetGetGeometry (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+
+ register char *op;
+ Dimension winWidth, winHeight;
+ int dist, gravity, x, y, width, height;
+ char buf[128];
+
+ if (argc < 5)
+ return (TCL_ERROR);
+
+ x = atoi(argv[1]);
+ y = atoi(argv[2]);
+ width = atoi(argv[3]);
+ height = atoi(argv[4]);
+ gravity = (argc < 6 || strncmp(argv[5],"no",2) != 0);
+
+ XtVaGetValues (wp->w,
+ XtNwidth, &winWidth,
+ XtNheight, &winHeight,
+ NULL);
+
+ sprintf (buf, "%dx%d", width, height);
+ for (op=buf; *op; )
+ op++;
+
+ if (gravity && (dist = winWidth - (x + width)) < 10)
+ sprintf (op, "-%d", dist);
+ else
+ sprintf (op, "+%d", x);
+ while (*op)
+ op++;
+
+ if (gravity && (dist = winHeight - (y + height)) < 10)
+ sprintf (op, "-%d", dist);
+ else
+ sprintf (op, "+%d", y);
+
+ Tcl_SetResult (wp->obm->tcl, buf, TCL_VOLATILE);
+ return (TCL_OK);
+}
+
+
+/* widgetSetSensitive -- Set the sensitivity of a widget.
+ *
+ * Usage: setSensitive <sensitive>
+ */
+static int
+widgetSetSensitive (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Boolean sensitive;
+
+ sensitive = FALSE;
+ if (argc >= 2)
+ if (strcmp (argv[1], "true") == 0 ||
+ strcmp (argv[1], "True") == 0 ||
+ strcmp (argv[1], "TRUE") == 0 ||
+ strcmp (argv[1], "1") == 0) {
+
+ sensitive = TRUE;
+ }
+
+ XtSetSensitive (wp->w, sensitive);
+ return (TCL_OK);
+}
+
+
+/* widgetIsSensitive -- Test the sensitivity of a widget.
+ *
+ * Usage: isSensitive
+ */
+static int
+widgetIsSensitive (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ WidgetPrivate wp = &obj->widget;
+ Boolean sensitive;
+
+ if (XtIsSensitive (wp->w))
+ Tcl_SetResult (wp->obm->tcl, TRUESTR, TCL_STATIC);
+ else
+ Tcl_SetResult (wp->obm->tcl, FALSESTR, TCL_STATIC);
+
+ return (TCL_OK);
+}
+
+
+/*
+ * Event handling facility.
+ */
+
+/* Event masks. */
+#define NonMaskable 0
+struct evMask {
+ char *name;
+ int mask;
+} eventMasks[] = {
+ { "nonMaskable", NonMaskable },
+ { "button1MotionMask", Button1MotionMask },
+ { "button2MotionMask", Button2MotionMask },
+ { "button3MotionMask", Button3MotionMask },
+ { "button4MotionMask", Button4MotionMask },
+ { "button5MotionMask", Button5MotionMask },
+ { "buttonMotionMask", ButtonMotionMask },
+ { "buttonPressMask", ButtonPressMask },
+ { "buttonReleaseMask", ButtonReleaseMask },
+ { "colormapChangeMask", ColormapChangeMask },
+ { "enterWindowMask", EnterWindowMask },
+ { "exposureMask", ExposureMask },
+ { "focusChangeMask", FocusChangeMask },
+ { "keyPressMask", KeyPressMask },
+ { "keyReleaseMask", KeyReleaseMask },
+ { "keymapStateMask", KeymapStateMask },
+ { "leaveWindowMask", LeaveWindowMask },
+ { "noEventMask", NoEventMask },
+ { "ownerGrabButtonMask", OwnerGrabButtonMask },
+ { "pointerMotionHintMask", PointerMotionHintMask },
+ { "pointerMotionMask", PointerMotionMask },
+ { "propertyChangeMask", PropertyChangeMask },
+ { "resizeRedirectMask", ResizeRedirectMask },
+ { "structureNotifyMask", StructureNotifyMask },
+ { "substructureNotifyMask", SubstructureNotifyMask },
+ { "substructureRedirectMask", SubstructureRedirectMask },
+ { "visibilityChangeMask", VisibilityChangeMask },
+};
+
+/* Event types. */
+struct evType {
+ char *name;
+ int type;
+} eventTypes[] = {
+ { "buttonPress", ButtonPress },
+ { "buttonRelease", ButtonRelease },
+ { "circulateNotify", CirculateNotify },
+ { "circulateRequest", CirculateRequest },
+ { "clientMessage", ClientMessage },
+ { "colormapNotify", ColormapNotify },
+ { "configureNotify", ConfigureNotify },
+ { "configureRequest", ConfigureRequest },
+ { "createNotify", CreateNotify },
+ { "destroyNotify", DestroyNotify },
+ { "enterNotify", EnterNotify },
+ { "expose", Expose },
+ { "focusIn", FocusIn },
+ { "focusOut", FocusOut },
+ { "graphicsExpose", GraphicsExpose },
+ { "gravityNotify", GravityNotify },
+ { "keyPress", KeyPress },
+ { "keyRelease", KeyRelease },
+ { "keymapNotify", KeymapNotify },
+ { "leaveNotify", LeaveNotify },
+ { "mapNotify", MapNotify },
+ { "mapRequest", MapRequest },
+ { "mappingNotify", MappingNotify },
+ { "motionNotify", MotionNotify },
+ { "noExpose", NoExpose },
+ { "propertyNotify", PropertyNotify },
+ { "reparentNotify", ReparentNotify },
+ { "resizeRequest", ResizeRequest },
+ { "selectionClear", SelectionClear },
+ { "selectionNotify", SelectionNotify },
+ { "selectionRequest", SelectionRequest },
+ { "unmapNotify", UnmapNotify },
+ { "visibilityNotify", VisibilityNotify },
+};
+
+
+/* widgetAddEventHandler -- Add a custom event handler to a widget. A list
+ * of event masks is given to define the classes of events the user supplied
+ * event handling procedure is to receive.
+ *
+ * Usage: addEventHandler <procname> <event-mask> [<event-mask>...]
+ */
+static int
+widgetAddEventHandler (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ ObmCallback cb, new_cb;
+ int event_mask, i, j;
+ Boolean nonmaskable;
+
+ if (argc < 3)
+ return (TCL_ERROR);
+
+ event_mask = 0;
+ nonmaskable = FALSE;
+
+ /* Get the event mask. */
+ for (j=2; j < argc; j++) {
+ for (i=0; i < XtNumber(eventMasks); i++) {
+ if (strcmp (eventMasks[i].name, argv[j]) == 0) {
+ if (eventMasks[i].mask == NonMaskable)
+ nonmaskable = TRUE;
+ else
+ event_mask |= eventMasks[i].mask;
+ break;
+ }
+ }
+ }
+
+ /* Create event handler record. */
+ new_cb = (ObmCallback) XtCalloc (1, sizeof (obmCallback));
+ strcpy (new_cb->name, argv[1]);
+ new_cb->u.obj = (ObmObject) obj;
+ new_cb->client_data = (XtPointer) event_mask;
+
+ /* Add record to tail of event handler list. */
+ if (wp->event_handler) {
+ for (cb = wp->event_handler; cb->next; cb = cb->next)
+ ;
+ cb->next = new_cb;
+ } else
+ wp->event_handler = new_cb;
+
+ /* Post event handler. */
+ XtAddEventHandler (wp->w, event_mask, nonmaskable, widgetEvent, new_cb);
+
+ return (TCL_OK);
+}
+
+/* widgetRemoveEventHandler -- Remove an event handler previously posted
+ * with addEventHandler, above.
+ *
+ * Usage: removeEventHandler procname
+ */
+static int
+widgetRemoveEventHandler (msg, tcl, argc, argv)
+MsgContext msg;
+Tcl_Interp *tcl;
+int argc;
+char **argv;
+{
+ WidgetObject obj = (WidgetObject) msg->object[msg->level];
+ register WidgetPrivate wp = &obj->widget;
+ register ObmContext obm = wp->obm;
+ register ObmCallback cb, pcb;
+ Boolean nonmaskable;
+ char *procname;
+
+ if (argc < 2)
+ return (TCL_ERROR);
+
+ procname = argv[1];
+ nonmaskable = False;
+
+ for (cb = wp->event_handler, pcb=NULL; cb; pcb=cb, cb = cb->next)
+ if (strcmp (cb->name, procname) == 0)
+ break;
+
+ if (cb) {
+ XtRemoveEventHandler (wp->w, (int) cb->client_data, nonmaskable,
+ widgetEvent, cb);
+ if (pcb)
+ pcb->next = cb->next;
+ else
+ wp->event_handler = NULL;
+ XtFree ((char *)cb);
+ }
+
+ return (TCL_OK);
+}
+
+
+/* widgetEvent -- Generic event handler called when a widget event handler
+ * posted by addEventHandler is called.
+ *
+ * The user event handler is called as
+ *
+ * userEventHandler widget event-type time wx wy rx ry other
+ *
+ * where "other" is an event-type specific list of fields describing the
+ * the event.
+ */
+static void
+widgetEvent (w, cb, event, continue_to_dispatch)
+Widget w;
+ObmCallback cb;
+XEvent *event;
+Boolean *continue_to_dispatch;
+{
+ WidgetObject obj = (WidgetObject) cb->u.obj;
+ WidgetPrivate wp = &obj->widget;
+ ObmContext obm = wp->obm;
+ char cmd[SZ_COMMAND];
+ register char *ip, *op;
+ register int i, j;
+ int status;
+
+ /* Our job is to translate the X event into a call to a widget server
+ * procedure. Start with the callback procedure name.
+ */
+ for (ip = cb->name, op=cmd; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+
+ /* Add the name of the widget that received the event. */
+ for (ip = obj->core.name; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+
+ /* Add the event type. */
+ for (i=0; i < XtNumber(eventTypes); i++) {
+ if (eventTypes[i].type == event->type) {
+ for (ip = eventTypes[i].name; *ip; )
+ *op++ = *ip++;
+ *op++ = ' ';
+ break;
+ }
+
+ /* Ignore events we don't know anything about. */
+ if (i >= XtNumber(eventTypes))
+ return;
+ }
+
+ /* Add the event specific fields. */
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ { XKeyPressedEvent *ev = (XKeyPressedEvent *) event;
+ char buf[20];
+ int n;
+
+ sprintf (op, "%u %d %d %d %d ",
+ ev->time, ev->x, ev->y, ev->x_root, ev->y_root);
+ while (*op) op++;
+
+ *op++ = '{';
+ if ((n = XLookupString(ev,buf,sizeof(buf),NULL,NULL)) > 0) {
+ for (ip=buf; --n >= 0; )
+ if (*ip <= ' ') {
+ *op++ = '^';
+ *op++ = *ip++ + 'A' - 1;
+ } else if (isprint (*ip)) {
+ *op++ = *ip++;
+ } else
+ ip++;
+ } else {
+ /* This case occurs when only a modifier is typed. */
+ for (ip = "??"; *op++ = *ip++; )
+ ;
+ }
+ *op++ = ' ';
+ op = widgetEventState (op, ev->state);
+ while (op > cmd && isspace (*(op-1)))
+ --op;
+ *op++ = '}';
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ { XButtonPressedEvent *ev = (XButtonPressedEvent *) event;
+
+ sprintf (op, "%u %d %d %d %d ",
+ ev->time, ev->x, ev->y, ev->x_root, ev->y_root);
+ while (*op) op++;
+
+ *op++ = '{';
+ sprintf (op, "%d ", ev->button); while (*op) op++;
+ op = widgetEventState (op, ev->state);
+ while (op > cmd && isspace (*(op-1)))
+ --op;
+ *op++ = '}';
+ }
+ break;
+
+ case KeymapNotify:
+ { XKeymapEvent *ev = (XKeymapEvent *) event;
+ KeySym keysym;
+
+ sprintf (op, "0 0 0 0 0 ");
+ while (*op) op++;
+
+ *op++ = '{';
+ for (j=0; j < 32; j++) {
+ for (i=0; i < 8; i++)
+ if ((ev->key_vector[j]) & (1 << i)) {
+ keysym = XKeycodeToKeysym (obm->display,
+ j * 8 + i, 0);
+ if (ip = XKeysymToString (keysym)) {
+ while (*ip)
+ *op++ = *ip++;
+ *op++ = ' ';
+ }
+ }
+ }
+ *op++ = '}';
+ }
+ break;
+
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ { XPointerMovedEvent *ev = (XPointerMovedEvent *) event;
+
+ sprintf (op, "%u %d %d %d %d ",
+ ev->time, ev->x, ev->y, ev->x_root, ev->y_root);
+ while (*op) op++;
+
+ *op++ = '{';
+ op = widgetEventState (op, ev->state);
+ while (op > cmd && isspace (*(op-1)))
+ --op;
+ *op++ = '}';
+ }
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ { XFocusChangeEvent *ev = (XFocusChangeEvent *) event;
+
+ sprintf (op, "0 0 0 0 0 ");
+ while (*op) op++;
+ }
+ break;
+
+ case Expose:
+ { XExposeEvent *ev = (XExposeEvent *) event;
+
+ sprintf (op, "0 %d %d 0 0 ", ev->x, ev->y);
+ while (*op) op++;
+
+ *op++ = '{';
+ sprintf (op, "%d ", ev->width); while (*op) op++;
+ sprintf (op, "%d ", ev->height); while (*op) op++;
+ sprintf (op, "%d ", ev->count); while (*op) op++;
+ *op++ = '}';
+ }
+ break;
+
+ case GraphicsExpose:
+ { XGraphicsExposeEvent *ev = (XGraphicsExposeEvent *) event;
+
+ sprintf (op, "0 %d %d 0 0 ", ev->x, ev->y);
+ while (*op) op++;
+
+ *op++ = '{';
+ sprintf (op, "%d ", ev->width); while (*op) op++;
+ sprintf (op, "%d ", ev->height); while (*op) op++;
+ sprintf (op, "%d ", ev->count); while (*op) op++;
+ *op++ = '}';
+ }
+ break;
+
+ case NoExpose:
+ case ColormapNotify:
+ case PropertyNotify:
+ case VisibilityNotify:
+ case ResizeRequest:
+ case CirculateNotify:
+ case ConfigureNotify:
+ case CreateNotify:
+ case DestroyNotify:
+ case GravityNotify:
+ case MapNotify:
+ case MappingNotify:
+ case ReparentNotify:
+ case SelectionNotify:
+ case UnmapNotify:
+ {
+ sprintf (op, "0 0 0 0 0 ");
+ while (*op) op++;
+ }
+ break;
+
+ case CirculateRequest:
+ case ConfigureRequest:
+ case MapRequest:
+ case SelectionRequest:
+ {
+ sprintf (op, "0 0 0 0 0 ");
+ while (*op) op++;
+ }
+ break;
+
+
+ case ClientMessage:
+ case SelectionClear:
+ {
+ sprintf (op, "0 0 0 0 0 ");
+ while (*op) op++;
+ }
+ break;
+ }
+ *op = '\0';
+
+ /* Call the user supplied event handler. */
+ status = Tcl_Eval (obm->tcl, cmd);
+ if (status != TCL_OK) {
+ fprintf (stderr, "Error on line %d of %s: %s\n",
+ obm->tcl->errorLine, cb->name, obm->tcl->result);
+ }
+}
+
+
+/* widgetEventState -- Encode the "state" field of an event struct.
+ */
+char *
+widgetEventState (op, state)
+register char *op;
+unsigned int state;
+{
+ if (state & ShiftMask)
+ { sprintf (op, "shift "); while (*op) op++; }
+ if (state & LockMask)
+ { sprintf (op, "lock "); while (*op) op++; }
+ if (state & ControlMask)
+ { sprintf (op, "control "); while (*op) op++; }
+ if (state & Mod1Mask)
+ { sprintf (op, "mod1 "); while (*op) op++; }
+ if (state & Mod2Mask)
+ { sprintf (op, "mod2 "); while (*op) op++; }
+ if (state & Mod3Mask)
+ { sprintf (op, "mod3 "); while (*op) op++; }
+ if (state & Mod4Mask)
+ { sprintf (op, "mod4 "); while (*op) op++; }
+ if (state & Mod5Mask)
+ { sprintf (op, "mod5 "); while (*op) op++; }
+
+ *op = '\0';
+ return (op);
+}
+
+
+
+/* widgetGetFontName -- Encode the font name in a string in XLFD format.
+ */
+
+#define SZ_FONT_NAME 128
+
+static char *
+widgetGetFontName (display, fs) /* MF016 */
+Display *display;
+XFontStruct *fs;
+{
+ register int i;
+ unsigned long val;
+ char *name = (char *) malloc (SZ_FONT_NAME), *str, *lp;
+
+ name[0] = '\0';
+ if (fs) {
+ for (i=0; i < NUMITEMS(fontNamePropTable); i++) {
+ fontNamePropTable[i].atom =
+ XInternAtom(display, fontNamePropTable[i].name, 0);
+ if (XGetFontProperty (fs, fontNamePropTable[i].atom, &val)) {
+ switch (fontNamePropTable[i].type) {
+ case atom:
+ str = XGetAtomName (display, (Atom)val);
+ for (lp=str; *lp; lp++)
+ if (isupper(*lp))
+ *lp = tolower(*lp);
+ strcat (name, str);
+ XFree (str);
+ break;
+
+ case pixel_size:
+ case point_size:
+ case resolution:
+ case resolution_x:
+ case resolution_y:
+ case average_width:
+ case scaledX:
+ case scaledY:
+ case unscaled:
+ case scaledXoverY:
+ case uncomputed:
+ sprintf(name, "%s%d", name, val);
+ break;
+ }
+ } else
+ strcat(name, "*");
+
+ if (i != (NUMITEMS(fontNamePropTable)-1))
+ strcat(name, "-");
+ }
+ }
+
+ return (name);
+}
diff --git a/vendor/x11iraf/obm/widget.h b/vendor/x11iraf/obm/widget.h
new file mode 100644
index 00000000..ffaef86a
--- /dev/null
+++ b/vendor/x11iraf/obm/widget.h
@@ -0,0 +1,47 @@
+/* Copyright(c) 1993 Association of Universities for Research in Astronomy Inc.
+ */
+
+/*
+ * WIDGET.H -- Widget class public definitions (used to subclass widgets).
+ * These definitions are intended for use only by Widget subclasses, not by
+ * client applications.
+ */
+
+struct widgetPrivate {
+ Widget w;
+ ObmContext obm;
+ ObmCallback callback;
+ ObmCallback event_handler;
+ Boolean widget_destroyed;
+ XawTextPosition text_pos;
+ XtCallbackProc response_cb;
+ int text_newline;
+ char translation_table_name[SZ_NAME];
+ char *data;
+ int datalen;
+};
+
+typedef struct widgetPrivate *WidgetPrivate;
+
+struct widgetObject {
+ struct obmObjectCore core;
+ struct widgetPrivate widget;
+};
+
+typedef struct widgetObject *WidgetObject;
+
+/* Object message context. */
+struct msgContext {
+ Tcl_Interp *tcl; /* class interpreter */
+ ObmObject object[MAX_LEVELS]; /* object which received last message */
+ int level;
+};
+typedef struct msgContext *MsgContext;
+
+extern int WidgetEvaluate();
+extern void WidgetDestroy();
+extern void WidgetClassDestroy();
+extern ObmObject WidgetCreate();
+extern WidgetObject widgetToObject();
+extern int coordType();
+extern char *widgetEventState();