From fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Wed, 8 Jul 2015 20:46:52 -0400 Subject: Initial commit --- vendor/x11iraf/obm/ObmW/Arrow.c | 465 + vendor/x11iraf/obm/ObmW/Arrow.h | 70 + vendor/x11iraf/obm/ObmW/Arrow.man | 680 + vendor/x11iraf/obm/ObmW/ArrowP.h | 51 + vendor/x11iraf/obm/ObmW/Board.c | 393 + vendor/x11iraf/obm/ObmW/Board.h | 120 + vendor/x11iraf/obm/ObmW/Board.man | 749 ++ vendor/x11iraf/obm/ObmW/BoardP.h | 56 + vendor/x11iraf/obm/ObmW/Button.c | 123 + vendor/x11iraf/obm/ObmW/Button.h | 20 + vendor/x11iraf/obm/ObmW/Button.man | 264 + vendor/x11iraf/obm/ObmW/ButtonP.h | 41 + vendor/x11iraf/obm/ObmW/CHANGES | 32 + vendor/x11iraf/obm/ObmW/Common.c | 770 ++ vendor/x11iraf/obm/ObmW/Common.c.ORIG | 852 ++ vendor/x11iraf/obm/ObmW/Common.h | 108 + vendor/x11iraf/obm/ObmW/Common.man | 1226 ++ vendor/x11iraf/obm/ObmW/CommonP.h | 108 + vendor/x11iraf/obm/ObmW/Container.c | 346 + vendor/x11iraf/obm/ObmW/Container.h | 61 + vendor/x11iraf/obm/ObmW/ContainerP.h | 71 + vendor/x11iraf/obm/ObmW/Converters.h | 42 + vendor/x11iraf/obm/ObmW/DrawIString.c | 45 + vendor/x11iraf/obm/ObmW/DrawString.c | 45 + vendor/x11iraf/obm/ObmW/DrawingArea.c | 193 + vendor/x11iraf/obm/ObmW/DrawingArea.h | 35 + vendor/x11iraf/obm/ObmW/DrawingAreaP.h | 45 + vendor/x11iraf/obm/ObmW/FIXFWF | 6 + vendor/x11iraf/obm/ObmW/FWFSED | 17 + vendor/x11iraf/obm/ObmW/Frame.c | 654 + vendor/x11iraf/obm/ObmW/Frame.h | 142 + vendor/x11iraf/obm/ObmW/Frame.man | 1062 ++ vendor/x11iraf/obm/ObmW/FrameP.h | 48 + vendor/x11iraf/obm/ObmW/Gcs.c | 580 + vendor/x11iraf/obm/ObmW/Gcs.h | 121 + vendor/x11iraf/obm/ObmW/Group.c | 383 + vendor/x11iraf/obm/ObmW/Group.h | 74 + vendor/x11iraf/obm/ObmW/Group.man | 723 ++ vendor/x11iraf/obm/ObmW/GroupP.h | 48 + vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c | 13283 ++++++++++++++++++++ vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG | 11897 ++++++++++++++++++ vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h | 306 + vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h | 587 + vendor/x11iraf/obm/ObmW/Gterm.c | 1944 +++ vendor/x11iraf/obm/ObmW/Gterm.c.ORIG | 11897 ++++++++++++++++++ vendor/x11iraf/obm/ObmW/Gterm.h | 306 + vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c | 12188 ++++++++++++++++++ vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG | 11897 ++++++++++++++++++ vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h | 247 + vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h | 524 + vendor/x11iraf/obm/ObmW/GtermCmap.c | 765 ++ vendor/x11iraf/obm/ObmW/GtermCnv.c | 486 + vendor/x11iraf/obm/ObmW/GtermDebug.c | 23 + vendor/x11iraf/obm/ObmW/GtermGraphics.c | 1474 +++ vendor/x11iraf/obm/ObmW/GtermImaging.c | 3164 +++++ vendor/x11iraf/obm/ObmW/GtermMapping.c | 2189 ++++ vendor/x11iraf/obm/ObmW/GtermMarker.c | 4674 +++++++ vendor/x11iraf/obm/ObmW/GtermP.h | 598 + vendor/x11iraf/obm/ObmW/GtermUtil.c | 52 + vendor/x11iraf/obm/ObmW/HTML-PSformat.c | 1544 +++ vendor/x11iraf/obm/ObmW/HTML.c | 6177 +++++++++ vendor/x11iraf/obm/ObmW/HTML.h | 491 + vendor/x11iraf/obm/ObmW/HTML.notes | 72 + vendor/x11iraf/obm/ObmW/HTMLP.h | 246 + vendor/x11iraf/obm/ObmW/HTMLamp.h | 141 + vendor/x11iraf/obm/ObmW/HTMLformat.c | 6285 +++++++++ vendor/x11iraf/obm/ObmW/HTMLimages.c | 891 ++ vendor/x11iraf/obm/ObmW/HTMLjot.c | 642 + vendor/x11iraf/obm/ObmW/HTMLlists.c | 897 ++ vendor/x11iraf/obm/ObmW/HTMLparse.c | 1373 ++ vendor/x11iraf/obm/ObmW/HTMLwidgets.c | 4014 ++++++ vendor/x11iraf/obm/ObmW/Icon.c | 224 + vendor/x11iraf/obm/ObmW/Icon.h | 31 + vendor/x11iraf/obm/ObmW/Icon.man | 392 + vendor/x11iraf/obm/ObmW/IconP.h | 41 + vendor/x11iraf/obm/ObmW/Imakefile | 241 + vendor/x11iraf/obm/ObmW/Label.c | 345 + vendor/x11iraf/obm/ObmW/Label.h | 130 + vendor/x11iraf/obm/ObmW/Label.man | 732 ++ vendor/x11iraf/obm/ObmW/LabelP.h | 89 + vendor/x11iraf/obm/ObmW/Layout.c | 965 ++ vendor/x11iraf/obm/ObmW/Layout.c.ORIG | 952 ++ vendor/x11iraf/obm/ObmW/Layout.ex | 463 + vendor/x11iraf/obm/ObmW/Layout.h | 94 + vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip | Bin 0 -> 17910 bytes vendor/x11iraf/obm/ObmW/LayoutP.h | 213 + vendor/x11iraf/obm/ObmW/ListTree.c | 2265 ++++ vendor/x11iraf/obm/ObmW/ListTree.h | 123 + vendor/x11iraf/obm/ObmW/ListTreeP.h | 109 + vendor/x11iraf/obm/ObmW/Makefile | 1192 ++ vendor/x11iraf/obm/ObmW/MenuBar.c | 183 + vendor/x11iraf/obm/ObmW/MenuBar.h | 15 + vendor/x11iraf/obm/ObmW/MenuBar.man | 365 + vendor/x11iraf/obm/ObmW/MenuBarP.h | 47 + vendor/x11iraf/obm/ObmW/MultiList.c | 1793 +++ vendor/x11iraf/obm/ObmW/MultiList.h | 279 + vendor/x11iraf/obm/ObmW/MultiList.man | 207 + vendor/x11iraf/obm/ObmW/MultiListP.h | 200 + vendor/x11iraf/obm/ObmW/Notes | 191 + vendor/x11iraf/obm/ObmW/README | 83 + vendor/x11iraf/obm/ObmW/RadioGrp.c | 239 + vendor/x11iraf/obm/ObmW/RadioGrp.h | 22 + vendor/x11iraf/obm/ObmW/RadioGrp.man | 384 + vendor/x11iraf/obm/ObmW/RadioGrpP.h | 43 + vendor/x11iraf/obm/ObmW/RowCol.c | 346 + vendor/x11iraf/obm/ObmW/RowCol.h | 60 + vendor/x11iraf/obm/ObmW/RowCol.man | 482 + vendor/x11iraf/obm/ObmW/RowColP.h | 51 + vendor/x11iraf/obm/ObmW/Scrollbar.c | 427 + vendor/x11iraf/obm/ObmW/Scrollbar.h | 105 + vendor/x11iraf/obm/ObmW/Scrollbar.man | 812 ++ vendor/x11iraf/obm/ObmW/ScrollbarP.h | 58 + vendor/x11iraf/obm/ObmW/Separator.c | 357 + vendor/x11iraf/obm/ObmW/Separator.h | 98 + vendor/x11iraf/obm/ObmW/SeparatorP.h | 62 + vendor/x11iraf/obm/ObmW/Simple.c | 489 + vendor/x11iraf/obm/ObmW/SimpleMenu.c | 1467 +++ vendor/x11iraf/obm/ObmW/Slider2.c | 640 + vendor/x11iraf/obm/ObmW/Slider2.h | 96 + vendor/x11iraf/obm/ObmW/Slider2.man | 1068 ++ vendor/x11iraf/obm/ObmW/Slider2P.h | 87 + vendor/x11iraf/obm/ObmW/TabString.h | 26 + vendor/x11iraf/obm/ObmW/Table.c | 4594 +++++++ vendor/x11iraf/obm/ObmW/Table.h | 539 + vendor/x11iraf/obm/ObmW/Table3d.c | 924 ++ vendor/x11iraf/obm/ObmW/Table3d.h | 145 + vendor/x11iraf/obm/ObmW/TableP.h | 166 + vendor/x11iraf/obm/ObmW/TableUtil.c | 919 ++ vendor/x11iraf/obm/ObmW/TableUtil.h | 94 + vendor/x11iraf/obm/ObmW/Tablist2Tabs.c | 35 + vendor/x11iraf/obm/ObmW/Tabs.c | 2183 ++++ vendor/x11iraf/obm/ObmW/Tabs.h | 186 + vendor/x11iraf/obm/ObmW/TabsP.h | 127 + vendor/x11iraf/obm/ObmW/TextWidth.c | 39 + vendor/x11iraf/obm/ObmW/Toggle.c | 290 + vendor/x11iraf/obm/ObmW/Toggle.h | 60 + vendor/x11iraf/obm/ObmW/Toggle.man | 538 + vendor/x11iraf/obm/ObmW/ToggleP.h | 50 + vendor/x11iraf/obm/ObmW/Xraw/3d.h | 145 + vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h | 33 + vendor/x11iraf/obm/ObmW/Xraw/Arrow.h | 144 + vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h | 45 + vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h | 87 + vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h | 93 + vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h | 190 + vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h | 133 + vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h | 110 + vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h | 138 + vendor/x11iraf/obm/ObmW/Xraw/Box.h | 74 + vendor/x11iraf/obm/ObmW/Xraw/BoxP.h | 90 + vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h | 35 + vendor/x11iraf/obm/ObmW/Xraw/Clock.h | 87 + vendor/x11iraf/obm/ObmW/Xraw/ClockP.h | 95 + vendor/x11iraf/obm/ObmW/Xraw/Command.h | 104 + vendor/x11iraf/obm/ObmW/Xraw/CommandP.h | 121 + vendor/x11iraf/obm/ObmW/Xraw/Container.h | 61 + vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h | 71 + vendor/x11iraf/obm/ObmW/Xraw/Dialog.h | 82 + vendor/x11iraf/obm/ObmW/Xraw/DialogP.h | 76 + vendor/x11iraf/obm/ObmW/Xraw/Form.h | 142 + vendor/x11iraf/obm/ObmW/Xraw/FormP.h | 126 + vendor/x11iraf/obm/ObmW/Xraw/Frame.h | 163 + vendor/x11iraf/obm/ObmW/Xraw/FrameP.h | 95 + vendor/x11iraf/obm/ObmW/Xraw/Grip.h | 83 + vendor/x11iraf/obm/ObmW/Xraw/GripP.h | 79 + vendor/x11iraf/obm/ObmW/Xraw/Label.h | 98 + vendor/x11iraf/obm/ObmW/Xraw/LabelP.h | 111 + vendor/x11iraf/obm/ObmW/Xraw/List.h | 225 + vendor/x11iraf/obm/ObmW/Xraw/ListP.h | 115 + vendor/x11iraf/obm/ObmW/Xraw/Logo.h | 50 + vendor/x11iraf/obm/ObmW/Xraw/LogoP.h | 51 + vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h | 61 + vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h | 80 + vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h | 96 + vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h | 86 + vendor/x11iraf/obm/ObmW/Xraw/Object.h | 37 + vendor/x11iraf/obm/ObmW/Xraw/Paned.h | 229 + vendor/x11iraf/obm/ObmW/Xraw/PanedP.h | 172 + vendor/x11iraf/obm/ObmW/Xraw/Panner.h | 104 + vendor/x11iraf/obm/ObmW/Xraw/PannerP.h | 100 + vendor/x11iraf/obm/ObmW/Xraw/Porthole.h | 60 + vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h | 63 + vendor/x11iraf/obm/ObmW/Xraw/Repeater.h | 73 + vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h | 76 + vendor/x11iraf/obm/ObmW/Xraw/Reports.h | 51 + vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h | 221 + vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h | 99 + vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h | 104 + vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h | 64 + vendor/x11iraf/obm/ObmW/Xraw/Separator.h | 99 + vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h | 60 + vendor/x11iraf/obm/ObmW/Xraw/Simple.h | 96 + vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h | 113 + vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h | 169 + vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h | 62 + vendor/x11iraf/obm/ObmW/Xraw/Sme.h | 66 + vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h | 109 + vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h | 121 + vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h | 75 + vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h | 93 + vendor/x11iraf/obm/ObmW/Xraw/SmeP.h | 102 + vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h | 83 + vendor/x11iraf/obm/ObmW/Xraw/StripChart.h | 94 + vendor/x11iraf/obm/ObmW/Xraw/Table.h | 539 + vendor/x11iraf/obm/ObmW/Xraw/Table3d.h | 145 + vendor/x11iraf/obm/ObmW/Xraw/TableP.h | 166 + vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h | 94 + vendor/x11iraf/obm/ObmW/Xraw/Template.h | 65 + vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h | 57 + vendor/x11iraf/obm/ObmW/Xraw/Text.h | 314 + vendor/x11iraf/obm/ObmW/Xraw/TextP.h | 224 + vendor/x11iraf/obm/ObmW/Xraw/TextSink.h | 239 + vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h | 121 + vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h | 224 + vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h | 106 + vendor/x11iraf/obm/ObmW/Xraw/Toggle.h | 170 + vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h | 108 + vendor/x11iraf/obm/ObmW/Xraw/Tree.h | 120 + vendor/x11iraf/obm/ObmW/Xraw/TreeP.h | 112 + vendor/x11iraf/obm/ObmW/Xraw/Viewport.h | 153 + vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h | 92 + vendor/x11iraf/obm/ObmW/Xraw/XawAll.h | 48 + vendor/x11iraf/obm/ObmW/Xraw/XawInit.h | 60 + vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h | 95 + vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h | 60 + vendor/x11iraf/obm/ObmW/Xraw/color.h | 73 + vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h | 94 + vendor/x11iraf/obm/ObmW/_c | 90 + vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm | 8 + vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm | 16 + vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm | 41 + vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm | 48 + vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm | 42 + vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm | 36 + vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm | 46 + vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm | 38 + vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm | 39 + vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm | 26 + vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG | 26 + vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm | 26 + vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm | 26 + vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm | 27 + vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG | 27 + vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm | 27 + vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm | 27 + vendor/x11iraf/obm/ObmW/bitmaps/square0.pm | 24 + vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm | 24 + vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm | 24 + vendor/x11iraf/obm/ObmW/bitmaps/square1.pm | 24 + vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm | 25 + vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm | 25 + vendor/x11iraf/obm/ObmW/color.c | 309 + vendor/x11iraf/obm/ObmW/cvtLong.c | 34 + vendor/x11iraf/obm/ObmW/done.h | 16 + vendor/x11iraf/obm/ObmW/iconutil.c | 297 + vendor/x11iraf/obm/ObmW/iconutil.c.ORIG | 279 + vendor/x11iraf/obm/ObmW/inkstore.h | 1844 +++ vendor/x11iraf/obm/ObmW/laygram.y | 263 + vendor/x11iraf/obm/ObmW/laylex.l | 126 + vendor/x11iraf/obm/ObmW/laylex.l.ORIG | 96 + vendor/x11iraf/obm/ObmW/scroll.c | 46 + vendor/x11iraf/obm/ObmW/scroll.h | 96 + vendor/x11iraf/obm/ObmW/stip4.bm | 4 + vendor/x11iraf/obm/ObmW/strnchr.c | 17 + vendor/x11iraf/obm/ObmW/zz/Separator.c | 357 + vendor/x11iraf/obm/ObmW/zz/Separator.h | 99 + vendor/x11iraf/obm/ObmW/zz/SeparatorP.h | 60 + vendor/x11iraf/obm/ObmW/zz/Simple.c | 489 + vendor/x11iraf/obm/ObmW/zz/Simple.h | 96 + vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h | 113 + vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c | 1467 +++ vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h | 169 + vendor/x11iraf/obm/ObmW/zz/SimpleP.h | 62 + vendor/x11iraf/obm/ObmW/zz/Table.c | 4529 +++++++ vendor/x11iraf/obm/ObmW/zz/Table.h | 539 + vendor/x11iraf/obm/ObmW/zz/Table3d.c | 924 ++ vendor/x11iraf/obm/ObmW/zz/Table3d.h | 145 + vendor/x11iraf/obm/ObmW/zz/TableP.h | 166 + vendor/x11iraf/obm/ObmW/zz/TableUtil.c | 918 ++ vendor/x11iraf/obm/ObmW/zz/TableUtil.h | 94 + vendor/x11iraf/obm/ObmW/zz/XrawInit.h | 60 + 281 files changed, 166840 insertions(+) create mode 100644 vendor/x11iraf/obm/ObmW/Arrow.c create mode 100644 vendor/x11iraf/obm/ObmW/Arrow.h create mode 100644 vendor/x11iraf/obm/ObmW/Arrow.man create mode 100644 vendor/x11iraf/obm/ObmW/ArrowP.h create mode 100644 vendor/x11iraf/obm/ObmW/Board.c create mode 100644 vendor/x11iraf/obm/ObmW/Board.h create mode 100644 vendor/x11iraf/obm/ObmW/Board.man create mode 100644 vendor/x11iraf/obm/ObmW/BoardP.h create mode 100644 vendor/x11iraf/obm/ObmW/Button.c create mode 100644 vendor/x11iraf/obm/ObmW/Button.h create mode 100644 vendor/x11iraf/obm/ObmW/Button.man create mode 100644 vendor/x11iraf/obm/ObmW/ButtonP.h create mode 100644 vendor/x11iraf/obm/ObmW/CHANGES create mode 100644 vendor/x11iraf/obm/ObmW/Common.c create mode 100644 vendor/x11iraf/obm/ObmW/Common.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/Common.h create mode 100644 vendor/x11iraf/obm/ObmW/Common.man create mode 100644 vendor/x11iraf/obm/ObmW/CommonP.h create mode 100644 vendor/x11iraf/obm/ObmW/Container.c create mode 100644 vendor/x11iraf/obm/ObmW/Container.h create mode 100644 vendor/x11iraf/obm/ObmW/ContainerP.h create mode 100644 vendor/x11iraf/obm/ObmW/Converters.h create mode 100644 vendor/x11iraf/obm/ObmW/DrawIString.c create mode 100644 vendor/x11iraf/obm/ObmW/DrawString.c create mode 100644 vendor/x11iraf/obm/ObmW/DrawingArea.c create mode 100644 vendor/x11iraf/obm/ObmW/DrawingArea.h create mode 100644 vendor/x11iraf/obm/ObmW/DrawingAreaP.h create mode 100755 vendor/x11iraf/obm/ObmW/FIXFWF create mode 100644 vendor/x11iraf/obm/ObmW/FWFSED create mode 100644 vendor/x11iraf/obm/ObmW/Frame.c create mode 100644 vendor/x11iraf/obm/ObmW/Frame.h create mode 100644 vendor/x11iraf/obm/ObmW/Frame.man create mode 100644 vendor/x11iraf/obm/ObmW/FrameP.h create mode 100644 vendor/x11iraf/obm/ObmW/Gcs.c create mode 100644 vendor/x11iraf/obm/ObmW/Gcs.h create mode 100644 vendor/x11iraf/obm/ObmW/Group.c create mode 100644 vendor/x11iraf/obm/ObmW/Group.h create mode 100644 vendor/x11iraf/obm/ObmW/Group.man create mode 100644 vendor/x11iraf/obm/ObmW/GroupP.h create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.092408/Gterm.h create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.092408/GtermP.h create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.c create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/Gterm.h create mode 100644 vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c create mode 100644 vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/Gterm1.5/Gterm.h create mode 100644 vendor/x11iraf/obm/ObmW/Gterm1.5/GtermP.h create mode 100644 vendor/x11iraf/obm/ObmW/GtermCmap.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermCnv.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermDebug.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermGraphics.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermImaging.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermMapping.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermMarker.c create mode 100644 vendor/x11iraf/obm/ObmW/GtermP.h create mode 100644 vendor/x11iraf/obm/ObmW/GtermUtil.c create mode 100644 vendor/x11iraf/obm/ObmW/HTML-PSformat.c create mode 100644 vendor/x11iraf/obm/ObmW/HTML.c create mode 100644 vendor/x11iraf/obm/ObmW/HTML.h create mode 100644 vendor/x11iraf/obm/ObmW/HTML.notes create mode 100644 vendor/x11iraf/obm/ObmW/HTMLP.h create mode 100644 vendor/x11iraf/obm/ObmW/HTMLamp.h create mode 100644 vendor/x11iraf/obm/ObmW/HTMLformat.c create mode 100644 vendor/x11iraf/obm/ObmW/HTMLimages.c create mode 100644 vendor/x11iraf/obm/ObmW/HTMLjot.c create mode 100644 vendor/x11iraf/obm/ObmW/HTMLlists.c create mode 100644 vendor/x11iraf/obm/ObmW/HTMLparse.c create mode 100644 vendor/x11iraf/obm/ObmW/HTMLwidgets.c create mode 100644 vendor/x11iraf/obm/ObmW/Icon.c create mode 100644 vendor/x11iraf/obm/ObmW/Icon.h create mode 100644 vendor/x11iraf/obm/ObmW/Icon.man create mode 100644 vendor/x11iraf/obm/ObmW/IconP.h create mode 100644 vendor/x11iraf/obm/ObmW/Imakefile create mode 100644 vendor/x11iraf/obm/ObmW/Label.c create mode 100644 vendor/x11iraf/obm/ObmW/Label.h create mode 100644 vendor/x11iraf/obm/ObmW/Label.man create mode 100644 vendor/x11iraf/obm/ObmW/LabelP.h create mode 100644 vendor/x11iraf/obm/ObmW/Layout.c create mode 100644 vendor/x11iraf/obm/ObmW/Layout.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/Layout.ex create mode 100644 vendor/x11iraf/obm/ObmW/Layout.h create mode 100644 vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip create mode 100644 vendor/x11iraf/obm/ObmW/LayoutP.h create mode 100644 vendor/x11iraf/obm/ObmW/ListTree.c create mode 100644 vendor/x11iraf/obm/ObmW/ListTree.h create mode 100644 vendor/x11iraf/obm/ObmW/ListTreeP.h create mode 100644 vendor/x11iraf/obm/ObmW/Makefile create mode 100644 vendor/x11iraf/obm/ObmW/MenuBar.c create mode 100644 vendor/x11iraf/obm/ObmW/MenuBar.h create mode 100644 vendor/x11iraf/obm/ObmW/MenuBar.man create mode 100644 vendor/x11iraf/obm/ObmW/MenuBarP.h create mode 100644 vendor/x11iraf/obm/ObmW/MultiList.c create mode 100644 vendor/x11iraf/obm/ObmW/MultiList.h create mode 100644 vendor/x11iraf/obm/ObmW/MultiList.man create mode 100644 vendor/x11iraf/obm/ObmW/MultiListP.h create mode 100644 vendor/x11iraf/obm/ObmW/Notes create mode 100644 vendor/x11iraf/obm/ObmW/README create mode 100644 vendor/x11iraf/obm/ObmW/RadioGrp.c create mode 100644 vendor/x11iraf/obm/ObmW/RadioGrp.h create mode 100644 vendor/x11iraf/obm/ObmW/RadioGrp.man create mode 100644 vendor/x11iraf/obm/ObmW/RadioGrpP.h create mode 100644 vendor/x11iraf/obm/ObmW/RowCol.c create mode 100644 vendor/x11iraf/obm/ObmW/RowCol.h create mode 100644 vendor/x11iraf/obm/ObmW/RowCol.man create mode 100644 vendor/x11iraf/obm/ObmW/RowColP.h create mode 100644 vendor/x11iraf/obm/ObmW/Scrollbar.c create mode 100644 vendor/x11iraf/obm/ObmW/Scrollbar.h create mode 100644 vendor/x11iraf/obm/ObmW/Scrollbar.man create mode 100644 vendor/x11iraf/obm/ObmW/ScrollbarP.h create mode 100644 vendor/x11iraf/obm/ObmW/Separator.c create mode 100644 vendor/x11iraf/obm/ObmW/Separator.h create mode 100644 vendor/x11iraf/obm/ObmW/SeparatorP.h create mode 100644 vendor/x11iraf/obm/ObmW/Simple.c create mode 100644 vendor/x11iraf/obm/ObmW/SimpleMenu.c create mode 100644 vendor/x11iraf/obm/ObmW/Slider2.c create mode 100644 vendor/x11iraf/obm/ObmW/Slider2.h create mode 100644 vendor/x11iraf/obm/ObmW/Slider2.man create mode 100644 vendor/x11iraf/obm/ObmW/Slider2P.h create mode 100644 vendor/x11iraf/obm/ObmW/TabString.h create mode 100644 vendor/x11iraf/obm/ObmW/Table.c create mode 100644 vendor/x11iraf/obm/ObmW/Table.h create mode 100644 vendor/x11iraf/obm/ObmW/Table3d.c create mode 100644 vendor/x11iraf/obm/ObmW/Table3d.h create mode 100644 vendor/x11iraf/obm/ObmW/TableP.h create mode 100644 vendor/x11iraf/obm/ObmW/TableUtil.c create mode 100644 vendor/x11iraf/obm/ObmW/TableUtil.h create mode 100644 vendor/x11iraf/obm/ObmW/Tablist2Tabs.c create mode 100644 vendor/x11iraf/obm/ObmW/Tabs.c create mode 100644 vendor/x11iraf/obm/ObmW/Tabs.h create mode 100644 vendor/x11iraf/obm/ObmW/TabsP.h create mode 100644 vendor/x11iraf/obm/ObmW/TextWidth.c create mode 100644 vendor/x11iraf/obm/ObmW/Toggle.c create mode 100644 vendor/x11iraf/obm/ObmW/Toggle.h create mode 100644 vendor/x11iraf/obm/ObmW/Toggle.man create mode 100644 vendor/x11iraf/obm/ObmW/ToggleP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/3d.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AllWidgets.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Arrow.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ArrowP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiSink.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiSinkP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiSrc.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiSrcP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiText.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/AsciiTextP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Box.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/BoxP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Cardinals.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Clock.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ClockP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Command.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/CommandP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Container.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ContainerP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Dialog.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/DialogP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Form.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/FormP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Frame.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/FrameP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Grip.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/GripP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Label.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/LabelP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/List.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ListP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Logo.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/LogoP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Mailbox.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/MailboxP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/MenuButtoP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/MenuButton.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Object.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Paned.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/PanedP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Panner.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/PannerP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Porthole.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/PortholeP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Repeater.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/RepeaterP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Reports.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Scrollbar.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ScrollbarP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ScrolledTable.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ScrolledTableP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Separator.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SeparatorP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Simple.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SimpleMenP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SimpleMenu.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SimpleP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Sme.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SmeBSB.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SmeBSBP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SmeLine.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SmeLineP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/SmeP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/StripCharP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/StripChart.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Table.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Table3d.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TableP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TableUtil.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Template.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TemplateP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Text.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TextP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TextSink.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TextSinkP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TextSrc.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TextSrcP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Toggle.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ToggleP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Tree.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/TreeP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Viewport.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/ViewportP.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/XawAll.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/XawInit.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/Xosdefs.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/XrawInit.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/color.h create mode 100644 vendor/x11iraf/obm/ObmW/Xraw/xraw_table.h create mode 100644 vendor/x11iraf/obm/ObmW/_c create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/AnchoredImage.xbm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/DelayedImage.xbm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/ERROR.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/FATAL.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/INFO.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/NONE.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/NoImage.xbm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/QUESTION.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/WARNING.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond0.pm.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond0m.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond0s.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond1.pm.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond1m.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/diamond1s.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square0.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square0m.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square0s.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square1.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square1m.pm create mode 100644 vendor/x11iraf/obm/ObmW/bitmaps/square1s.pm create mode 100644 vendor/x11iraf/obm/ObmW/color.c create mode 100644 vendor/x11iraf/obm/ObmW/cvtLong.c create mode 100644 vendor/x11iraf/obm/ObmW/done.h create mode 100644 vendor/x11iraf/obm/ObmW/iconutil.c create mode 100644 vendor/x11iraf/obm/ObmW/iconutil.c.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/inkstore.h create mode 100644 vendor/x11iraf/obm/ObmW/laygram.y create mode 100644 vendor/x11iraf/obm/ObmW/laylex.l create mode 100644 vendor/x11iraf/obm/ObmW/laylex.l.ORIG create mode 100644 vendor/x11iraf/obm/ObmW/scroll.c create mode 100644 vendor/x11iraf/obm/ObmW/scroll.h create mode 100644 vendor/x11iraf/obm/ObmW/stip4.bm create mode 100644 vendor/x11iraf/obm/ObmW/strnchr.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/Separator.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/Separator.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/SeparatorP.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/Simple.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/Simple.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/SimpleMenP.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/SimpleMenu.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/SimpleMenu.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/SimpleP.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/Table.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/Table.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/Table3d.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/Table3d.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/TableP.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/TableUtil.c create mode 100644 vendor/x11iraf/obm/ObmW/zz/TableUtil.h create mode 100644 vendor/x11iraf/obm/ObmW/zz/XrawInit.h (limited to 'vendor/x11iraf/obm/ObmW') 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 +#include +#include "stip4.bm" +#include +#include +#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[] = "\ +: activate_and_start_timer() \n\ +: 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 = 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 + 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 +: activate_and_start_timer() +.fi + +.nf +: 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 + +.fi + +.nf + +.B incl + +.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 +#include +#include +#include +#include +#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 = "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 = "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 = "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 = "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 = "1.0" +.fi + +.eh + +.TP +.I "XtNvunit" + +.hi + +.nf +float vunit = "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 + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.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 +#include +#include "ButtonP.h" +static void activate( +#if NeedFunctionPrototypes +Widget,XEvent*,String*,Cardinal* +#endif +); + +static XtActionsRec actionsList[] = { +{"activate", activate}, +}; + +static char defaultTranslations[] = "\ +: set_shadow(sunken) \n\ +,: activate() set_shadow() \n\ +Button1: set_shadow() \n\ +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 + 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 +: set_shadow(sunken) +.fi + +.nf +,: activate() set_shadow() +.fi + +.nf +Button1: set_shadow() +.fi + +.nf +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 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 +#include +#include +#include +#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()\n\ + : focusOut()\n\ + Up: traverseUp()\n\ + Down: traverseDown()\n\ + Left: traverseLeft()\n\ + Right: traverseRight()\n\ + Next: traverseNext()\n\ + ~ShiftTab: traverseNext()\n\ + Prior: traversePrev()\n\ + ShiftTab: traversePrev()\n\ + KP_Enter: traverseNextTop()\n\ + 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 +#include +#line 929 "Common.w" +#include +#line 930 "Common.w" +#include +#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()\n\ + : focusOut()\n\ + Up: traverseUp()\n\ + Down: traverseDown()\n\ + Left: traverseLeft()\n\ + Right: traverseRight()\n\ + Next: traverseNext()\n\ + ~ShiftTab: traverseNext()\n\ + Prior: traversePrev()\n\ + ShiftTab: traversePrev()\n\ + KP_Enter: traverseNextTop()\n\ + 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 +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 = 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 + 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 + 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 + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.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()\\n\\ + : focusOut()\\n\\ + Up: traverseUp()\\n\\ + Down: traverseDown()\\n\\ + Left: traverseLeft()\\n\\ + Right: traverseRight()\\n\\ + Next: traverseNext()\\n\\ + ~ShiftTab: traverseNext()\\n\\ + Prior: traversePrev()\\n\\ + ShiftTab: traversePrev()\\n\\ + KP_Enter: traverseNextTop()\\n\\ + 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 +#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 + +#include +#include +#include +#include +#include + + + +#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 + +/*********************************************************************** + * + * 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 +#include + +#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 + +/* 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 +#include +#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 +#include +#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 +#include + +/* +#include +#include +#include +*/ + +#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 */ +/*********************************************************************** + * + * 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 + +#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++"\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 +#include +#include +#include +#include +#include +#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 = compute_topcolor +.fi + +.eh + +.TP +.I "XtNbottomShadowColor" + +.hi + +.nf +Pixel bottomShadowColor = 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 + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.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 + +#include +#include +#include +#include +#include + +#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 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 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 +#include +#include "Toggle.h" +#include +#include +#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<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 + XFontStruct * font = XtDefaultFont +.fi + +.eh + +.TP +.I "XtNforeground" +The foreground color is the color used to draw the text. + + + +.hi + +.nf +Pixel foreground = 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 + 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 + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.fi + +.nf + +.B incl + +.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<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 +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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; igterm.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 +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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 +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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 +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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 +#include +#include + +#include +#include +#include +#include +#include +#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 : popup-menu(tekMenu) */ + +static char defaultGtermTranslations[] = +"\ + : m_create() \n\ + : crosshair(on) \n\ + : crosshair(on) \n\ + : crosshair(off) \n\ + : enter-window() \n\ + : leave-window() \n\ + : graphics-input() \n\ + : track-cursor() \n\ +"; + +/* Default translations when pointer is over a marker. */ +static char defaultMarkerTranslations[] = +"\ + !Shift : m_rotateResize() \n\ + : m_moveResize() \n\ + !Shift : m_raise() m_markpos() \n\ + : m_raise() m_markposAdd() \n\ + : m_redraw() m_destroyNull() \n\ + : m_lower() \n\ + BackSpace: m_deleteDestroy() \n\ + Delete: m_deleteDestroy() \n\ + : m_input() \n\ + : 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) >ermClassRec; +#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 %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 +#include +#include +#include +#include "HTMLP.h" + +#ifdef _GNU_SOURCE +#define USE_STDARG +#endif +#if defined(__APPLE__) || (__APPLE_CC__ > 1151) || defined(USE_STDARG) +#include +#else +#include + +/* 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 +#endif + + +/* Fix thanks to robm. */ +/* We don't have this on our system at NOAO... + * #ifdef __alpha + * #include + * #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; i10000.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: + | # 'run' of count+1 equal pixels + | # 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; i1) { + /* 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; jI 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>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; inum_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; ireds[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; ihtml.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 +#include "HTMLP.h" +#ifdef MOTIF +#include +#include +#else +#include "DrawingArea.h" +#include +#endif +#include + + +#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[] = +" \ +: select-start() ManagerGadgetArm()\n\ +: extend-adjust() ManagerGadgetButtonMotion()\n\ +: extend-end(PRIMARY, CUT_BUFFER0) ManagerGadgetActivate()\n\ +: select-start()\n\ +: extend-adjust()\n\ +: extend-end(PRIMARY, CUT_BUFFER0)\n\ +: extend-start()\n\ +: extend-adjust()\n\ +: extend-end(PRIMARY, CUT_BUFFER0) \n\ +f: scroll(1)\n\ +b: scroll(-1)\n\ +Prior: scroll(-1)\n\ +Next: scroll(1)\n\ +u: scroll(-0.5)\n\ +d: scroll(0.5)\n\ +Up: scroll(-0.5)\n\ +Down: scroll(0.5)\n\ +j: scroll(1ch)\n\ +k: scroll(-1ch)\n\ +: track-motion()\n\ +: track-motion()\n\ +: track-motion()\n\ +: track-motion()\ +"; +#else +static char defaultTranslations[] = +" \ +: select-start() \n\ +: extend-adjust() \n\ +: extend-end(PRIMARY, CUT_BUFFER0) \n\ +: select-start() \n\ +: extend-adjust() \n\ +: extend-end(PRIMARY, CUT_BUFFER0) \n\ +: extend-start()\n\ +: extend-adjust()\n\ +: extend-end(PRIMARY, CUT_BUFFER0) \n\ +f: scroll(1)\n\ +b: scroll(-1)\n\ +Prior: scroll(-1)\n\ +Next: scroll(1)\n\ +u: scroll(-0.5)\n\ +d: scroll(0.5)\n\ +Up: scroll(-0.5)\n\ +Down: scroll(0.5)\n\ +j: scroll(1ch)\n\ +k: scroll(-1ch)\n\ +: track-motion()\n\ +: track-motion()\n\ +: track-motion()\n\ +: 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; ihtml.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 + */ + 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 +/* + * 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\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 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; ihtml.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 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 +#if (XmVERSION == 1)&&(XmREVISION >= 2) +#define MOTIF1_2 +#endif +#else +#include +#include +#endif /* MOTIF */ +#include + + + +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 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 +# ifdef MOTIF1_2 +# include +# endif /* MOTIF1_2 */ +#else +#include +#include +#endif /* MOTIF */ + +#include +#include + +#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 +struct timeval Tv; +struct timezone Tz; +#endif + +#include +#include +#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

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

'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
'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, is the same as: + *
+ *
+ * This is a searchable index. Enter search keywords: + * + *
+ *
+ * Also, 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: "; 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: "." + */ + 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; iunderline_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; ihtml.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; itype == 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; itype == 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; itype == 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; itype == 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; itype == 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; itype == 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 +#include +#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; jhtml.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; ipixel; + for (i=0; ired) / 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> 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 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 +#include "inkstore.h" +#include "HTMLP.h" + +#include +#include + +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; istroke_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; istroke_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; istroke_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 +#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; iline_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 +struct timeval Tv; +struct timezone Tz; +#endif + +#include +#include +#ifndef sun +/* To get atoi. */ +#include +#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 "<" = "<", ">" = ">", + * "&" = "&" + * GAG: apperantly < 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 ;" = "<" 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 ''. 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 '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 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 Binary files /dev/null and b/vendor/x11iraf/obm/ObmW/Layout.ps.gz.mip 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_ */ -- cgit