DIRECTORY Commander, Imager, Rope, Xl, XlInputExtension, XTk, XTkBitmapWidgets, XTkWidgets; X11InputExtensionTest: CEDAR MONITOR LOCKS i USING i: Instance IMPORTS Commander, Imager, Rope, Xl, XlInputExtension, XTk, XTkBitmapWidgets, XTkWidgets = BEGIN Widget: TYPE = XTkWidgets.Widget; Instance: TYPE = REF InstanceRec; InstanceRec: TYPE = MONITORED RECORD [ shell: Widget ¬ NIL, bitmap: Widget ¬ NIL, context: Imager.Context ¬ NIL, deviceInfos: LIST OF XlInputExtension.DeviceInfo ¬ NIL ]; PenState: TYPE = RECORD [ i: Instance, beginValid: BOOL ¬ FALSE, beginPos: Xl.Point ¬ [0, 0] ]; debugLastInstance: Instance; CreateInstance: Commander.CommandProc = { i: Instance ¬ debugLastInstance ¬ NEW[InstanceRec]; shell: Widget ¬ i.shell ¬ XTkWidgets.CreateShell[ className: $X11InputExtensionTest, windowHeader: "X11InputExtensionTest", standardMigration: TRUE ]; bitmap: Widget ¬ i.bitmap ¬ XTkBitmapWidgets.CreateBitmapWidget[ widgetSpec: [geometry: [size: [150, 400], borderWidth: 1]], notify: BitmapChanged, data: i ]; XTk.RegisterNotifier[bitmap, XTk.postWindowCreationKey, PostWindowCreation, i]; XTkWidgets.SetShellChild[shell, bitmap]; XTkWidgets.RealizeShell[shell]; }; penDeviceType: Rope.ROPE ¬ "TABLET"; PostWindowCreation: XTk.WidgetNotifyProc = { i: Instance ¬ NARROW[registerData]; BEGIN --Set up base event p: REF PenState ¬ NEW[PenState ¬ [i: i]]; XTk.AddTemporaryMatch[widget, [proc: EventReceived, handles: Xl.CreateEventFilter[motionNotify, buttonRelease, buttonPress], tq: NIL, data: p], [pointerMotion: TRUE, buttonRelease: TRUE, buttonPress: TRUE] ]; END; BEGIN --Set up extension events... i.deviceInfos ¬ XlInputExtension.ListInputDevices[widget.connection]; FOR list: LIST OF XlInputExtension.DeviceInfo ¬ i.deviceInfos, list.rest WHILE list#NIL DO type: Rope.ROPE ¬ Xl.GetAtomName[widget.connection, list.first.type]; IF Rope.Equal[type, penDeviceType] THEN { d: REF XlInputExtension.OpenDeviceRec ¬ XlInputExtension.OpenDevice[widget.connection, list.first.id]; IF d#NIL THEN { interest: LIST OF XlInputExtension.EventClass ¬ LIST[ XlInputExtension.MakeEventClass[d, deviceButtonRelease], XlInputExtension.MakeEventClass[d, deviceButtonPress], XlInputExtension.MakeEventClass[d, deviceMotionNotify] ]; p: REF PenState ¬ NEW[PenState ¬ [i: i]]; XTk.AddTemporaryMatch[widget, [proc: EventReceived, handles: Xl.FullCreateEventFilter[extensions: LIST[XlInputExtension.deviceButtonPressKey, XlInputExtension.deviceButtonReleaseKey, XlInputExtension.deviceMotionNotifyKey]], tq: NIL, data: p] ]; XlInputExtension.SelectExtensionEvents[c: widget.connection, window: widget.window, interest: interest]; }; }; ENDLOOP; END; }; Move: ENTRY PROC [i: Instance, p: REF PenState, down: BOOL, pos: Xl.Point] = { SELECT TRUE FROM down AND ~p.beginValid => { p.beginValid ¬ TRUE }; down AND p.beginValid => { Line[p, p.beginPos, pos]; }; ~down AND p.beginValid => { Line[p, p.beginPos, pos]; p.beginValid ¬ FALSE; }; ~down AND ~p.beginValid => { }; ENDCASE => {}; p.beginPos ¬ pos }; Line: PROC [p: REF PenState, pos1, pos2: Xl.Point] = { h: INT ¬ p.i.bitmap.actual.size.height; context: Imager.Context ¬ p.i.context; IF context#NIL THEN Imager.MaskVector[context, [pos1.x, h-pos1.y], [pos2.x, h-pos2.y]]; }; BitmapChanged: XTkBitmapWidgets.BitmapEventProc = { NewBitmap: ENTRY PROC [i: Instance, widget: XTk.Widget] = { context: Imager.Context; XTkBitmapWidgets.CreateAndSetBitmap[widget: widget, size: [widget.actual.size.height, widget.actual.size.width], bpp: 1]; context ¬ XTkBitmapWidgets.CreateContext[widget]; Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context: context, x: -1000, y: -1000, w: 4000, h: 4000]; Imager.SetStrokeWidth[context,1]; Imager.SetStrokeEnd[context, round]; Imager.SetStrokeJoint[context, round]; Imager.SetColor[context, Imager.black]; i.context ¬ context; }; SELECT reason FROM createWindow, resize, map => { NewBitmap[NARROW[data], widget]; }; ENDCASE => {} }; EventReceived: Xl.EventProcType = { p: REF PenState ~ NARROW[clientData]; SELECT event.type FROM Xl.EventCode.motionNotify => { e: Xl.MotionNotifyEvent ~ NARROW[event]; Move[p.i, p, e.state.button1 OR e.state.button2 OR e.state.button3, e.pos]; }; Xl.EventCode.buttonRelease => { e: Xl.ButtonReleaseEvent ~ NARROW[event]; Move[p.i, p, FALSE, e.pos]; }; Xl.EventCode.buttonPress => { e: Xl.ButtonPressEvent ~ NARROW[event]; Move[p.i, p, TRUE, e.pos]; }; Xl.EventCode.extension => { e: Xl.ExtensionEvent ~ NARROW[event]; WITH e.decoded SELECT FROM x: XlInputExtension.DeviceBaseEvent => { pos: Xl.Point ¬ x.eventPos; IF x.valuators=NIL OR x.valuators.leng<2 THEN RETURN; pos.x ¬ x.valuators[0]; pos.y ¬ x.valuators[1]; SELECT x.eventOffset FROM deviceButtonPress => { Move[p.i, p, TRUE, pos]; }; deviceButtonRelease => { Move[p.i, p, FALSE, pos]; }; deviceMotionNotify => { Move[p.i, p, x.state.button1 OR x.state.button2 OR x.state.button3, pos]; }; ENDCASE => {} }; ENDCASE => {} }; ENDCASE => {}; }; Commander.Register["X11InputExtensionTest", CreateInstance, "Create test widget to debug X input extension with multiple pens"]; END. °X11InputExtensionTest.mesa Copyright Σ 1992 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, January 9, 1992 Christian Jacobi, March 27, 1992 10:40 am PST This is a test. This is a test. This is a test only. Tests multiple pens. --register events explicitely only now because we should figure out availability of extension events first. Handle core event the same way for documentation reason. Κ •NewlineDelimiter –(cedarcode) style˜codešœ™Kšœ Οeœ1™