greg@gergle.UUCP (07/24/88)
I always litter my screen with windows, and have to uncover my
clock to read it. I decided I was going to write a clock which would
be smart enough to keep itself visible. I thought it was going to be easy,
but I found no good way to find a free spot on the root canvas. I stooped
to traversing the canvas list, and doing rectangle list calculations
in PostScript. If anyone has a better way please let me know. I cringe
every time I see the clock change knowing what its doing. If there isn't
a better way, others may find the "findplace" routine below usefull.
-greg.
Bugs: This is not an accurate clock, because it relies on a sleep in the
shell script to feed the correct time to NeWS.
------------------------------------------------------------------------
#!/bin/sh
DATECOMMAND="date +%H:%M"
trap "echo systemdict /DigitalTime null put | psh;exit" 15 2
# Need to put a non null value in DigitalTime
echo "systemdict /DigitalTime (`$DATECOMMAND`) put" | psh
psh <<GIVETONEWS
{
/Height 64 def
/Width 0 def
/Xpos 10 def
/Ypos 10 def
/CX 100 def
/CY 100 def
/myfont /Times-Roman findfont Height scalefont def
/erase { Xpos Ypos Width Height rectpath
clipcanvas PaintRoot newpath clipcanvas
} def
myfont setfont
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The Following code up the next line of % finds the free spot on the
% root canvas
%
% Leave the rectangle of a Canvas on the stack.
%
/getcanvasrect { % canvas ==> array canvas
dup /Mapped get
{ dup getcanvaslocation [ 3 1 roll
gsave
3 index setcanvas
clippath pathbbox 4 -2 roll pop pop
grestore
] exch
} if
} def
%
% Get the Rectangles of all the Mapped&Opaque Canvases on the Display.
% Each is left in an array [x y w h] on the stack
%
/getcanvasrects { framebuffer /TopCanvas get getcanvasrect nextcanvas } def
/nextcanvas {
/CanvasBelow get dup null ne { getcanvasrect nextcanvas} { pop } ifelse
} def
%
% Find the largest rectangle unoccupied in the root canvas which will fit
% the given width & heigth. Return false if it does not exist.
%
/findplace { % w h ==> x y w h bool
/outrects [ getcanvasrects ] def
/inrects [[ clippath pathbbox ]] def
outrects { subtractfromall pause } forall
/maxarea -1 def
/keeper null def
inrects { /r exch def r 2 get 2 index gt
{ r 3 get 1 index gt
{ r 2 get r 3 get mul dup maxarea gt
{ /maxarea exch store /keeper r store }
{ pop }
ifelse
} if
} if
} forall
pause pop pop
keeper null eq
{ false }
{ keeper aload pop true}
ifelse
} def
%
% Subtract this rect from all the inrects.
%
/subtractfromall { % [x y w h] ==> -
/r exch def
/inrects [ inrects { subtractrect } forall ] def
} def
%
% Subtract rectangle r from the rectangle on the stack if it intersects
%
/subtractrect { % [x y w h] ==> 1-4 of [x y w h]
dup r hitrect
{ r mungerect } if
} def
%
% check if 2 rects intersect
%
/hitrect { % [x y w h] [x y w h] ==> bool
/r2 exch def /r1 exch def
r1 0 get r1 2 get add r2 0 get ge dup
{ pop r2 0 get r2 2 get add r1 0 get ge dup
{ pop r1 1 get r1 3 get add r2 1 get ge dup
{ pop r2 1 get r2 3 get add r1 1 get ge
} if
} if
} if
} def
%
% Subtract the top rectangle from the rectangle underneath
% Rectangles have already been tested, they must intersect.
%
/mungerect { % [x y w h] [x y w h ] ==> 1-4 of [x y w h]
/r2 exch def /r1 exch def
% left piece
r2 0 get r1 0 get sub dup 0 gt % w bool
{ r1 4 array copy dup 2 4 -1 roll put } % [x y w h]
{ pop }
ifelse
% right piece
r1 0 get r1 2 get add r2 0 get r2 2 get add sub dup 0 gt % w bool
{ [ r2 0 get r2 2 get add r1 1 get 4 -1 roll r1 3 get ] } % [x y w h]
{ pop }
ifelse
% bottom piece
r2 1 get r1 1 get sub dup 0 gt % h bool
{ r1 4 array copy dup 3 4 -1 roll put } % [x y w h]
{ pop }
ifelse
% top piece
r1 1 get r1 3 get add r2 1 get r2 3 get add sub dup 0 gt % h bool
{ [ r1 0 get r2 1 get r2 3 get add r1 2 get 5 -1 roll ] } % [x y w h]
{ pop }
ifelse
} def
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{
DigitalTime null ne
{
/NewWidth DigitalTime stringwidth pop 10 add def
NewWidth Height findplace
{ 2 div 3 -1 roll add 3 1 roll 2 div add % cy cx
dup CX ne 2 index CY ne or % cy cy bool have we moved
{ erase } if
/CX exch store /CY exch store
} if
/Width NewWidth store
/Xpos CX Width 2 div sub def
/Ypos CY Height 2 div sub def
Xpos Ypos Width Height dup 4 div
5 1 roll rrectpath
0 setgray fill 1 setgray
Xpos 5 add Ypos 10 add moveto
DigitalTime show
}
{ erase quit } ifelse
.5 sleep
} loop
} fork
GIVETONEWS
while true
do
echo "systemdict /DigitalTime (`$DATECOMMAND`) put" | psh
sleep 55
done