aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/ObmW
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/x11iraf/obm/ObmW')
-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
281 files changed, 166840 insertions, 0 deletions
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_ */