XTkBitmapWidgetsImpl.mesa
Copyright Ó 1988, 1989, 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Christian Jacobi, October 21, 1988 1:13:59 pm PDT
Christian Jacobi, August 16, 1993 2:11 pm PDT
DIRECTORY
ForkOps,
Imager,
ImagerSample,
Process,
Rope,
SF,
Xl,
XlBitmap,
XlBWFriends,
XlColorAccess,
XlDetails,
XlShmPixmaps,
XTk,
XTkFriends,
XTkBitmapWidgets,
XTkBitmapWidgetsExtras,
XTkShellWidgets;
XTkBitmapWidgetsImpl: CEDAR MONITOR
LOCKS bmRef USING bmRef: REF BMRec
IMPORTS ForkOps, ImagerSample, Process, Rope, SF, Xl, XlBitmap, XlBWFriends, XlColorAccess, XlDetails, XlShmPixmaps, XTk, XTkFriends, XTkShellWidgets
EXPORTS XTkBitmapWidgets, XTkBitmapWidgetsExtras
SHARES XlBWFriends =
BEGIN OPEN Xl, XTk, XTkBitmapWidgets;
bmClass: ImplementorClass ¬ XTkFriends.CreateClass[[
key: $bitmapWidget, wDataNum: 1,
configureLR: BMConfigureLR,
destroyWindowLR: BMDestroyWindowLR,
preStopFastAccess: BMPreStopFastAccess,
fullStopFastAccessLR: BMFullStopFastAccessLR,
destroyWidget: BMDestroyWidget,
initInstPart: InitInstPart,
eventMask: [exposure: TRUE, structureNotify: TRUE],
backgroundKey: $white
]];
BMRec: TYPE = MONITORED RECORD [
wAsUsed: XlBWFriends.WRef ¬ NIL,
wInternal: XlBWFriends.WRef ¬ NIL,
bm: XlBitmap.Bitmap ¬ NIL,
origin: Xl.Point ¬ [0, 0],
restrict: SF.Box ¬ SF.maxBox,
notify: BitmapEventProc,
mapped: BOOL ¬ FALSE,
data: REF ¬ NIL,
ownedBitmap: XlBitmap.Bitmap ¬ NIL,
--window relative
support8: BOOL ¬ FALSE,
support4: BOOL ¬ FALSE,
support2: BOOL ¬ FALSE,
shmData: REF ShmData ¬ NIL,
gc: Xl.GContext
];
ShmData: TYPE = RECORD [
shmPixmap: Xl.Pixmap ¬ Xl.nullPixmap,
c: Xl.Connection ¬ NIL,
bm: XlBitmap.Bitmap ¬ NIL
];
noErrors: Xl.Details ~ XlDetails.ignoreErrors;
NoOp: Xl.EventProcType ~ {};
mPadNoErrors: Xl.Details ~ NEW[Xl.DetailsRec ¬ [
errorMatch: NEW[Xl.MatchRep ¬ [proc: NoOp]],
specific: $ZPixmap
]];
MPadBugActualPaint1: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 1;
dirtyFix: INT ¬ b.min.f MOD 32;
IF w.offset.x+b.min.f<dirtyFix THEN {
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - 32;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: mPadNoErrors];
};
IBMBugActualPaint1: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 1;
dirtyFix: INT ¬ b.min.f MOD 32;
IF w.offset.x+b.min.f<dirtyFix THEN {
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - 32;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ActualPaint1: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 1;
dirtyFix: INT ~ 0;
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ActualPaint2: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 2;
modulus: INT ~ 32 / bpp; --Oops, this line knows unit size is 32...
dirtyFix: INT ¬ b.min.f MOD modulus;
--X protocol says left-pad must be 0 for zPixmap format
IF w.offset.x+b.min.f<dirtyFix THEN {
--Horrible case of unfriendly alignments
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - modulus;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ActualPaint4: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 4;
modulus: INT ~ 32 / bpp; --Oops, this line knows unit size is 32...
dirtyFix: INT ¬ b.min.f MOD modulus;
--X protocol says left-pad must be 0 for zPixmap format
IF w.offset.x+b.min.f<dirtyFix THEN {
--Horrible case of unfriendly alignments
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - modulus;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ActualPaint8: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 8;
modulus: INT ~ 32 / bpp; --Oops, this line knows unit size is 32...
dirtyFix: INT ¬ b.min.f MOD modulus;
--X protocol says left-pad must be 0 for zPixmap format
IF w.offset.x+b.min.f<dirtyFix THEN {
--Horrible case of unfriendly alignments
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - modulus;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ActualPaint24: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
bpp: INT ~ 24;
dirtyFix: INT ¬ b.min.f MOD 3;
--X protocol says left-pad must be 0 for zPixmap format
--Oops, this line knows unit size is 32...
IF w.offset.x+b.min.f<dirtyFix THEN {
--Horrible case of unfriendly alignments
--Prevent raising an error on negative dest.x.
--However, some pixels will be missing
dirtyFix ¬ dirtyFix - 3;
};
Xl.PutImage[c: w.c, drawable: w.d, gc: w.gc,
base: w.base,
dest: [w.offset.x+b.min.f-dirtyFix, w.offset.y+b.min.s],
size: [b.max.f-b.min.f+dirtyFix, b.max.s-b.min.s],
offx: b.min.f-dirtyFix, offy: b.min.s,
scanLineBytes: w.scanLineBytes, bitsPerPixel: bpp, details: noErrors];
};
ShmPaintCopyPlane: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
Xl.CopyPlane[c: w.c, src: w.sharedD, dst: w.d,
srcP: [b.min.f, b.min.s],
dstP: [w.offset.x+b.min.f, w.offset.y+b.min.s],
size: [b.max.f-b.min.f, b.max.s-b.min.s],
gc: w.gc, bitPlane: 1, details: noErrors]
};
ShmPaintCopyArea: PROC[b: SF.Box, ref: REF] = {
w: XlBWFriends.WRef ~ NARROW[ref];
Xl.CopyArea[c: w.c, src: w.sharedD, dst: w.d,
srcP: [b.min.f, b.min.s],
dstP: [w.offset.x+b.min.f, w.offset.y+b.min.s],
size: [b.max.f-b.min.f, b.max.s-b.min.s],
gc: w.gc, details: noErrors]
};
GetInstData: PROC [w: Widget] RETURNS [REF BMRec] = INLINE {
RETURN [NARROW[XTkFriends.InstPart[w, bmClass]]];
};
eventFilter: Xl.EventFilter = Xl.CreateEventFilter[unmapNotify, mapNotify, expose];
EventHandler: Xl.EventProcType = {
widget: Widget ~ NARROW[clientData];
bmRef: REF BMRec ~ GetInstData[widget];
IF bmRef.notify#NIL THEN {
SELECT event.type FROM
mapNotify => {
bmRef.mapped ¬ TRUE;
SetBM[bmRef, widget, FALSE, FALSE];
bmRef.notify[widget, map, bmRef.data];
};
unmapNotify => {
bmRef.mapped ¬ FALSE;
Stop[bmRef];
bmRef.notify[widget, unmap, bmRef.data];
};
expose => {
e: Xl.ExposeEvent ~ NARROW[event];
s: XlBWFriends.SRef;
w: XlBWFriends.WRef ~ bmRef.wAsUsed;
IF w=NIL OR (s ¬ w.s)=NIL THEN RETURN;
XlBWFriends.IncludeRect[s, w, [
min: [s: e.pos.y-w.offset.y, f: e.pos.x-w.offset.x],
max: [s: e.pos.y+e.size.height-w.offset.y, f: e.pos.x+e.size.width-w.offset.x]
], e.count#0];
};
ENDCASE => {};
};
};
FreeShmData: PROC [x: REF] = {
WITH x SELECT FROM
sd: REF ShmData => {
pm: Xl.Pixmap ¬ sd.shmPixmap;
sd.shmPixmap ¬ Xl.nullPixmap;
IF Xl.Alive[sd.c] AND pm#Xl.nullPixmap THEN Xl.FreePixmap[sd.c, pm, noErrors];
};
ENDCASE => {}
};
DelayedDestroyShmData: PROC [sd: REF ShmData] = {
--Because we do not stop the painters immediately
--Very short delay so bitmap will be finalized soon
IF sd#NIL THEN ForkOps.ForkDelayed[100, FreeShmData, sd]
};
BMDestroyWindowLR: TerminateProc = {
bmRef: REF BMRec ~ GetInstData[widget];
sd: REF ShmData ~ bmRef.shmData;
bmRef.shmData ¬ NIL;
IF bmRef.notify#NIL THEN bmRef.notify[widget, destroyWindow, bmRef.data];
XTkFriends.SimpleDestroyWindowLR[widget, reason];
Stop[bmRef];
IF sd#NIL THEN DelayedDestroyShmData[sd];
};
BMConfigureLR: ConfigureProc = {
bmRef: REF BMRec ~ GetInstData[widget];
existW, createW: BOOL;
reason: BitmapEventReason ¬ resize;
existW ¬ widget.actualMapping<unconfigured;
createW ¬ mapping<unconfigured AND ~existW;
IF createW THEN {
XTk.AddTemporaryMatch[widget, [EventHandler, eventFilter, widget.rootTQ, widget], [exposure: TRUE]];
};
XTkFriends.SimpleConfigureOneLevelLR[widget, geometry, mapping];
IF existW OR createW THEN {
IF createW THEN {
sd: Xl.ScreenDepth ¬ widget.screenDepth;
ownBM: XlBitmap.Bitmap ¬ bmRef.ownedBitmap;
bmRef.gc ¬ MakeGC[widget];
bmRef.mapped ¬ FALSE;
reason ¬ createWindow;
IF sd#NIL
THEN {
bmRef.support8 ¬ XlColorAccess.FindVisualType[sd.screen, 8, Xl.VisualClass.pseudoColor]#NIL;
bmRef.support4 ¬ XlColorAccess.FindVisualType[sd.screen, 4, Xl.VisualClass.pseudoColor]#NIL;
bmRef.support2 ¬ XlColorAccess.FindVisualType[sd.screen, 2, Xl.VisualClass.pseudoColor]#NIL;
IF ownBM#NIL AND (bmRef.support8 OR bmRef.support4 OR bmRef.support2) THEN FollowColorsOnce[widget, ownBM];
}
ELSE {
bmRef.support8 ¬ bmRef.support4 ¬ bmRef.support2 ¬ FALSE;
};
};
SetBM[bmRef, widget, FALSE, TRUE];
IF bmRef.notify#NIL THEN bmRef.notify[widget, reason, bmRef.data];
};
};
Set: PROC [bmRef: REF BMRec, h: XlBWFriends.WRef] = {
Swap: ENTRY PROC [bmRef: REF BMRec, new: XlBWFriends.WRef] RETURNS [old: XlBWFriends.WRef] = {
old ¬ bmRef.wAsUsed;
IF old=new THEN old ¬ NIL;
bmRef.wAsUsed ¬ new;
};
old: XlBWFriends.WRef ¬ Swap[bmRef, h];
IF old#NIL THEN XlBWFriends.StopWRef[old];
};
Stop: PROC [bmRef: REF BMRec] = {
Nillout: ENTRY PROC [bmRef: REF BMRec] RETURNS [old: XlBWFriends.WRef] = {
old ¬ bmRef.wAsUsed;
bmRef.wAsUsed ¬ NIL;
};
old: XlBWFriends.WRef ¬ Nillout[bmRef];
IF old#NIL THEN XlBWFriends.StopWRef[old];
};
BMPreStopFastAccess: TerminateProc = {
bmRef: REF BMRec ~ GetInstData[widget];
Stop[bmRef];
};
BMFullStopFastAccessLR: FullStopFastAccessProc = {
bmRef: REF BMRec ~ GetInstData[widget];
Stop[bmRef];
IF bmRef.notify#NIL THEN bmRef.notify[widget, destroyWindow, bmRef.data];
};
BMDestroyWidget: WidgetProc = {
bmRef: REF BMRec ~ GetInstData[widget];
Stop[bmRef];
};
NullNotify: BitmapEventProc = {};
InitInstPart: InitInstancePartProc = {
XTkFriends.AssignInstPart[widget, bmClass, NEW[BMRec ¬ [notify: NullNotify, wAsUsed: NIL]]];
XTk.SetWidgetFlag[widget, XTk.preferredSizeCurrent, TRUE];
};
DontNotify: BitmapEventProc = {};
SetCallbacks: PUBLIC PROC [bmw: BitmapWidget, notify: BitmapEventProc ¬ NIL, data: REF ¬ NIL] = {
bmRef: REF BMRec ~ GetInstData[bmw];
IF notify=NIL THEN notify ¬ DontNotify;
bmRef.notify ¬ notify;
bmRef.data ¬ data;
};
varyingFlag: XTk.WidgetFlagKey ~ wf6;
CreateBitmapWidget: PUBLIC PROC [widgetSpec: WidgetSpec, notify: BitmapEventProc, data: REF] RETURNS [widget: Widget] = {
widget ¬ XTk.CreateWidget[widgetSpec, bmClass];
XTk.SetWidgetFlag[widget, varyingFlag];
SetCallbacks[widget, notify, data];
};
SetBitmap: PUBLIC PROC [widget: BitmapWidget, bitmap: XlBitmap.Bitmap, restrict: SF.Box ¬ SF.maxBox, origin: Xl.Point ¬ [0, 0], immediateRefresh: BOOL ¬ TRUE, retainRefreshs: BOOL ¬ FALSE] = {
bmRef: REF BMRec ~ GetInstData[widget];
bmRef.bm ¬ bitmap;
bmRef.restrict ¬ SF.Intersect[restrict, XlBitmap.GetBox[bitmap]];
bmRef.origin ¬ origin;
IF widget.state=realized THEN
SetBM[bmRef, widget, immediateRefresh, retainRefreshs];
};
GetBitmap: PUBLIC PROC [widget: BitmapWidget] RETURNS [bitmap: XlBitmap.Bitmap, restrict: SF.Box, origin: Xl.Point] = {
bmRef: REF BMRec ~ GetInstData[widget];
bitmap ¬ bmRef.bm;
restrict ¬ bmRef.restrict;
origin ¬ bmRef.origin;
};
MakeGC: PROC [widget: XTk.Widget] RETURNS [Xl.GContext] = {
vendor: Rope.ROPE ¬ Xl.Info[widget.connection].vendor;
screen: Xl.Screen ~ widget.screenDepth.screen;
gc: Xl.GContext ~ Xl.MakeGContext[widget.connection, widget.window.drawable];
Xl.SetGCGraphicsExposures[gc, FALSE];
IF Rope.Equal[vendor, "Xerox Split MPAD"] THEN {
IF screen.blackPixel=0 THEN {
In bitmap format 1 delivers foreGround; compensate for zPixmap format
Xl.SetGCFunction[gc, copyInverted];
RETURN [gc]
};
};
Xl.SetGCFunction[gc, copy];
Xl.SetGCGrounds[gc: gc, foreground: screen.blackPixel, background: screen.whitePixel];
RETURN [gc]
};
SetBM: PROC [bmRef: REF BMRec, widget: BitmapWidget, immediateRefresh: BOOL, retainRefreshs: BOOL] = {
Range: PROC [x: INT] RETURNS [INTEGER] = {
RETURN[ MIN[ MAX[x, FIRST[INTEGER]], LAST[INTEGER] ] ]
};
vendor: Rope.ROPE;
bm: XlBitmap.Bitmap ¬ bmRef.bm;
IF bm=NIL OR widget.state#realized THEN Stop[bmRef]
ELSE {
sd: REF ShmData;
shmP: Xl.Pixmap ¬ Xl.nullPixmap;
rsm: ImagerSample.RasterSampleMap ¬ NARROW[XlBitmap.GetSM[bm]];
paintProc: PROC[b: SF.Box, ref: REF];
currentCase: Rope.ROPE ¬ NIL;
w: XlBWFriends.WRef;
origin: Xl.Point ¬ bmRef.origin;
clip: SF.Box ¬ [
min: [s: Range[-origin.y], f: Range[-origin.x]],
max: [s: Range[widget.actual.size.height-origin.y], f: Range[widget.actual.size.width-origin.x]]
];
restrict: SF.Box ¬ SF.Intersect[bmRef.restrict, clip];
bpp: NAT ¬ ImagerSample.GetBitsPerSample[XlBitmap.GetSM[bm]];
SELECT bpp FROM
1 => NULL; --always works
8 => IF ~bmRef.support8 THEN RETURN; --it wouldn't work
4 => IF ~bmRef.support4 THEN RETURN; --it wouldn't work
2 => IF ~bmRef.support2 THEN RETURN; --it wouldn't work
ENDCASE => {
--No test yet developped;
--Take your chance that it works or crashes
};
Stop[bmRef];
w ¬ NEW[XlBWFriends.WRec];
w.c ¬ widget.connection;
w.d ¬ widget.window;
w.bm ¬ bm;
w.base ¬ LOOPHOLE[ImagerSample.GetBase[rsm].word];
w.offset ¬ origin;
sd ¬ bmRef.shmData;
IF sd#NIL AND sd.c=w.c AND sd.bm=bm AND sd.shmPixmap#Xl.nullPixmap
THEN shmP ¬ sd.shmPixmap --reuse it
ELSE {
IF XlShmPixmaps.ConnectionSupportsPixmaps[w.c] AND XlShmPixmaps.SampleMapSupportsThis[rsm] THEN {
shmP ¬ XlShmPixmaps.UnsafeCreatePixmap[c: w.c, drawable: w.d, sm: rsm !
Xl.XError => {
--we wrongly believed shared memory would work
shmP ¬ Xl.nullPixmap;
CONTINUE
}
];
IF shmP=Xl.nullPixmap
THEN bmRef.shmData ¬ NIL
ELSE bmRef.shmData ¬ NEW[ShmData ¬ [shmPixmap: shmP, c: w.c, bm: bm]];
IF sd#NIL THEN DelayedDestroyShmData[sd];
};
};
w.clip ¬ SF.Intersect[clip, SF.Intersect[pseudoInfinitBox, XlBitmap.GetBox[bm]]];
w.scanLineBytes ¬ ImagerSample.GetBitsPerLine[rsm]/8;
w.gc ¬ bmRef.gc;
IF shmP=Xl.nullPixmap
THEN {
--overhead cost compensates for transferring request overhead (PutImage=6 words)
--it is scaled to compensate for cost function strictly assuming 8 bits per pixel
--is sligtly increased for a wild guess of per request overhead
SELECT ImagerSample.GetBitsPerSample[rsm] FROM
1 => {
IF widget.screenDepth.depth=4
THEN {paintProc ¬ IBMBugActualPaint1; currentCase ¬ "ibm 6000 bug fix"}
ELSE {paintProc ¬ ActualPaint1; currentCase ¬ "1 bpp, remote"};
w.overheadCost ¬ 48+40
};
8 => {
paintProc ¬ ActualPaint8; w.overheadCost ¬ 6+10;
currentCase ¬ "8 bpp, remote";
};
2 => {
paintProc ¬ ActualPaint2; w.overheadCost ¬ 24+20;
currentCase ¬ "2 bpp, remote";
};
4 => {
paintProc ¬ ActualPaint4; w.overheadCost ¬ 12+20;
currentCase ¬ "4 bpp, remote";
};
24 => {
paintProc ¬ ActualPaint24; w.overheadCost ¬ 0+4;
currentCase ¬ "24 bpp, remote";
};
ENDCASE => {RETURN};
}
ELSE {
w.sharedD ¬ shmP;
--overhead is wild guess on how much unification is justified
IF ImagerSample.GetBitsPerSample[rsm]=1
THEN {
paintProc ¬ ShmPaintCopyPlane; w.overheadCost ¬ 40000;
currentCase ¬ "1 bpp, shm";
}
ELSE {
paintProc ¬ ShmPaintCopyArea; w.overheadCost ¬ 20000;
currentCase ¬ "multi bpp, shm";
}
};
vendor ¬ Xl.Info[w.c].vendor;
IF Rope.Equal[vendor, "Xerox Split MPAD"] THEN {
--This server uses slow radio communication in spite of possible presence of shared memory
w.overheadCost ¬ 2;
w.serverQueueLimit ¬ 10;
paintProc ¬ MPadBugActualPaint1;
currentCase ¬ Rope.Concat[currentCase, " MPAD"];
};
--for experimenting to find out reasonable overheadCost
WITH XTk.GetWidgetProp[widget, $OverheadCost] SELECT FROM
ri: REF INT => {
w.overheadCost ¬ ri­;
WITH XTk.GetWidgetProp[widget, $ServerQueueLimit] SELECT FROM
ri: REF INT => w.serverQueueLimit ¬ ri­;
ENDCASE => {};
};
ENDCASE => {};
w.report ¬ LIST[[paintProc, w]];
XTk.PutWidgetProp[widget, $XTkBitmapWidgetsImpl, currentCase];
bmRef.wInternal ¬ w;
IF bmRef.mapped THEN {
XlBWFriends.StartWRef[w];
Set[bmRef, w];
ClearOutsideAreas[widget];
IF immediateRefresh OR retainRefreshs THEN
XlBWFriends.IncludeRect[w.s, w, clip, FALSE];
};
}
};
ClearOutsideAreas: PROC [w: XTk.Widget] = {
ENABLE ANY => GOTO Oops;
Clear: PROC [pos: Point, size: Size] = {
Xl.ClearArea[c, win, pos, size, FALSE, noErrors];
};
Fill: PROC [pos: Point, size: Size] = {
Xl.FillRectangle[c, win, bmRef.gc, pos, size, noErrors];
};
infinite: INT = 9999;
bmRef: REF BMRec ~ GetInstData[w];
c: Xl.Connection ¬ w.connection;
win: Xl.Window ¬ w.window;
r: SF.Box ¬ SF.Displace[bmRef.restrict, [bmRef.origin.y, bmRef.origin.x]];
IF win=Xl.nullWindow OR w.fastAccessAllowed#ok THEN RETURN;
--remember: paints [0, 0] of bitmap at point "origin" in window
--clear left half space
IF r.min.f>0 THEN Clear[[0, 0], [r.min.f, infinite]];
--clear direct upper and upper right quarter space
IF r.min.s>0 THEN Clear[[r.min.f, 0], [infinite, r.min.s]];
--clear direct right and right lower quarter space
Clear[[r.max.f, 0], [infinite, infinite]];
--clear direct under and right lower quarter space
Clear[[0, r.max.s], [infinite, infinite]];
IF XTk.GetWidgetProp[w, $BitmapBorder]#NIL THEN {
<<left>> Fill[[r.min.f-1, r.min.s-1], [1, r.max.s-r.min.s+2]];
<<right>> Fill[[r.max.f, r.min.s-1], [1, r.max.s-r.min.s+2]];
<<top>> Fill[[r.min.f-1, r.min.s-1], [r.max.f-r.min.f+2, 1]];
<<bottom>> Fill[[r.min.f-1, r.max.s], [r.max.f-r.min.f+2, 1]];
};
EXITS Oops => {};
};
pseudoInfinitBox: SF.Box ~ [min: [-8000, -8000], max: [8000, 8000]]; --artificial clip region used to prevent arithmetic overflow
GetImplData: PUBLIC PROC [widget: BitmapWidget] RETURNS [REF] = {
bmRef: REF BMRec ~ GetInstData[widget];
RETURN [bmRef.wAsUsed];
};
Wait: PUBLIC PROC [widget: BitmapWidget, server: BOOL ¬ FALSE] = {
bmRef: REF BMRec ~ GetInstData[widget];
w: XlBWFriends.WRef ¬ bmRef.wAsUsed;
IF w#NIL
THEN {
timedOut: BOOL ¬ XlBWFriends.WaitLocal[w.s, w].timedOut;
IF timedOut AND server THEN {
WHILE XlBWFriends.WaitLocal[w.s, w].timedOut DO ENDLOOP;
};
IF server AND Xl.Alive[w.c] THEN Xl.RoundTrip[w.c];
}
ELSE Process.Yield[];
};
noWhereBM: XlBitmap.Bitmap ~ XlBitmap.Create[[1, 1], 1, FALSE];
CreateContext: PUBLIC PROC [widget: BitmapWidget, surfaceUnitsPerPixel: NAT ¬ 1] RETURNS [context: Imager.Context] = {
bmRef: REF BMRec ~ GetInstData[widget];
bm: XlBitmap.Bitmap ¬ bmRef.bm;
IF bm=NIL THEN bm ¬ noWhereBM;
context ¬ XlBitmap.CreateContext[bm, surfaceUnitsPerPixel];
};
CreateAndSetBitmap: PUBLIC PROC [widget: BitmapWidget, size: SF.Vec, bpp: NAT ¬ 1, origin: Xl.Point ¬ [0, 0]] = {
bmRef: REF BMRec ~ GetInstData[widget];
bm: XlBitmap.Bitmap;
IF bpp=0 AND widget.screenDepth#NIL THEN {
IF XlColorAccess.FindVisualType[widget.screenDepth.screen, 8, Xl.VisualClass.pseudoColor]#NIL THEN bpp ¬ 8
ELSE IF XlColorAccess.FindVisualType[widget.screenDepth.screen, 4, Xl.VisualClass.pseudoColor]#NIL THEN bpp ¬ 4
ELSE bpp ¬ 1;
};
IF bpp=0 THEN bpp ¬ 1;
bm ¬ XlBitmap.Create[size, bpp];
SetBitmap[widget: widget, bitmap: bm, origin: origin];
FollowColors[widget, bm];
};
FollowColors: PUBLIC PROC [widget: XTk.Widget, bitmap: XlBitmap.Bitmap] = {
bmRef: REF BMRec ~ GetInstData[widget];
bmRef.ownedBitmap ¬ bitmap;
FollowColorsOnce[widget, bitmap];
};
FollowColorsOnce: PUBLIC PROC [widget: XTk.Widget, bitmap: XlBitmap.Bitmap] = {
screenDepth: Xl.ScreenDepth ¬ widget.screenDepth;
IF bitmap#NIL AND screenDepth#NIL THEN {
sm: ImagerSample.RasterSampleMap ~ XlBitmap.GetSM[bitmap];
bbp: NAT ¬ ImagerSample.GetBitsPerSample[sm];
IF bbp>1 THEN {
cd: XlColorAccess.ColorData ¬ XlColorAccess.Access[screenDepth.screen, bbp, Xl.VisualClass.pseudoColor];
IF cd#NIL AND cd.hasColors THEN {
XlBitmap.SetColormap[bitmap, cd.entries];
IF cd.hasPrivateColormap AND widget.attributes.colorMap#cd.colormap AND widget.fastAccessAllowed=ok THEN {
attributes: Xl.Attributes ¬ [];
widget.attributes.colorMap ¬ attributes.colorMap ¬ cd.colormap;
XlBitmap.SetColormap[bitmap, cd.entries];
XTkShellWidgets.TrackColorMap[shell: NIL, w: widget];
Xl.ChangeWindowAttributes[widget.connection, widget.window, attributes, noErrors];
};
};
};
};
};
END.