WindowManagerImpl.mesa
Copyright © 1982, 1983, 1984 Xerox Corporation. All rights reserved.
Edited by McGregor on December 14, 1982 10:55 am
Last Edited by: Maxwell, February 8, 1983 3:58 pm
Last Edited by: Paul Rovner, June 15, 1983 6:15 pm
Doug Wyatt, September 5, 1984 3:06:55 pm PDT
DIRECTORY
Carets USING [ResumeCarets, SuspendCarets],
ColorWorld USING [TurnOffColor, TurnOnColor],
Cursors USING [CursorType, GetCursor, SetCursor],
Imager USING [black, ClipRectangleI, Color, Context, MaskRectangle, MaskRectangleI, SetColor, white],
ImagerOps USING [Color, ColorFromStipple, GraphicsFromImager],
InputFocus USING [CaptureButtons, inputEnabled, ReleaseButtons, WindowManagerTIPTable],
Interminal USING [terminal],
InterminalExtra USING [InsertAction],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuEntry, MenuProc, ReplaceMenuEntry, SetGuarded],
MenusPrivate USING [ClearMenu, DrawMenu, HitMenu, MarkMenu],
MessageWindow USING [Append, Blink],
PrincOpsUtils USING [IsBound],
Terminal USING [BlinkBWDisplay],
TIPUser USING [TIPScreenCoords, TIPScreenCoordsRec],
ViewerClasses USING [Column, ScrollOp, Viewer],
ViewerExtras USING [PaintWindow],
ViewerMenus USING [Adjust, Close, Color, Destroy, Grow, Left, Right],
ViewerOps USING [ChangeColumn, CloseViewer, EnumerateViewers, EnumProc, InitialiseColorPainting, MouseInViewer, PaintViewer, TopViewer],
ViewerSpecs USING [captionHeight, scrollBarW, windowBorderSize],
WindowManager USING [ScreenPos],
WindowManagerPrivate USING [];
WindowManagerImpl: CEDAR MONITOR
IMPORTS Carets, ColorWorld, Cursors, Imager, ImagerOps, InputFocus, Interminal, InterminalExtra, Menus, MenusPrivate, MessageWindow, PrincOpsUtils, ViewerExtras, ViewerMenus, ViewerOps, Terminal
EXPORTS WindowManager, WindowManagerPrivate
SHARES InputFocus, Menus, ViewerClasses, ViewerOps
= BEGIN OPEN Cursors, ViewerClasses, ViewerSpecs;
Zone: TYPE = {none, menu, scroll, caption, client};
trackingState: Zone ← none;
CursorZone:
PROC [v: Viewer, mousePos: TIPUser.TIPScreenCoords]
RETURNS [z: Zone] =
{ OPEN v;
RETURN[
SELECT
TRUE
FROM
parent=NIL AND column#static AND mousePos.mouseY IN [wh-captionHeight..wh] => caption,
scrollable AND mousePos.mouseX IN [0..scrollBarW] AND mousePos.mouseY IN [0..ch] => scroll,
menu#NIL AND mousePos.mouseY IN ((cy-wy)+ch..wh-captionHeight) => menu,
};
ProcessWindowResults:
PUBLIC
PROC [self: Viewer, input:
LIST
OF
REF
ANY] = {
not monitored since notifier is synchronous
zone: Zone;
newZone: BOOL;
shift, control: BOOL ← FALSE;
mousePos: TIPUser.TIPScreenCoords;
FOR l: LIST OF REF ANY ← input, l.rest UNTIL l = NIL DO WITH l.first SELECT FROM
z: ATOM => { OPEN InputFocus;
IF newZone
THEN
SELECT trackingState
FROM
-- old feedback
scroll => {ReleaseButtons[]; RemoveScrollFeedback[]};
menu => {ReleaseButtons[]; MenusPrivate.ClearMenu[feedbackViewer.menu,
feedbackViewer]; feedbackViewer ← NIL};
caption => {ReleaseButtons[]; RemoveCaptionFeedback[]};
ENDCASE;
IF newZone
THEN
SELECT zone
FROM
-- first time stuff
scroll => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable,
self];
PostScrollFeedback[self]};
menu => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable,
self];
feedbackViewer ← self;
SetC[bullseye]};
caption => {CaptureButtons[ProcessWindowResults, WindowManagerTIPTable,
self];
PostCaptionFeedback[self];
SetC[bullseye]};
ENDCASE => SetC[textPointer];
SELECT trackingState ← zone
FROM
-- zone specific ops
scroll =>
SELECT z
FROM
$M => SetC[scrollUpDown];
$RU => HitScroll[self, mousePos.mouseY, up, shift, control];
$RD, $RM => SetC[scrollUp];
$YU => HitScroll[self, mousePos.mouseY, thumb, shift, control];
$YD, $YM => SetC[scrollRight];
$BU => HitScroll[self, mousePos.mouseY, down, shift, control];
$BD, $BM => SetC[scrollDown];
$Control => control ← TRUE;
$Shift => shift ← TRUE;
ENDCASE => NULL;
menu =>
SELECT z
FROM
$RU => MenusPrivate.HitMenu[self.menu,
self, mousePos, red, shift, control];
$BU => MenusPrivate.HitMenu[self.menu,
self, mousePos, blue, shift, control];
$YU => MenusPrivate.HitMenu[self.menu,
self, mousePos, yellow, shift, control];
$RM, $BM, $YM
=> {MenusPrivate.MarkMenu[self.menu,
self, mousePos]};
$RD, $BD, $YD
=> MenusPrivate.MarkMenu[self.menu,
self, mousePos];
$Control => control ← TRUE;
$Shift => shift ← TRUE;
ENDCASE => NULL;
caption =>
SELECT z
FROM
$RU => MenusPrivate.HitMenu[windowMenu,
self, mousePos, red, shift, control];
$BU => MenusPrivate.HitMenu[windowMenu,
self, closePos, blue, FALSE, FALSE];
$YU => MenusPrivate.HitMenu[windowMenu,
self, growPos, yellow, FALSE, FALSE];
$RM, $RD => MenusPrivate.MarkMenu[windowMenu,
self, mousePos];
$BM, $BD => MenusPrivate.MarkMenu[windowMenu,
self, closePos];
$YM, $YD => MenusPrivate.MarkMenu[windowMenu,
self, growPos];
$Control => control ← TRUE;
$Shift => shift ← TRUE;
ENDCASE => NULL;
ENDCASE;
};
z: TIPUser.TIPScreenCoords => {
client: BOOL ← FALSE;
mousePos ← z;
IF mousePos.mouseX = 0 --AND trackingState = scroll-- THEN mousePos.mouseX ← 1;
IF trackingState#none THEN [self, client] ← ViewerOps.MouseInViewer[mousePos];
zone ← IF client OR self=NIL THEN none ELSE CursorZone[self, mousePos];
newZone ← trackingState#zone
OR (zone=caption
AND self#feedbackViewer)
OR (zone=scroll AND self#feedbackViewer);
};
z: REF CHAR => TRUSTED {Interminal.terminal.BlinkBWDisplay[]};
ENDCASE => NULL;
ENDLOOP;
};
AlterColumn:
PROC [v: Viewer, mx:
INTEGER] = {
column: ViewerClasses.Column;
right: BOOL ~ mx >= v.ww/2;
column ←
SELECT v.column
FROM
left => IF right THEN right ELSE IF colorDisplayOn THEN color ELSE right,
right => IF ~right THEN left ELSE IF colorDisplayOn THEN color ELSE left,
color => IF right THEN right ELSE left,
ENDCASE => ERROR;
ViewerOps.ChangeColumn[v, column];
};
SetC:
PROC [cursor: CursorType] =
INLINE
{IF waitCount=0 AND GetCursor[]#cursor THEN SetCursor[cursor]};
HitScroll:
PROC [v: Viewer, y:
LONG
INTEGER, op: ScrollOp, shift, control:
BOOL] = {
RemoveScrollFeedback[];
IF v.parent=NIL OR v.class.coordSys#top THEN y ← v.ch-y; -- client coords
IF v.class.scroll#
NIL
THEN [] ← v.class.scroll[v, op,
SELECT op
FROM
up, down => y,
ENDCASE => (100*y)/v.ch, -- percent
shift, control];
SetC[scrollUpDown]; -- put the cursor back
PostScrollFeedback[v];
};
feedbackViewer: Viewer ← NIL;
visible: Imager.Color ~ ImagerOps.ColorFromStipple[122645B];
inVisible: Imager.Color ~ ImagerOps.ColorFromStipple[100040B];
PostScrollFeedback:
PROC [v: Viewer] = {
top, bottom: INTEGER;
action:
PROC[context: Imager.Context] ~ {
wbs: INTEGER ~ IF v.border THEN windowBorderSize ELSE 0;
baseX, baseY: INTEGER ~ wbs;
relY1, relY2: INT; -- so won't overflow
relY1 ← baseY;
relY2 ← (LONG[100-bottom]*v.ch)/100+baseY;
Imager.SetColor[context, inVisible];
Imager.MaskRectangle[context, baseX, relY1, scrollBarW, relY2-relY1];
relY1 ← relY2;
relY2 ← relY2 + (LONG[bottom-top]*v.ch)/100;
Imager.SetColor[context, visible];
Imager.MaskRectangle[context, baseX, relY1, scrollBarW, relY2-relY1];
Imager.SetColor[context, inVisible];
Imager.MaskRectangle[context, baseX, relY2, scrollBarW, baseY+v.ch-relY2];
};
IF feedbackViewer#NIL OR v.class.scroll=NIL THEN RETURN;
IF ~v.init THEN RETURN; -- avoid a race condition bug
[top, bottom] ← v.class.scroll[v, query, 0];
IF top>100 OR bottom>100 THEN RETURN;
Carets.SuspendCarets[];
ViewerExtras.PaintWindow[v, action];
Carets.ResumeCarets[];
feedbackViewer ← v;
};
RemoveScrollFeedback:
PROC = {
v: Viewer ~ feedbackViewer;
action:
PROC[context: Imager.Context] ~ {
wbs: INTEGER ~ IF v.border THEN windowBorderSize ELSE 0;
Imager.SetColor[context, Imager.white];
Imager.MaskRectangleI[context, wbs, wbs, scrollBarW, v.ch];
};
IF v=NIL THEN RETURN;
Carets.SuspendCarets[];
ViewerExtras.PaintWindow[v, action];
Carets.ResumeCarets[];
feedbackViewer ← NIL;
};
DrawCaptionMenu:
PUBLIC
ENTRY
PROC [v: Viewer, guard:
BOOL] =
{ENABLE UNWIND => NULL; InternalDrawCaptionMenu[v, guard]};
InternalDrawCaptionMenu:
INTERNAL
PROC [v: Viewer, guard:
BOOL] = {
OPEN v;
action:
PROC[context: Imager.Context] ~ {
wbs: INTEGER ~ windowBorderSize;
Imager.ClipRectangleI[context, wbs, v.wh, v.ww-2*wbs, -captionHeight];
Imager.SetColor[context, Imager.white];
Imager.MaskRectangleI[context, 0, v.wh, v.ww, -captionHeight];
Imager.SetColor[context, Imager.black];
IF guard
THEN Menus.SetGuarded[destroyEntry,
guardDestroy OR (newVersion AND link=NIL AND ~saveInProgress)];
MenusPrivate.DrawMenu[windowMenu,
ImagerOps.GraphicsFromImager[context], wbs, v.wh-captionHeight];
};
IF feedbackViewer#v OR v.iconic OR ~v.visible THEN RETURN;
ViewerExtras.PaintWindow[v, action];
};
PostCaptionFeedback:
ENTRY
PROC [v: Viewer] = {
ENABLE UNWIND => NULL;
IF feedbackViewer#v
THEN {
-- remove old
IF feedbackViewer#
NIL
THEN
MenusPrivate.ClearMenu[windowMenu, feedbackViewer, FALSE];
feedbackViewer ← v;
};
InternalDrawCaptionMenu[v, TRUE];
};
RemoveCaptionFeedback:
ENTRY
PROC = {
ENABLE UNWIND => NULL;
IF feedbackViewer#
NIL
THEN {
MenusPrivate.ClearMenu[windowMenu, feedbackViewer, FALSE];
ViewerOps.PaintViewer[feedbackViewer, caption];
feedbackViewer ← NIL;
};
};
waitCount: PUBLIC INTEGER ← 0;
WaitCursor:
PUBLIC
ENTRY
PROC [cursor: Cursors.CursorType ← hourGlass] = {
ENABLE UNWIND => NULL;
IF InputFocus.inputEnabled THEN SetCursor[cursor];
waitCount ← waitCount + 1;
};
UnWaitCursor:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL;
waitCount ← MAX[0, waitCount - 1];
IF waitCount=0 THEN RestoreCursor[];
};
RestoreCursor:
PUBLIC
PROC
= TRUSTED
{IF InputFocus.inputEnabled THEN InterminalExtra.InsertAction[[contents: deltaMouse[[0,0]]]]};
StartColorViewers:
PUBLIC
PROC [screenPos: WindowManager.ScreenPos,
bitsPerPixel: CARDINAL] = {
IF colorDisplayOn THEN StopColorViewers[];
IF PrincOpsUtils.IsBound[ColorWorld.TurnOnColor]
THEN
colorDisplayOn ← ColorWorld.TurnOnColor[bitsPerPixel, (screenPos=left)]
ELSE colorDisplayOn ← FALSE;
IF ~colorDisplayOn
THEN {
MessageWindow.Append["Sorry, you don't have a color display.", TRUE];
MessageWindow.Blink[];
RETURN;
};
ViewerOps.InitialiseColorPainting[];
Menus.ReplaceMenuEntry[windowMenu, tNopEntry, tColorEntry];
growPos^ ← [growEntry.xPos+1, FALSE, 0];
closePos^ ← [closeEntry.xPos+1, FALSE, 0];
};
StopColorViewers:
PUBLIC
PROC = {
DoColorViewer: ViewerOps.EnumProc = {
IF v.column=color
THEN {
ViewerOps.CloseViewer[v];
ViewerOps.ChangeColumn[v, left];
};
};
IF ~colorDisplayOn THEN RETURN;
ViewerOps.EnumerateViewers[DoColorViewer];
ColorWorld.TurnOffColor[];
colorDisplayOn ← FALSE;
Menus.ReplaceMenuEntry[windowMenu, tColorEntry, tNopEntry];
growPos^ ← [growEntry.xPos+1, FALSE, 0];
closePos^ ← [closeEntry.xPos+1, FALSE, 0];
};
BuildWindowMenus:
PROC = {
windowMenu ← Menus.CreateMenu[];
Menus.AppendMenuEntry[windowMenu, destroyEntry ← Menus.CreateEntry[name: "Destroy",
proc: ViewerMenus.Destroy, fork: FALSE, documentation: "Edits will be discarded..."]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Adjust",
proc: ViewerMenus.Adjust, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "Top",
proc: Top, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "<--",
proc: ViewerMenus.Left, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, Menus.CreateEntry[name: "-->",
proc: ViewerMenus.Right, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, tNopEntry ← Menus.CreateEntry["", NIL]];
tColorEntry ← Menus.CreateEntry[name: "Color", proc: ViewerMenus.Color, fork: FALSE];
Menus.AppendMenuEntry[windowMenu, growEntry ← Menus.CreateEntry[name: "Grow",
proc: ViewerMenus.Grow, fork: FALSE]];
Menus.AppendMenuEntry[windowMenu, closeEntry ← Menus.CreateEntry[name: "Close",
proc: ViewerMenus.Close, fork: FALSE]];
growPos ← NEW[TIPUser.TIPScreenCoordsRec ← [growEntry.xPos+1, FALSE, 0]];
closePos ← NEW[TIPUser.TIPScreenCoordsRec ← [closeEntry.xPos+1, FALSE, 0]];
};
this should be in ViewerMenus
Top: Menus.MenuProc = {ViewerOps.TopViewer[NARROW[parent]]};
colorDisplayOn: PUBLIC BOOL ← FALSE; -- color display status
windowMenu: PUBLIC Menus.Menu;
destroyEntry, closeEntry, growEntry, tColorEntry, tNopEntry: Menus.MenuEntry;
growPos, closePos: TIPUser.TIPScreenCoords;
BuildWindowMenus[];
END.